Developer Documentation
Tabsy provides a simple REST API for delivering digital receipts from your POS to shoppers in real time. One POST per transaction — receipt in the shopper vault in under 500ms.
Authentication
All API requests must include your retailer API key as a Bearer token in the Authorization header.
Authorization: Bearer YOUR_API_KEY
API keys are issued privately per retailer. Each key is scoped to your account and can be rotated via the Retailer Portal. Never expose your API key in client-side code or public repositories.
POST /pos-receipt
Submit a receipt after each transaction. The shopper is identified by their Tabsy member code, which they present at checkout via QR code or verbally.
Content type
Content-Type: application/json
Request payload schema
| Field | Type | Required | Description |
|---|---|---|---|
member_code | string | Yes | Shopper's Tabsy member code (6-char alphanumeric) |
store_name | string | Yes | Your store or branch name as registered with Tabsy |
transaction_at | string (ISO 8601) | Yes | Transaction datetime in UTC, e.g. 2026-05-05T14:32:00Z |
currency | string (ISO 4217) | Yes | Three-letter currency code, e.g. AED, EUR, GBP |
total | number | Yes | Transaction total as a decimal number |
items | array | Yes | Array of line items (see item schema below) |
return_window_days | integer | No | Number of days the shopper has to return items (default: none) |
external_id | string | No | Your internal transaction or receipt ID for deduplication |
notes | string | No | Any free-text note attached to the receipt |
Item schema
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Product name |
price | number | Yes | Unit price |
qty | integer | No | Quantity (default: 1) |
sku | string | No | Your internal SKU or product code |
warranty_months | integer | No | Manufacturer warranty period in months |
category | string | No | Product category for analytics |
Example request
// Headers: Authorization: Bearer YOUR_API_KEY // Content-Type: application/json { "member_code": "A7K2M9", "store_name": "IKEA Dubai Marina", "transaction_at": "2026-05-05T14:32:00Z", "currency": "AED", "total": 329.00, "return_window_days": 14, "external_id": "POS-20260505-0042", "items": [ { "name": "BILLY Bookcase", "price": 199.00, "qty": 1, "sku": "BILLY-202X-WHT", "warranty_months": 24, "category": "Furniture" }, { "name": "KALLAX Shelf Unit", "price": 130.00, "qty": 1 } ] }
Response
Success (200 OK)
{
"status": "inserted",
"receipt_id": "rcpt_01jx3k2m...",
"delivery": "delivered"
}
Error codes
| HTTP status | Meaning | Action |
|---|---|---|
401 Unauthorized | Missing or invalid API key | Check your Authorization header and key value |
403 Forbidden | API key valid but not authorised for this store | Contact support to verify your key-store binding |
422 Unprocessable Entity | Payload validation failed | Check required fields and data types. Response body contains field-level errors. |
429 Too Many Requests | Rate limit exceeded | Back off and retry after the Retry-After header value (seconds) |
500 Internal Server Error | Server-side error | Retry with exponential backoff. If persistent, contact support. |
Rate limits
The API enforces rate limits per API key to protect infrastructure quality:
- Default limit: 300 requests per minute per API key
- Burst limit: Up to 60 requests per second for short bursts
- Enterprise: Higher limits available — contact us for high-volume configurations
When a rate limit is exceeded, the API returns 429 Too Many Requests with a Retry-After header indicating how many seconds to wait before retrying.
Webhook retry behaviour
Tabsy processes receipts asynchronously after initial acceptance. If delivery to the shopper fails, the system retries automatically:
- Retry schedule: 5 attempts over 24 hours (1min, 5min, 30min, 4hr, 20hr)
- Delivery status: Track delivery outcomes in your Retailer Portal under the Receipts tab
- Shopper not found: If no Tabsy account matches the member code, the receipt is held for 30 days in case the shopper registers later
- Idempotency: Use the
external_idfield to prevent duplicate receipts — the sameexternal_idsubmitted twice returns the original receipt