POS API · 面向收银系统开发者

面向收银系统的开放 API

商家自己的收银系统识别 Unemi 顾客,把顾客的积分和奖励用到账单上,结账后把金额发给 Unemi——盖章、积分或月卡的处理方式与 Unemi Staff 收银台完全相同。面向收银系统开发者和使用自有收银系统的商家。

如何接入

  1. Pro 套餐

    开放 API 在 Pro 套餐中可用。其他套餐无法创建密钥,之前创建的密钥发出的请求会被拒绝。

  2. 在后台创建密钥

    商家所有者在后台打开「API и интеграции」(API 与对接)并创建密钥:填写名称(例如按收银台或门店命名)并设置权限。

  3. 权限:单个门店或整个商家

    门店密钥只在该门店有效。整个商家的密钥在识别顾客和撤销小票时需要指明门店——门店 id 也在同一页面。

  4. 密钥只显示一次

    把它复制到服务器上的收银系统设置中。Unemi 只保存哈希值:丢失的密钥无法找回——请创建新密钥并吊销旧密钥。

收银系统如何与 Unemi 配合

每张小票四步。顾客对每张小票单独授权:顾客手机上的二维码或数字码只开启一张小票的会话。

  1. 顾客出示二维码

    或报出二维码下方的六位数字。收银系统识别顾客,并获取其余额、奖励、优惠券和正在进行的活动。

    posIdentify
  2. 收银员使用优惠

    抵扣积分、使用奖励或优惠券,都在您自己的收银系统里像普通折扣一样完成。

  3. 结账后金额发给 Unemi

    收银系统发送小票号、会员计划、金额、抵扣的积分和已核销的奖励,也可以附上收银员和商品明细。顾客会收到推送,和在 Unemi Staff 收银台结账后一样。

    posApply
  4. 48 小时内可撤销或退款

    小票被撤销或退款后,收银系统按小票号在 Unemi 中同样撤销:一切恢复原样。部分退款连同退款金额一起发送——Unemi 会把它展示给商家所有者。

    posUndo

限制

  • 每个密钥每分钟 120 次请求
  • 一次识别会话只处理一张小票,有效期 2 小时;收银系统密钥的会话为 12 小时
  • 小票可在 48 小时内撤销或退款
  • 每张小票一个会员计划,最多 5 个奖励和优惠券
  • 15 分钟内识别失败:5 次后暂停 1 分钟,10 次后暂停 5 分钟,15 次后暂停 30 分钟
  • 每个商家最多 10 个有效密钥

接口参考

参考文档为英文。方法、字段和错误码的名称在任何语言中都相同。 俄文版参考

General rules

ItemValue
Address https://api.unemi.kz/<method>
Methods posIdentify, posApply, posUndo — POST only
Headers Authorization: Bearer unemi_<id>_<secret>, Content-Type: application/json
Body A JSON object; the response is JSON
Time ISO 8601 in UTC: "2026-10-07T09:30:00.000Z"
Money and bonuses Whole tenge; 1 bonus = 1 ₸
Request id Response header X-Unemi-Request-Id (and requestId in errors) — support will ask for it
Location A location key works only at its location; a key for the whole business passes venueId to posIdentify and posUndo, and posApply takes the location from the session
POS key A key for one location with a POS system and the location's rules: 12-hour sessions and a default program — see “POS key”
Limit 120 requests per minute per key
CORS None: the key lives on the POS server, not in a browser
Texts Program, reward, coupon and promotion names come as the business wrote them in its dashboard (the examples use English); level names and error message are in Russian

Session and customer consent

  • The customer consents to every receipt: the QR or six digits from the customer's screen open a session that posts one receipt and lasts 2 hours, 12 hours with a POS key. The next receipt needs a new QR.
  • The QR and the code are single-use: posIdentify redeems them, just like a staff scan. Repeating the same request with the same key (the response got lost) returns the same session — until a receipt is posted on it or it expires; the Unemi till or another key gets code_used.
  • With a POS key, the same code or phone number returns the same open session for 12 hours, even after the code itself has expired (it lives about a minute): the POS asks for the customer's card several times per order. A fresh code of another customer with the same digits wins — it is redeemed and opens a new session.
  • A cancelled receipt (posUndo) doesn't use up the consent: the same session, while it lives, can post it again.
  • A phone number finds only this business's customers (they already have a card, a bonus account or a subscription), and the session is accrual-only: accrualOnly: true, stamps and bonuses without spending.
  • A phone number proves nothing: spending bonuses, buying or using a subscription and redeeming a reward need the QR or code from the customer's phone — otherwise consent_required. The API does not create new customers by phone number.

