POS Integration
Connect your point-of-sale system to Xtarly Rewards to automatically award points or stamps when customers make a purchase.
The POS integration lets your point-of-sale system register transactions directly via a REST API. Every time a customer pays, your POS calls the Xtarly endpoint and the customer instantly receives their points or stamps — no manual scanning required.
Don't want to write code? There are 15 automatic connectors — Loyverse, Poster, Square, Clover, Toast, Bsale, Lightspeed, Odoo, Shopify, Alegra, CleanCloud, Epos Now, Mercado Pago, Clip and SumUp — that you connect in minutes from the POS integrations panel, no code required.
The POS REST API is a Premium plan feature: integrating your own system with Xtarly through code. It is not the same as connecting a POS from the catalog, which is available from the Shared plan and requires no programming — see the POS integrations dashboard. At the register you can always record sales from the cashier app, on any plan.
Getting your API key
- Open your organization dashboard and go to Settings → General.
- Scroll down to the POS Integration section.
- Click Generate API key. The key is shown once — copy it immediately and store it securely (e.g. in your POS system's environment configuration).
- If the key is ever compromised, click Rotate to invalidate the old key and generate a new one. If you already have a live key, you can rotate it even if your plan changes: you never lose the way to replace a leaked credential.
The API key is shown only once after generation. If you lose it, you will need to rotate and update all integrations using the old key.
Base URL
All POS endpoints are served from your Xtarly domain:
https://www.xtarly.com/api/integrations/posAuthentication
Include your API key in every request via the X-API-Key header:
X-API-Key: xtarly_pos_<your_key>Requests without a valid key return 401 Unauthorized.
Endpoints
Register a transaction
POST /api/integrations/pos/transactionCall this endpoint when a customer completes a purchase. Xtarly calculates the points or stamps earned based on your active reward program and credits them to the customer.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
amount | number | ✓ | Purchase total in the smallest currency unit (e.g. cents for MXN/USD). |
customerId | string | ✓ (or customerEmail) | Xtarly customer ID. |
customerEmail | string | ✓ (or customerId) | Customer's registered email. |
metadata | object | — | Optional free-form object attached to the transaction (e.g. { "ticket": "1234" }). |
Provide either customerId or customerEmail — at least one is required.
Example request
curl -X POST https://www.xtarly.com/api/integrations/pos/transaction \
-H "Content-Type: application/json" \
-H "X-API-Key: xtarly_pos_<your_key>" \
-d '{
"amount": 35000,
"customerEmail": "cliente@ejemplo.com",
"metadata": { "ticket": "T-00412" }
}'Successful response 200 OK
{
"success": true,
"data": {
"transactionId": "txn_abc123",
"earnedPoints": 35,
"earnedStamps": 0,
"customerPoints": 210,
"customerStamps": 0
}
}| Field | Description |
|---|---|
transactionId | Unique ID of the recorded transaction. |
earnedPoints | Points credited in this transaction. |
earnedStamps | Stamps credited in this transaction (stamp programs). |
customerPoints | Customer's total points after this transaction. |
customerStamps | Customer's total stamps after this transaction. |
Look up a customer
GET /api/integrations/pos/customer/:idReturns the current balance and tier of a customer. Useful to display loyalty status at the point of sale before or after a transaction.
Example request
curl https://www.xtarly.com/api/integrations/pos/customer/cus_abc123 \
-H "X-API-Key: xtarly_pos_<your_key>"Successful response 200 OK
{
"success": true,
"data": {
"id": "cus_abc123",
"name": "María García",
"email": "cliente@ejemplo.com",
"points": 210,
"stamps": 0,
"tier": null
}
}Point-of-sale endpoints
The same API key gives you access to the endpoints a connected point of sale uses: identifying the customer at the register, seeing what they can apply today, and redeeming coupons or rewards at checkout.
| Endpoint | What it's for |
|---|---|
GET /ping | Checks that the API key is valid and returns the program name. |
GET /program | Active program type (POINTS, STAMPS or TIERS) and what the unit is called ("puntos" or "sellos"). |
POST /accrue | Credits a POS sale. Idempotent by saleId. |
GET /customer/by-phone?phone= | Looks up the customer by phone number. |
GET /customer/by-qr?payload= | Looks up the customer from their card QR scanned at the register. |
GET /customer/by-email?email= | Looks up the customer by email (case-insensitive). |
GET /customer/benefits?customerId= | Everything that customer can apply today: available coupons and rewards with a verdict. |
GET /coupon/by-qr?payload= | Resolves a scanned coupon and says whether it can be redeemed. |
GET /coupon/by-code?code= | Same, with the code typed by hand. |
POST /coupon/redeem | Applies a coupon to the sale. Idempotent by saleId. |
POST /reward/redeem | Redeems a reward and deducts the points or stamps. Idempotent by saleId. |
All four customer lookup endpoints return the same shape: id, name, email, phone, points, stamps and tier (the tier name, or null).
Crediting a sale from the POS
POST /api/integrations/pos/accrue| Field | Type | Required | Description |
|---|---|---|---|
saleId | string | ✓ | The sale's id in your POS. It's the idempotency key: the same sale never credits twice. |
customerPhone | string | ✓ | The customer's phone number. |
amountCentavos | number | ✓ | Sale total in cents (integer). |
occurredAt | string | ✓ | Date and time of the sale. |
branchName | string | — | Name of the branch where the sale was charged. |
items | array | — | Ticket line items; stored verbatim on the transaction. |
The response carries a status: ACCRUED when credited (with pointsAccrued and stampsAccrued), SKIPPED if that sale was already processed or there's no active program, and CUSTOMER_NOT_FOUND if no customer has that phone number.
branchName is resolved against your active Xtarly branch names (case-insensitive), so the stamp or points land in the right branch instead of showing up with no branch in the activity feed. If it doesn't match exactly one branch, the transaction is saved without a branch.
What the customer can apply today
GET /api/integrations/pos/customer/benefits?customerId=cus_abc123Returns, in a single call, the program type, the customer, their available coupons and every reward with the verdict already computed: attainable says whether they can redeem it right now, and if not, blockedReason and blockedMessage explain why (not enough points, tier not reached, already used this cycle…).
Each reward also includes a benefit object with the executable semantics of the discount — its type, its value and the menu products it applies to — so the POS can apply it on its own instead of leaving the math to the cashier.
Redeeming a coupon or a reward
POST /api/integrations/pos/coupon/redeem
POST /api/integrations/pos/reward/redeemFor a coupon, send couponId, saleId, amountCentavos and, optionally, customerId and branchName. A coupon flagged as walk-in can be redeemed without a customerId.
For a reward, send rewardId, customerId, saleId and, optionally, amountCentavos and branchName.
Both answer status: "REDEEMED" with the redemptionId, and DUPLICATE if that same sale had already redeemed. The reward redemption also returns pointsSpent, stampsSpent and the customer's balance after the redemption.
Every condition is validated on the server: minimum purchase, required tier, expiry, per-customer redemption cap and balance. The POS doesn't decide whether a coupon applies — it asks and obeys the answer.
Points calculation
The points or stamps credited per transaction depend on your active program type:
| Program type | Calculation |
|---|---|
| Points | floor(amount / currencyUnit × pointsPerCurrency) |
| Tiers | Same as Points, then multiplied by the customer's tier multiplier. |
| Stamps | 1 stamp per transaction, regardless of amount. |
You configure currencyUnit and pointsPerCurrency in Settings → Program.
Error codes
| Code | HTTP | Description |
|---|---|---|
UNAUTHORIZED | 401 | Missing or invalid API key. |
VALIDATION_ERROR | 400 | amount or customer identifier not provided. |
NOT_FOUND | 404 | No customer found with the given ID or email in your organization. |
BAD_REQUEST | 400 | Your organization has no active reward program. |
POS integrations panel
Connect your point of sale from the dashboard — no code required — so every sale credits points or stamps to your customers automatically.
Connect your email (Resend) for campaigns
Step-by-step guide to connect your Resend account and send email campaigns to your customers from Xtarly.