POS API · for POS developers
An open API for POS systems
The business's own POS recognises an Unemi customer, applies their bonuses and rewards to the bill and, once it's paid, sends the amount to Unemi — the stamp, bonuses or subscription go through exactly as in the Unemi Staff till. For POS developers and businesses with their own POS.
How to connect
-
The Pro plan
The open API works on the Pro plan. On other plans a key can't be created, and requests with a key made earlier are refused.
-
A key in the dashboard
The owner opens «API и интеграции» (API and integrations) in the dashboard and creates a key: a name — say, after the till or location — and its access.
-
Access: one location or the whole business
A location key works only at that location. A key for the whole business names the location when identifying a customer and cancelling a receipt — location ids are in the same section.
-
The key is shown once
Copy it into the POS settings on your server. Unemi keeps only a hash: a lost key can't be recovered — create a new one and revoke the old one.
How a POS works with Unemi
Four steps per receipt. The customer consents to every receipt: the QR or code from their phone opens a session for one receipt.
-
The customer shows a QR
Or reads out the six digits under it. The POS recognises the customer and gets their balances, rewards, coupons and running promotions.
posIdentify -
Staff apply the discount
Spending bonuses, a reward or a coupon is applied in your own POS, like any other discount.
-
Receipt closed — the amount goes to Unemi
The POS sends the receipt number, program, amount, bonuses spent and redeemed rewards — and, optionally, the cashier and the items. The customer gets a push, just as after the Unemi Staff till.
posApply -
Cancel or refund within 48 hours
If the receipt is cancelled or refunded, the POS cancels it in Unemi too by its number: everything goes back to how it was. A partial refund goes with its amount — Unemi shows it to the owner.
posUndo
Limits
- 120 requests per minute per key
- An identification session posts one receipt and lasts 2 hours, 12 hours with a POS key
- A receipt can be cancelled or refunded within 48 hours
- One receipt — one program and up to 5 rewards and coupons
- Failed identifications within 15 minutes: after 5 — a 1-minute pause, after 10 — 5 minutes, after 15 — 30 minutes
- Up to 10 active keys per business
Method reference
The reference is in English. Method, field and error code names are the same in any language. Reference in Russian
General rules
| Item | Value |
|---|---|
| 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:
posIdentifyredeems 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 getscode_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.
-
posIdentifywith the same QR or code from the same key returns the same session until a receipt is posted on it or it expires. -
posApplywith the samereceiptIdand the same data returns the saved response withreplayed: true— no second operation and no second push to the customer. The samereceiptIdwith different data or another session getsreceipt_conflict. The cashier and items (cashier,items) are for reference only: they aren't compared. -
receiptIdis 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 samereceiptIdcan be posted again. - Repeating
posUndoreturns the same response withreplayed: true. -
rate_limitedandtoo_many_attempts— waitdetails.secondsseconds;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
| Field | Description |
|---|---|
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.
{ "qr": "unemi:1:st:Xk2pQ9LmNb7Tz1Rw4Ycd", "venueId": "v8Kp2LmQx1" } { "code": "482913" } { "phone": "+7 701 123 45 67" } 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 }
}
]
} | Field | Description |
|---|---|
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
| Field | Description |
|---|---|
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.
{
"session": "Gm3kQ8rT2vXw9LpZa1Yc",
"receiptId": "A-1024",
"programId": "q2Nw7xRt",
"action": "bonus",
"amount": 4500,
"spend": 500,
"rewardIds": ["cP3mN8sD"]
} Program actions
action | Program | What 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
{
"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
}
]
} | Field | Description |
|---|---|
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
| Field | Description |
|---|---|
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. |
{ "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
{
"receiptId": "A-1024",
"undone": ["bonus:Zx81LmQa0pTt7uVv3wYb", "redeem:cP3mN8sD"],
"undoneAt": "2026-10-07T09:41:12.000Z",
"replayed": false
} {
"receiptId": "A-1024",
"undone": [],
"undoneAt": null,
"partial": true,
"replayed": false
} | Field | Description |
|---|---|
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
| Code | HTTP | When | details |
|---|---|---|---|
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)
| Code | HTTP | When | details |
|---|---|---|---|
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)
| Code | HTTP | When | details |
|---|---|---|---|
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 |
consent_required | 403 | The customer was found by phone number, but the receipt spends bonuses or has a subscription or reward | |
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)
| Code | HTTP | When | details |
|---|---|---|---|
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 sameunauthorized. - 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;
posIdentifyreturnsdefaultProgram; a receipt without a program goes to the default program, and if nothing was accrued, the reason is inskipped. - 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
posIdentifyinqr(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.
{
"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.
| Item | Value |
|---|---|
| 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.
See also
-
POS integrations
Ready-made integrations with Poster, iiko and other POS systems are built on this API. Mark yours — that's how we know which one to build first.
-
The Pro plan
The open API comes with Pro. What else the plan includes and what already works — see the plan comparison.
-
Integration questions
There's no sandbox: integrations are tested on a test business on the Pro plan. Write to us — we'll help you connect.