Retries and idempotency

  • The response got lost — repeat the same request: the operation is not posted twice.
  • posIdentify with the same QR or code from the same key returns the same session until a receipt is posted on it or it expires.
  • posApply with the same receiptId and the same data returns the saved response with replayed: true — no second operation and no second push to the customer. The same receiptId with different data or another session gets receipt_conflict. The cashier and items (cashier, items) are for reference only: they aren't compared.
  • receiptId is unique within a location: if a location has several tills, their receipt numbers must not overlap — for example, prefix them with the till. After a cancellation (posUndo) the same receiptId can be posted again.
  • Repeating posUndo returns the same response with replayed: true.
  • rate_limited and too_many_attempts — wait details.seconds seconds; internal — try again later.

Error response

An error is an HTTP status and a body:

{
  "error": {
    "code": "cooldown",
    "message": "Слишком рано: следующий штамп можно через 12 мин",
    "details": { "minutes": 12 },
    "requestId": "Qk2v9XyZaB7cD1eF3gH5"
  }
}

The POS branches on error.code — the codes are stable (tables below). message is in Russian, as in the Unemi till; details holds the numbers for the code (minutes, limit, balance).

posIdentify — identify the customer

POST https://api.unemi.kz/posIdentify

The QR from the Unemi app, the six digits under it or a phone number → a session for one receipt, the customer, balances, rewards and coupons, running promotions.

Request

FieldDescription
qr The QR code string from the customer's screen: unemi:1:st:… — or the six digits of a digital QR (see “POS key”)
code The six digits under the QR — when there is no scanner
phone The customer's Kazakhstan phone number — accruals only (see “Session and customer consent”)
venueId Location id — for a key for the whole business; optional for a location key

Exactly one of qr, code, phone.

By QR
{ "qr": "unemi:1:st:Xk2pQ9LmNb7Tz1Rw4Ycd", "venueId": "v8Kp2LmQx1" }
By six digits
{ "code": "482913" }
By phone number
{ "phone": "+7 701 123 45 67" }

Response

