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.
Sandbox & testing
Test your integration against the live endpoint without touching a real customer. There is no separate sandbox URL - test traffic is isolated by credentials instead, so going live needs no code change.
Test API keys
Generate a test key in the Retailer Portal (Integrations page). Test keys start with tsk_test_ and go exactly where a live key goes: the Authorization: Bearer header (or X-Api-Key). Receipts sent with a test key run the exact production pipeline - validation, shopper matching, warranty and return resolution - but are flagged as tests, delivered to the shared TEST01 sandbox shopper, and excluded from your live statistics. No email or push notification is ever sent for test traffic.
TEST member codes
Any receipt addressed to a member code starting with TEST is treated as sandbox traffic, whatever channel it arrives through. On a connected POS, ring up a sale with TABSY:TEST01 as the customer note and void it afterwards - the full webhook pipeline runs end to end and the result appears in the Test receipts list in your portal.
Going live
Replace your tsk_test_ key with a live key. Same endpoint, same payload, same response format.
external_id. Prefix your test transaction ids (for example test-001) so they can never collide with real sales.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