Run your YAS Connect loyalty card from your own till, shop or back office. Enrol members, read balances and record transactions — and every transaction you record pushes straight to the customer's Apple Wallet pass.
Every request is scoped to one card. The key you hold resolves to a card on our side, so there is no card id to send and no way to reach another business's members — not by guessing an id, and not by sending one.
Base URL
https://www.yasconnect.me/api/v1/loyalty
Quick start
Four steps from nothing to a stamp on somebody's lock screen. The whole integration is the third one; the rest is finding out what you are working with.
Ask for a key
From your loyalty dashboard. You get a merchant ID, which is public, and an API key. A YAS Connect administrator grants them before they work — until then every call answers 401.
Check the key, and what the card collects
type comes back as stamp-card or points-card, and it is what decides the unit you send on a transaction. Ask rather than assume: a business can be issued either, and the wrong unit is refused.
Enrolling the same address twice is not an error and does not create a second card — you get the existing member back with their balance intact, which is what makes a retry after a timeout safe.
This is the part that reaches the customer: the transaction is written and their Apple Wallet pass updates itself, with no second call from you. Send an Idempotency-Key so a timeout you retry cannot award twice. Points cards can earn by direct amount, by amountKwd, or by amountKwd plus rewardPercent.
Read the card rules before awarding.GET /card returns rules.earnRuleType. If it is points_per_kwd, use pointsPerKwd and pointValueFils. If it is purchase_percent, send amountKwd with rewardPercent; the API banks that percentage as KWD value, then converts it to points from the card's pointValueFils.
Points can come from a purchase percentage. For a points card, send amountKwd and rewardPercent instead of amount. A 10.000 KWD purchase at 5% banks 0.500 KWD worth of points, using the card's point value.
A full stamp card banks a reward. Stamps roll over on their own when the card fills; what the customer then hands over at the counter is a reward. Redeem one with { "action": "redeem", "unit": "rewards", "amount": 1 }, or grant one outright by earning it.
Code examples
The same till integration in four languages: find the member, award the stamp, read back what they hold. Each one handles the two answers worth branching on — nobody enrolled under that address, and a redemption refused for want of balance.
cURL
# 1. Which unit does this card collect? Ask it, rather than assuming.
curl -s "https://www.yasconnect.me/api/v1/loyalty/card" \
-H "Authorization: Bearer $YAS_API_KEY" \
-H "X-YAS-Merchant-ID: $YAS_MERCHANT_ID" | jq -r '.type'
# 2. Find the member at the counter.
MEMBER=$(curl -s "https://www.yasconnect.me/api/v1/loyalty/members?email=hussain@example.com" \
-H "Authorization: Bearer $YAS_API_KEY" \
-H "X-YAS-Merchant-ID: $YAS_MERCHANT_ID" | jq -r '.data[0].id')
# 3. Record a KWD purchase at 5%, keyed by the order so a retry cannot award it twice.
curl -s -X POST "https://www.yasconnect.me/api/v1/loyalty/transactions" \
-H "Authorization: Bearer $YAS_API_KEY" \
-H "X-YAS-Merchant-ID: $YAS_MERCHANT_ID" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-4471" \
-d "{\"memberId\":\"$MEMBER\",\"operation\":\"ADD_SPEND\",\"amountKwd\":10,\"rewardPercent\":5,\"note\":\"Order #4471\"}"
# 4. Their pass updates itself. This is only to show them the new balance on your screen.
curl -s "https://www.yasconnect.me/api/v1/loyalty/members/$MEMBER" \
-H "Authorization: Bearer $YAS_API_KEY" \
-H "X-YAS-Merchant-ID: $YAS_MERCHANT_ID" | jq '{stamps, points}'
OpenAPI & Postman
Both are generated from the same reference this page is rendered from, so neither can describe an endpoint that does not exist or miss one that does.
Postman can import the OpenAPI document too, but what it builds from one is a folder of requests with empty bodies. The collection carries the examples, so the first request does something you can then edit.
The spec follows the host you fetched it from. Pulling it from a preview deployment gives you a client that talks to that preview — a generated client quietly calling production from a staging branch is the sort of thing that is only noticed afterwards.
Authentication
Each card can be issued a credential: a merchant ID, which is public and identifies you, and an API key, which is secret. We check them together on every request; a key sent with another merchant ID is refused. We store only the key hash, so a lost key has to be revoked and replaced.
Send the key as a bearer token, and send the merchant ID in X-YAS-Merchant-ID, on every request. Requests are server-to-server: there are no CORS headers, so a browser cannot call this, which is deliberate — a key usable from a page is a key sitting in every visitor's devtools.
A key does nothing until it is granted. New credentials start switched off. A YAS Connect administrator turns access on for your card, and can turn it off again — so holding a key is not the same as having access.
Scopes
A credential is granted the scopes it needs and no more. A reporting tool that only reads balances should not hold a key that can also award points. Calling an endpoint outside your scopes answers 403 and names the missing scope — the key is fine, so regenerating it will not help.
Scope
Allows
members:read
Look a member up by id, email or phone, and read their balance.
members:write
Enrol a new member on this card.
transactions:read
List the transactions recorded against this card.
transactions:write
Add or redeem points, stamps and rewards.
points:write
Run points-card actions: add points, add purchase, or redeem points/KWD balance.
stamps:write
Run stamp-card actions: add stamps, remove stamps, or redeem banked rewards.
Rate limits
120 requests per minute by default, counted per credential rather than per address — one integration behaving badly cannot exhaust the allowance of every other business calling from the same cloud provider. Over the limit answers 429. If your volume needs more, ask; the limit is a number on your credential, not a property of the platform.
Errors
Every failure answers in the same shape. Branch on error.code — it is stable, and the sentence beside it is not: we reword messages whenever a clearer one exists, and an integration that matches on the text breaks the day we do. The status tells you the class of problem; the code tells you which problem.
requestId identifies the exact request in our logs and is also returned as the X-YAS-Request-ID header on every response, successful or not. Quote it when reporting a problem and we can find the request itself.
Error shape
{
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Member has 3 stamps, which is fewer than the 4 requested.",
"requestId": "req_01JBQ4M8ZK3XN7WVR2C5H9TFDG"
},
"message": "Member has 3 stamps, which is fewer than the 4 requested.",
"requestId": "req_01JBQ4M8ZK3XN7WVR2C5H9TFDG"
}
Error codes
Adding a code is not a breaking change, so handle an unrecognised one by falling back to the status. Moving an existing failure onto a different code is breaking, and we will not do it inside v1.
Code
Status
Meaning
INVALID_REQUEST
400
The request body or query string did not match the documented shape. The message names the field.
UNAUTHORIZED
401
No usable API key was presented. Every refusal at the door answers this way, whatever the underlying reason.
FORBIDDEN
403
The key is real but is not allowed to act on this object.
INVALID_API_KEY
401
Reserved. The door answers UNAUTHORIZED so a prober cannot tell a wrong key from a revoked one.
API_KEY_DISABLED
401
Reserved, for the same reason as INVALID_API_KEY.
INSUFFICIENT_SCOPE
403
The key is valid but was not granted the scope this endpoint needs. The message names the scope.
RATE_LIMIT_EXCEEDED
429
Too many requests on this credential. Retry-After says how long to wait.
MEMBER_NOT_FOUND
404
No member with that id belongs to the card this key serves.
MEMBER_SUSPENDED
409
The member is suspended. Reactivate them before recording activity.
MEMBER_ALREADY_EXISTS
409
A member with that email or phone is already enrolled on this card.
PROGRAM_NOT_FOUND
404
The loyalty card behind this key is gone or frozen.
TRANSACTION_NOT_FOUND
404
No transaction with that id belongs to the card this key serves.
INSUFFICIENT_BALANCE
422
The member holds less than the redemption asked for. Nothing was changed.
INVALID_REDEMPTION
422
The redemption is not valid for this card's rules.
INVALID_ADJUSTMENT
422
The adjustment would leave the balance in a state the card does not allow.
ALREADY_REVERSED
409
That transaction has already been reversed. A reversal happens once.
NOT_REVERSIBLE
422
That transaction cannot be reversed — a reversal itself is not reversible.
IDEMPOTENCY_CONFLICT
409
The same Idempotency-Key was reused with a different body.
DUPLICATE_EXTERNAL_ID
409
That externalId is already recorded on this card in this environment.
WEBHOOK_NOT_FOUND
404
No webhook endpoint with that id belongs to the card this key serves.
INVALID_WEBHOOK_URL
400
The URL is not a public HTTPS address we are willing to deliver to.
WEBHOOK_LIMIT_REACHED
409
This card already has the maximum number of webhook endpoints.
INTERNAL_ERROR
500
Our fault. The requestId in the response is what to quote when reporting it.
Statuses
Status
Meaning
400 Bad request
A field or query parameter was rejected. The message names which one.
401 Unauthorized
No key, no merchant ID, an unknown or mismatched credential, a revoked key, a key that has not been granted access, or a card that has been frozen. They answer the same way on purpose — the difference is ours to know, not a prober's.
403 Forbidden
The key is real but has not been granted the scope this endpoint needs. Ask the card owner to grant it; regenerating the key will not help.
404 Not found
No such member on your card.
422 Unprocessable
The request was understood but cannot be carried out — redeeming more than the member holds is the usual cause.
429 Too many requests
Over your per-minute allowance. Counted per key, so another integration cannot spend yours.
500 Server error
Ours. Safe to retry, and safer still with an Idempotency-Key.
Idempotency
Send an Idempotency-Key header on every transaction you record. A request that times out leaves you unable to tell whether the points landed, and without a key your only two options are to double-award or to skip. With one, the retry replays the first answer and returns 200 instead of 201, so you can tell the two apart.
Use something from your own system that identifies the event — an order number, a receipt id. Keys are scoped to the member, so two members can carry the same one.
Retrying safely
Idempotency-Key: order-4471
Pagination
Lists answer with data and nextCursor. Pass nextCursor back as cursor to get the following page; a null cursor means you have reached the end.
Cursors are timestamps rather than offsets. An offset drifts when a row is inserted mid-page, which on a transactions feed means silently skipping one.
When you record a transaction, the member's Apple Wallet pass is updated without you doing anything else. We send a silent push to every device holding that pass, iOS comes back for a fresh copy, and the new balance appears on the lock screen.
A device that misses the push refreshes the next time iOS asks, so a failed notification never costs the customer their points — and a push that cannot be delivered never fails your request. The transaction is committed first, always.
Returns the loyalty card your key belongs to, including whether it collects points or stamps. Call this first — it tells your integration which unit to send on a transaction. Points cards include the earn rule: points_per_kwd awards points directly from KWD spend, while purchase_percent banks a percentage of the purchase value. No scope is required.
Lists the members of your card, newest first. Pass email, phone or memberId to find one person — each of those identifies a single member, so the list comes back with at most one entry.
Returns one member and their current balance. A member belonging to another card answers 404 rather than 403 — whether that id exists at all is not something your key gets to learn.
Enrols someone on your card and returns them. Enrolling the same email twice is not an error and does not create a second card — you get the existing member back, balance intact, which makes a retry after a timeout safe. If that address already has a YAS Connect account, the card lands on it.
Runs the same balance buttons the scanner exposes, records the ledger movement, and pushes the change to the member's Apple Wallet pass. Send operation for the button you want: ADD_POINTS, ADD_SPEND, REDEEM_POINTS and SET_POINTS on points cards; ADD_STAMP, REMOVE_STAMP, REDEEM_REWARD and SET_REWARDS on stamp cards. The key needs transactions:write, or the narrower points:write/stamps:write scope for the balance being moved. The older action + unit shape remains supported. Redeeming more than the member holds is refused with 422 rather than clamped to zero — you are told the redemption did not happen instead of being told it did.
Recommended. The scanner button to run for this member.
action
earn | redeem | adjust
Legacy shape. earn adds, redeem subtracts, adjust sets the balance to an exact figure. Send action + unit instead of operation.
unit
points | stamps | rewards
Legacy shape. Which balance to move when using action + unit.
amount
integer
How many points, stamps or rewards to add or take. SET_POINTS and SET_REWARDS use amount as the exact balance, so amount 0 resets it. Stamp/reward movement operations default to 1 if omitted. For ADD_SPEND, amount can be the KWD purchase value when amountKwd is not sent.
amountKwd
number
Points cards only: KWD balance for ADD_POINTS or REDEEM_POINTS, or purchase value for ADD_SPEND. YAS Connect converts it using the card rules returned by GET /card.
rewardPercent
number
ADD_SPEND only: percentage of amountKwd to bank as reward value before converting to points. Example: amountKwd 10 and rewardPercent 5 banks 0.500 KWD, then converts that value using pointValueFils.
note
string
What the customer sees on their statement. An order number belongs here.
Redeems points, stamps or banked rewards from a member, records the ledger movement, and pushes the updated balance to Wallet. The key needs transactions:write, or the narrower points:write/stamps:write scope for the balance being moved. Use this as the direct POS redemption endpoint; POST /transactions with action redeem remains supported. Redeeming more than the member holds is refused with 422.
Body
Name
Type
Description
memberIdrequired
uuid
Who is spending the balance.
unitrequired
points | stamps | rewards
Which balance to redeem. Use points for points cards, stamps for stamp corrections, and rewards for banked rewards.
amount
integer
How many points, stamps or rewards to spend.
amountKwd
number
Points only: KWD balance to redeem. Send this instead of amount and YAS Connect converts it to points.
note
string
What the customer sees on their statement. An order number or reward name belongs here.