Response
{
  "session": "Gm3kQ8rT2vXw9LpZa1Yc",
  "expiresAt": "2026-10-07T11:30:00.000Z",
  "identifiedBy": "qr",
  "accrualOnly": false,
  "customer": {
    "id": "cus_4f1c9a0b2d7e8f3a6b5c1d2e",
    "name": "Aigerim"
  },
  "level": {
    "level": 3,
    "name": "Friend",
    "metric": "visits",
    "value": 18
  },
  "selectedProgramId": "p8Fh2kLm",
  "programs": [
    {
      "id": "p8Fh2kLm",
      "type": "stamps",
      "name": "Stamp card",
      "locked": false,
      "minLevel": 1,
      "stamps": {
        "count": 3,
        "required": 6,
        "rewardTitle": "Gift",
        "rewardPercent": 100,
        "steps": [
          { "stamp": 4, "kind": "discount", "percent": 20, "title": "" }
        ]
      }
    },
    {
      "id": "q2Nw7xRt",
      "type": "bonus",
      "name": "Bonus card",
      "locked": false,
      "minLevel": 1,
      "bonus": {
        "balance": 1250,
        "percent": 5,
        "percentBp": 500,
        "levelPercent": 7,
        "levelBp": 700,
        "welcomeBonusPending": false
      }
    },
    {
      "id": "s5Kd1vBn",
      "type": "subscription",
      "name": "Subscription",
      "locked": false,
      "minLevel": 1,
      "subscription": {
        "item": "Item of the day",
        "price": 15000,
        "durationDays": 30,
        "lifetime": false,
        "perDay": 1,
        "pass": {
          "expiresAt": "2026-10-20T07:00:00.000Z",
          "expired": false,
          "leftToday": 1,
          "lifetime": false
        }
      }
    }
  ],
  "rewards": [
    {
      "id": "rW7yT2pQ",
      "kind": "reward",
      "title": "Gift",
      "programId": "p8Fh2kLm",
      "percent": 100,
      "item": null,
      "expiresAt": "2026-10-30T09:00:00.000Z"
    },
    {
      "id": "cP3mN8sD",
      "kind": "coupon",
      "title": "−20% off the order",
      "programId": null,
      "percent": 20,
      "item": null,
      "expiresAt": "2026-10-08T18:00:00.000Z"
    }
  ],
  "promos": [
    {
      "title": "Scheduled offers",
      "description": "Bonuses ×2",
      "until": "2026-10-07T11:00:00.000Z",
      "effect": { "kind": "bonus_multiplier", "value": 2 }
    }
  ]
}
FieldDescription
session, expiresAt The session for posApply and when it ends — in 2 hours, 12 hours with a POS key.
identifiedBy, accrualOnly How the customer was identified: qr (a digital QR too), code or phone. accrualOnly: true — by phone number: accruals only.
customer id — a permanent customer id for this business (the same person has a different one at another business); name — the name as Unemi Staff shows it. The POS gets no phone number, email or internal Unemi id.
level The customer's level if the business has levels turned on; otherwise null. value — the all-time total: days with visits (metric: "visits") or purchases in tenge ("spend"); an earned level never goes down.
stamps.steps Rewards on intermediate stamps of the card, by stamp number: stamp — the stamp number (1 to required; on the last stamp the guest gets both the step reward and the main reward rewardTitle), kind — discount (percent% off) or item (a free item, percent is 100), title — the title; empty — name it by the discount. No rewards — an empty list.
locked, minLevel locked: true — the program starts at a level and the customer's level is below minLevel: an operation on it returns level_required (except a hand-out on an already paid subscription).
bonus.balance How many bonuses can be spent. welcomeBonusPending: true — the first visit: welcome bonuses are credited by this same operation and can already be spent.
bonus.percent, bonus.levelPercent percent — the program's percentage. levelPercent — this customer's percentage for their level, if the business set percentages by level and it is higher than percent: posApply credits at it; otherwise null.
bonus.percentBp, bonus.levelBp The same percentages exactly, in basis points: 250 — 2.5%, 10,000 — 100%. A percentage can be fractional (up to two decimal places, from 0 to 100); percent and levelPercent are integers rounded half up (2.5% → 3) for POS systems connected earlier. Preview the credit by bp: floor((amount − spend) × bp / 10000).
subscription.pass The customer's subscription; null — none bought.
subscription.lifetime A lifetime program: its durationDays is 36,500. pass.lifetime — the customer's lifetime subscription: it ends a hundred years from now and never needs renewing (pass_lifetime_active).
selectedProgramId The program the customer picked in the app before showing the QR; null — staff choose.
rewards Unredeemed stamp card rewards and campaign coupons still valid: percent — the discount (100 — free), item — the coupon's item.
promos Scheduled offers at the location right now. The server applies the effect (bonus_multiplier, bonus_extra_percent, double_stamps) itself on posApply; with no effect (effect: null) it is a reminder for staff to apply the discount.
defaultProgram POS key only: the program a receipt without programId and action goes to — { "programId": "q2Nw7xRt", "action": "bonus" }: the stamp card or bonus card the customer picked in the app, otherwise the key's default program; null — neither. A regular key has no such field.

posApply — post a closed receipt

POST https://api.unemi.kz/posApply

The receipt is closed and paid → the program operation and redeemed rewards. The operation, reward redemptions, the visit for levels, “Bring a friend” gifts and gifts for a new level go in one transaction: all or nothing.

Request

