POS API · kasa geliştiricileri için
Kasa sistemleri için açık API
İşletmenin kendi kasası Unemi müşterisini tanır, bonuslarını ve ödüllerini hesaba uygular, ödemeden sonra tutarı Unemi'ye gönderir — damga, bonus ya da abonelik, Unemi Staff kasasındakiyle aynı şekilde işlenir. Kasa sistemi geliştiricileri ve kendi kasası olan işletmeler için.
Nasıl bağlanır
-
Pro planı
Açık API, Pro planında çalışır. Diğer planlarda anahtar oluşturulamaz; daha önce oluşturulmuş bir anahtarla gelen istekler reddedilir.
-
Paneldeki anahtar
İşletme sahibi panelde «API и интеграции» (API ve entegrasyonlar) bölümünü açar ve bir anahtar oluşturur: adı — örneğin kasaya ya da şubeye göre — ve yetkileri.
-
Yetkiler: tek şube ya da tüm işletme
Şube anahtarı yalnızca o şubede çalışır. Tüm işletme için anahtar, müşteriyi tanırken ve fişi iptal ederken şubeyi belirtir — şube kimlikleri aynı bölümdedir.
-
Anahtar yalnızca bir kez gösterilir
Onu sunucudaki kasa ayarlarına kopyalayın. Unemi yalnızca özetini (hash) saklar: kaybolan anahtar geri getirilemez — yenisini oluşturun, eskisini iptal edin.
Kasa Unemi ile nasıl çalışır
Her fiş için dört adım. Müşteri her fişe ayrıca onay verir: telefonundaki QR ya da kod, tek fişlik bir oturum açar.
-
Müşteri QR gösterir
Ya da altındaki altı haneyi söyler. Kasa müşteriyi tanır; bakiyelerini, ödüllerini, kuponlarını ve süren kampanyaları alır.
posIdentify -
Kasiyer indirimi uygular
Bonus harcama, ödül ya da kupon, kendi kasanızda sıradan bir indirim gibi uygulanır.
-
Fiş kapandı — tutar Unemi'ye
Kasa fiş numarasını, programı, tutarı, harcanan bonusu ve kullanılan ödülleri, isterseniz kasiyeri ve fiş kalemlerini de gönderir. Müşteriye, Unemi Staff kasasından sonra olduğu gibi bildirim gider.
posApply -
İptal ve iade — 48 saat içinde
Fiş iptal ya da iade edilirse kasa onu Unemi'de de fiş numarasıyla iptal eder: her şey eski haline döner. Kısmi iadeyi kasa tutarıyla gönderir — Unemi bunu işletme sahibine gösterir.
posUndo
Sınırlar
- Anahtar başına dakikada 120 istek
- Tanıma oturumu tek fiş işler ve 2 saat geçerlidir, kasa anahtarında 12 saat
- Fiş 48 saat içinde iptal ya da iade edilebilir
- Bir fişte bir program ve en fazla 5 ödül ve kupon
- 15 dakika içindeki başarısız tanımalar: 5'ten sonra 1 dakika, 10'dan sonra 5 dakika, 15'ten sonra 30 dakika bekleme
- İşletme başına en fazla 10 etkin anahtar
Yöntem kılavuzu
Kılavuz İngilizcedir. Yöntem, alan ve hata kodu adları her dilde aynıdır. Rusça kılavuz
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.
Ayrıca bakın
-
Kasa entegrasyonları
Poster, iiko ve diğer kasalarla hazır entegrasyonlar bu API üzerine kurulur. Kendi kasanızı işaretleyin — önce hangisini yapacağımızı böyle anlarız.
-
Pro planı
Açık API, Pro planına dahildir. Planda başka neler olduğu ve nelerin şimdiden çalıştığı plan karşılaştırmasında.
-
Entegrasyon soruları
Ayrı bir test ortamı (sandbox) yok: entegrasyon, Pro planındaki bir test işletmesinde denenir. Bize yazın — bağlanmanıza yardımcı olalım.