FieldDescription
session From the posIdentify response.
receiptId The receipt id in your POS: 1–64 printable ASCII characters without spaces, or a non-negative integer. The idempotency key — within a location.
programId, action A program operation — as a pair (actions below). Without the pair — rewards redemption only, and with a POS key a receipt with amount goes to the default program.
amount The receipt amount, ₸. Required for bonus (1 … 10 000 000); optional for the others (a whole number 0 … 10 000 000) and stored for disputes.
spend Bonuses spent on this receipt; bonus only (with a POS key and no program too — then the default program must be a bonus card), no more than amount and the balance.
rewardIds Up to 5 rewards and coupons from posIdentify applied to the receipt.
cashier Optional: who posted the receipt — { "id": "1234", "name": "B. Vdovin" }; id — the employee code in your POS (up to 64 characters without spaces), the name — up to 100 characters. Stored with the receipt for disputes and fraud checks.
items Optional: up to 100 lines — { "code": "7644", "name": "Item of the day", "qty": 2, "amount": 2400 }; the POS item code — up to 40 characters, the quantity above zero (fractional for goods sold by weight), the amount after discounts in whole tenge. Needed for a POS key's “stamp only for these items” rule.

One receipt — one program and up to 5 rewards and coupons.

A bonus card receipt: bonuses spent and a coupon
{
  "session": "Gm3kQ8rT2vXw9LpZa1Yc",
  "receiptId": "A-1024",
  "programId": "q2Nw7xRt",
  "action": "bonus",
  "amount": 4500,
  "spend": 500,
  "rewardIds": ["cP3mN8sD"]
}

Program actions

actionProgramWhat it does
stamp Stamp card A stamp on the customer's card
bonus Bonus card Bonuses on the part paid in money, and spending spend
pass_purchase Subscription Buy or renew a subscription
pass_issue Subscription Hand out on a subscription

Bonuses are credited on the part paid in money (amount − spend) at the program's percentage, rounded down to a whole bonus — floor((amount − spend) × bp / 10000) — or — for a customer whose level gives more — at their level's percentage before this receipt (bonus.levelBp from posIdentify); with the scheduled offers effect if one is running. The level and promotion additions add up rather than multiply, and together never exceed the amount paid.

A POS key without a program. A receipt with amount but without the programId and action pair goes to the default program: the stamp card or bonus card the customer picked in the app before showing the QR, otherwise the program and action from the key's rules.

Rule thresholds: paid in money (amount − spend) below the threshold — no accrual; a stamp of a default program with item codes needs at least one line with such a code (no items — no stamp). The threshold never stops spending bonuses, but without a bonus program spending is impossible — action_mismatch.

Nothing accrued — the response is still a success: operation: null and the reason in skipped; the receipt is recorded and the session closed. A regular key has no skipped field, and a receipt without the pair and without rewards gets invalid_request.

Response

Response
{
  "receiptId": "A-1024",
  "operationId": "bonus:Zx81LmQa0pTt7uVv3wYb",
  "operation": {
    "type": "bonus",
    "programId": "q2Nw7xRt",
    "programName": "Bonus card",
    "amount": 4500,
    "spent": 500,
    "earned": 480,
    "welcome": 0,
    "balance": 1230,
    "promo": {
      "title": "Scheduled offers",
      "kind": "bonus_multiplier",
      "value": 2,
      "extra": 200
    },
    "levelPercent": 7,
    "levelBp": 700,
    "levelExtra": 80
  },
  "redeemed": [
    {
      "id": "cP3mN8sD",
      "kind": "coupon",
      "title": "−20% off the order"
    }
  ],
  "referral": null,
  "levelUp": null,
  "replayed": false
}
operation of a stamp
{
  "type": "stamp",
  "programId": "p8Fh2kLm",
  "programName": "Stamp card",
  "stamps": 4,
  "required": 6,
  "added": 1,
  "rewardIssued": false,
  "rewardTitle": null,
  "stepRewards": [{ "stamp": 4, "title": "20% off", "percent": 20 }],
  "promo": null
}
operation of a subscription purchase
{
  "type": "pass_purchase",
  "programId": "s5Kd1vBn",
  "programName": "Subscription",
  "item": "Item of the day",
  "price": 15000,
  "expiresAt": "2026-11-19T07:00:00.000Z",
  "renewed": true,
  "lifetime": false
}
operation of a subscription hand-out
{
  "type": "pass_issue",
  "programId": "s5Kd1vBn",
  "programName": "Subscription",
  "item": "Item of the day",
  "leftToday": 0,
  "perDay": 1,
  "expiresAt": "2026-10-20T07:00:00.000Z",
  "lifetime": false
}
levelUp with gifts: a big purchase moved the customer straight over a level (levels by purchase amount)
{
  "from": 1,
  "to": 3,
  "name": "Friend",
  "gifts": [
    {
      "level": 2,
      "kind": "coupon",
      "rewardId": "cL4vR9kTq2",
      "title": "−15% off the order",
      "percent": 15,
      "item": null,
      "expiresAt": "2026-11-05T18:59:59.000Z"
    },
    {
      "level": 3,
      "kind": "bonus",
      "programId": "q2Nw7xRt",
      "programName": "Bonus card",
      "amount": 500
    }
  ]
}
FieldDescription
operationId, operation The posted operation; null — the receipt only redeemed rewards or, with a POS key, there was nothing to accrue (see skipped).
promo Scheduled offers that applied to the operation: extra — how many bonuses or stamps the promotion added.
levelPercent, levelBp, levelExtra For a bonus operation: the customer's level percentage, if bonuses were credited at it (levelBp — exactly, in basis points; levelPercent — as an integer), and how many bonuses it added on top of the program's percentage (earned already includes them); otherwise null, null and 0. In the example: a Friend gets 7% instead of 5% and “bonuses ×2” on ₸4,000: 280 for the level + 200 from the promotion = 480, not 560.
rewardIssued true — the stamp completed the card and the customer has a new reward (rewardTitle); it can be redeemed on the next receipt.
stepRewards Rewards for intermediate stamps issued by this receipt: stamp number stamp, title title (without a title — “20% off” or “Gift”), discount percent (100 — a free item). Usually empty or one. These are regular rewards: they come in rewards on identification and can be redeemed on the next receipt.
redeemed Rewards and coupons redeemed from rewardIds.
referral The first visit of an invited friend: { "gift": { "kind": "bonus", "amount": 300, "programName": "Bonus card" } }; otherwise null.
levelUp The customer moved up a level: from, to, name and gifts — gifts for the new level given by this receipt (empty — no gifts; over a level — one per step); otherwise null. A coupon: rewardId — the reward id (it also comes in rewards on identification and can be redeemed on the next receipt), title, a discount percent or an item item, valid until expiresAt. Bonuses: programId, programName, amount — already on the customer's balance (if on this receipt's card — in operation.balance too).
skipped POS key only, for a receipt without a program: why nothing was accrued — no_program (the key has no default program and the customer didn't pick one), below_minimum (paid less than the threshold), no_qualifying_items (no items from the rule on the receipt); null — accrued.
replayed true — a repeated receipt: the saved response, no second operation.

posUndo — cancel a receipt

POST https://api.unemi.kz/posUndo

A cancellation puts everything back as it was before the receipt: the stamp, bonuses, subscription, redeemed rewards and coupons, the level visit, “Bring a friend” gifts and gifts for a new level (a gift coupon the customer has already redeemed stays with them; spent gift bonuses are taken back as far as the balance allows). Allowed within 48 hours after the receipt: voids and refunds happen at the end of a shift and the next day too.

Request

FieldDescription
receiptId The id of a receipt posted with posApply at this location.
venueId Only for a key for the whole business.
amount Optional: the refund amount, ₸ (a whole number 0 … 10 000 000). Less than the receipt amount — a partial refund; without it or with the full amount — the whole receipt is cancelled.
Cancel a receipt
{ "receiptId": "A-1024", "venueId": "v8Kp2LmQx1" }

Repeating a cancellation returns the same response with replayed: true. The receipt's session opens again while it lives: the same receipt can be posted again on the same session.

A receipt can't be cancelled if the customer's card has changed since (undo_not_last), the credited bonuses are spent (undo_bonus_spent), the reward for this stamp has been handed out (undo_reward_redeemed) or the bought subscription has been used (undo_pass_used).

A partial refund (amount below the receipt amount): the operation stays and the response is a success — partial: true, nothing cancelled.

A partial refund and the refusals undo_too_late, undo_not_last, undo_bonus_spent, undo_reward_redeemed, undo_pass_used, operation_not_found are recorded for the owner in the dashboard's refund log, and — if they turned on suspicious operation alerts — as a signal in the morning summary too. Don't block the refund in your POS because of the posUndo response: a refusal code means Unemi didn't reverse the accrual, and the owner decides. A successful cancellation removes the record from the log.

Response

Response
{
  "receiptId": "A-1024",
  "undone": ["bonus:Zx81LmQa0pTt7uVv3wYb", "redeem:cP3mN8sD"],
  "undoneAt": "2026-10-07T09:41:12.000Z",
  "replayed": false
}
Partial refund
{
  "receiptId": "A-1024",
  "undone": [],
  "undoneAt": null,
  "partial": true,
  "replayed": false
}
FieldDescription
undone What was cancelled: the operation id and redemptions (redeem:<reward id>); empty — a partial refund.
undoneAt When it was cancelled; null — a partial refund.
partial true — a partial refund: nothing cancelled, recorded for the owner. A full cancellation has no such field.
replayed true — a repeated cancellation: the saved response.

Error codes

Access and request

CodeHTTPWhendetails
unauthorized 401 No key, the key doesn't look like an Unemi key or doesn't match
key_revoked 401 The key was revoked in the dashboard
plan_feature 403 The business isn't on Pro (or the payment is more than 7 days overdue) plan, feature
method_not_allowed 405 Not POST
invalid_request 400 The body isn't a JSON object or a field has the wrong form field
rate_limited 429 More than 120 requests per minute per key, or 30 failed sign-ins from one address per minute seconds, limit
venue_required 400 A key for the whole business, but no venueId field
venue_forbidden 403 A location key, but the request is about another location
venue_not_found 404 The location doesn't exist, belongs to someone else or is turned off
internal 500 A failure on Unemi's side — try again later

Identification (posIdentify)

CodeHTTPWhendetails
unknown_qr 400 Neither an Unemi QR nor six digits
reward_qr 400 A reward QR was shown — the card QR is needed; rewards come in rewards
invalid_phone 400 Not a Kazakhstan phone number
code_not_found 404 No such code (a typo or someone else's QR)
code_used 409 The code has already been redeemed
code_expired 409 The code is outdated (it lives about a minute) — the customer refreshes the screen
customer_not_found 404 No customer of this business with that phone number
customer_unknown 400 The code has no customer
too_many_attempts 429 A pause after failed identifications seconds

Receipt (posApply)

CodeHTTPWhendetails
session_not_found 404 No such session, it belongs to someone else or to a location the key can't access
session_expired 409 The session is older than 2 hours (12 with a POS key)
session_used 409 Another receipt has already been posted on this session
receipt_conflict 409 This receipt has already been posted with different data operationId
program_not_found 404 No such program or it belongs to someone else
program_paused 409 The program is turned off
action_mismatch 409 The action doesn't fit the program type; with a POS key — bonuses spent on a receipt without a default bonus program type
level_required 409 The program starts at a level, the customer's level is lower minLevel, level
cooldown 409 This card got a stamp at this location recently minutes
daily_limit 409 The daily stamp limit limit
invalid_amount 400 The amount or bonuses spent aren't a whole number within the bounds max
bonus_insufficient 409 Spending more than the balance balance
pass_not_found 409 A hand-out without a subscription
pass_expired 409 The subscription has expired expiredAtMillis
pass_day_limit 409 Today's subscription hand-outs are used up limit
pass_lifetime_active 409 The customer already has a lifetime subscription — no need to buy it again
reward_not_found 404 No such reward or it belongs to another customer
reward_other_business 403 A reward of another business
reward_already_redeemed 409 The reward has already been redeemed
reward_expired 409 The reward has expired
coupon_exhausted 409 The first N customers have already used the coupon limit

Cancellation (posUndo)

CodeHTTPWhendetails
receipt_not_found 404 The receipt wasn't posted through the API at this location
invalid_amount 400 The refund amount isn't a whole number within the bounds max
undo_too_late 409 More than 48 hours have passed (minutes is the cancellation window, 2880) minutes
undo_already 409 The operation was already cancelled in the till or the dashboard
undo_not_last 409 The customer's card has changed since the receipt
undo_reward_redeemed 409 The reward for this stamp has already been handed out
undo_bonus_spent 409 The credited bonuses have already been spent balance
undo_pass_used 409 The subscription has already been used
operation_not_found 404 The receipt's operation no longer exists (the reward was deleted)

Security and data

  • The key is unemi_<key id, 20 characters>_<secret, 48 hex>, 192 random bits of secret. Unemi stores only the sha256 of the secret and its last four characters to recognise it in the list; a wrong, malformed or non-existent key gets the same unauthorized.
  • Other businesses are out of reach: a key is bound to its business, sessions and receipts are looked up only there, and a location key sees only its location. Someone else's session, program, reward or receipt answers “not found”.
  • Personal data: the POS gets the customer's name (as Unemi Staff shows it), balances, rewards and level. Responses carry no phone number, email or internal Unemi id; the customer id is a separate alias for each business.
  • Guessing codes and numbers: failed identifications (code_not_found, customer_not_found) add up per key over 15 minutes; after 5 — a 1-minute pause, after 10 — 5 minutes, after 15 — 30 minutes (too_many_attempts). The pause doesn't stop posting or cancelling receipts.
  • The request log in the dashboard has no customer data and is kept for 30 days.
  • There is no sandbox: integrations are tested on a test business on the Pro plan.

POS key

  • A POS key is an API key for one location marked with a POS system: r_keeper, iiko, Syrve or a chain's own POS. The owner creates it in the dashboard by choosing an r_keeper till key. There are no POS keys for the whole business: a POS stands at a particular location.
  • The key carries the location's rules — a default program and action (a stamp for a stamp card, bonuses for a bonus card), an amount threshold (0 … 10 000 000 ₸) and POS item codes (up to 100, each up to 40 characters without spaces) — and the language of texts on the POS screen, one of Unemi's six languages. The rules and the language change without a new key; another POS system needs a new key.
  • What differs in the methods: a session lasts 12 hours, and the same code or phone number within an order returns the same session; posIdentify returns defaultProgram; a receipt without a program goes to the default program, and if nothing was accrued, the reason is in skipped.
  • Digital QR: while the business has an active r_keeper POS key, the QR on the customer's card holds the same six digits as under it — the r_keeper scanner reads them as a card number. Pass them to posIdentify in qr (identifiedBy: "qr"). The general QR from the app menu (not tied to a card) stays as it is: the customer reads out the six digits under it.
What the owner sets in the dashboard: name, location, POS system, language and rules
{
  "name": "r_keeper · Abay",
  "venueId": "v8Kp2LmQx1",
  "pos": {
    "system": "r_keeper",
    "language": "ru",
    "rules": {
      "programId": "q2Nw7xRt",
      "action": "bonus",
      "minAmount": 0,
      "productCodes": []
    }
  }
}

r_keeper bridge for dealers Coming soon

The HttpFarCard module (ExtDllHTTP.dll) of the r_keeper POS server sends POST requests with XML itself — a card request (getcardinfoex) and the transactions of a closed receipt (transactionsex) — and the posRkeeper bridge runs them through the same core as the methods above: it identifies the customer, posts the receipt and cancels it on a rollback or refund.

ItemValue
Address https://api.unemi.kz/posRkeeper — the Address line in ExtDllHttp.ini
Handlers GetCardInfoEx=getcardinfoex, TransactionsEx=transactionsex
Sign-in Basic authentication: login unemi_<key id>, password — the key's secret; https only, otherwise https_required
Key An r_keeper POS key for one location: the owner gets the address, login and password in the dashboard when creating the key and passes them to the dealer. A regular API key or another POS system's key gets pos_key_required
Binding The first request remembers the r_keeper object (its codes in the POS requests); a request from another object gets venue_mismatch
Responses HttpFarCard protocol XML. Refused transactions — Result="1" with the reason in TRRESPONSE; a card not accepted — Locked="1" with the reason in WhyLock

Transactions are refused only when a bonus payment can't be accepted (for example, not enough bonuses, the customer was found by phone number or there is no bonus program): a receipt without a bonus payment always closes, and if the accrual didn't go through, the owner sees the reason in the request log.

Payment rollbacks, refunds and refund rollbacks never stop the POS: a refund cancels the receipt within 48 hours, and what Unemi didn't reverse, the owner sees in the refund log. Gifts and coupons aren't redeemed through r_keeper — they are handed out in the Unemi till. Texts on the POS screen are in the key's language.