POS Vendor Integration Guide¶
This guide provides step-by-step instructions for POS systems that want to integrate with Cata's platform. If you're a POS vendor building an integration, follow this guide to understand what you need to implement.
1. Authentication¶
All POS integrations with Cata use API Key authentication.
1.1 API Key Format¶
- Header:
X-Api-Key - Value: A tenant-scoped API key provided by Cata (ask your Cata partner manager)
- Scope: Each key is valid for exactly one tenant (restaurant group)
1.2 API Key Validation¶
Before implementing any integration logic, verify your API key works:
curl -i "https://{tenant}.sgp1.samba-technologies.xyz/service/pos-integration/api/v1/auth/whoami" \
-H "X-Api-Key: your-api-key-here"
Success Response (200 OK):
{
"authenticated": true,
"tenantId": "tenant-uuid-123",
"apiKeyId": 42,
"expiresAt": "2026-12-31T23:59:59Z"
}
Failure Responses:
- 401 Unauthorized: Key is missing, invalid, or expired
- Always treat 401 as a fatal error — don't retry
1.3 Tenant Subdomain Resolution¶
Each tenant has a unique subdomain. The API routes to the correct database based on the subdomain:
https://{TENANT_SUBDOMAIN}.sgp1.samba-technologies.xyz/service/pos-integration/api/v1/...
Example: If your tenant is "golden-dragon", your base URL is:
https://golden-dragon.sgp1.samba-technologies.xyz/service/pos-integration/api/v1
1.4 API Key Rotation¶
- Cata admin console can issue new keys and revoke old ones
- Rotation requires no coordination — issue a new key, update your integration, then revoke the old one
- No downtime needed
2. Webhook Registration for Order Status¶
When Cata receives an order payment, it dispatches the order to your POS via a webhook. You must register exactly one webhook URL per outlet to receive these order notifications.
2.1 Register a Webhook (One-time Setup)¶
Endpoint: POST /api/v1/webhooks/register
Required Headers:
- X-Api-Key: your-api-key
- Content-Type: application/json
Request Body:
{
"outletId": "store-uuid-123",
"provider": "your-pos-system-slug",
"callbackUrl": "https://your-pos-api.example.com/webhooks/cata/orders",
"events": ["order.paid"]
}
Field Explanations:
| Field | Type | Description |
|---|---|---|
outletId |
UUID | The outlet (store location) UUID. Get this from Cata. |
provider |
string | A slug uniquely identifying your POS system in Cata's system (e.g., "revel", "your-pos"). One webhook per (outletId, provider). |
callbackUrl |
URL | Your public HTTPS endpoint that will receive order payloads. Must be HTTPS. Must be reachable from the internet. |
events |
array | Event subscriptions. Currently only ["order.paid"] is supported. |
Success Response (201 Created):
{
"code": 201,
"isSuccess": true,
"message": "webhook registered",
"webhook": {
"id": 1,
"outletId": "store-uuid-123",
"provider": "your-pos",
"callbackUrl": "https://your-pos-api.example.com/webhooks/cata/orders",
"events": ["order.paid"],
"secret": "whsec_abc123xyz789...",
"isActive": true,
"createdAt": "2026-03-13T10:00:00Z"
}
}
⚠️ CRITICAL: Save the Secret Immediately¶
The secret is shown only once in the registration response. Store it securely — you'll use it to verify webhook signatures. If you lose it, rotate it using the endpoint below.
2.2 Update a Webhook¶
If you need to change the callback URL or subscribed events later:
Endpoint: PUT /api/v1/webhooks/{webhookId}
Request Body:
{
"callbackUrl": "https://new-url.example.com/webhooks/cata/orders",
"events": ["order.paid"],
"isActive": true
}
All fields are optional — omit any you don't want to change.
2.3 Rotate the Signing Secret¶
If you suspect the secret is compromised or lost it:
Endpoint: POST /api/v1/webhooks/{webhookId}/rotate-secret
Response:
{
"secret": "whsec_new_secret_xyz..."
}
A new secret is generated and returned once. Update your local configuration immediately.
2.4 List Your Registered Webhooks¶
Endpoint: GET /api/v1/webhooks
Response:
{
"webhooks": [
{
"id": 1,
"outletId": "store-uuid-123",
"provider": "your-pos",
"callbackUrl": "https://your-pos-api.example.com/webhooks/cata/orders",
"events": ["order.paid"],
"isActive": true,
"createdAt": "2026-03-13T10:00:00Z",
"updatedAt": "2026-03-15T14:30:00Z"
}
],
"total": 1
}
Note: secret is never included in list responses — it's only shown at registration and rotation.
2.5 Delete a Webhook¶
Endpoint: DELETE /api/v1/webhooks/{webhookId}
This soft-deletes the webhook and stops all deliveries to its callback URL. To resume, re-register with the same (outletId, provider) pair — you'll get a new ID and secret.
3. Receiving Webhook Events¶
When an order is paid in Cata, Cata POSTs to your registered callbackUrl. This section explains what you receive, how to verify it, and how to parse it.
3.1 Webhook Delivery Headers¶
Every webhook request includes these headers for identification and signature verification:
| Header | Value | Purpose |
|---|---|---|
X-Cata-Event |
order.paid |
Event type |
X-Cata-Delivery-ID |
UUID | Unique delivery identifier (idempotency key) |
X-Cata-Timestamp |
Unix timestamp | Time Cata dispatched the webhook |
X-Cata-Signature |
sha256=<hex> |
HMAC-SHA256 signature (see section 3.2) |
3.2 Verify the Webhook Signature¶
Every webhook is signed using your secret. Always verify the signature before processing the order.
Signature Formula:
X-Cata-Signature = "sha256=" + HEXDIGEST( HMAC-SHA256(secret, raw_body) )
Python Example:
import hmac
import hashlib
import json
def verify_webhook(secret, raw_body, signature_header):
"""Verify the X-Cata-Signature header against the webhook body."""
expected_sig = "sha256=" + hmac.new(
secret.encode('utf-8'),
raw_body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected_sig, signature_header)
# In your Flask/Django handler:
@app.post('/webhooks/cata/orders')
def handle_order_webhook():
raw_body = request.get_data() # Raw bytes, not parsed JSON
signature = request.headers['X-Cata-Signature']
if not verify_webhook(SECRET, raw_body, signature):
return {'error': 'invalid signature'}, 401
order = json.loads(raw_body)
# Process order...
Node.js Example:
const crypto = require('crypto');
function verifyWebhook(secret, rawBody, signatureHeader) {
const expectedSig = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expectedSig),
Buffer.from(signatureHeader)
);
}
app.post('/webhooks/cata/orders', (req, res) => {
const signature = req.get('X-Cata-Signature');
const rawBody = req.body; // Middleware must NOT parse JSON first
if (!verifyWebhook(process.env.WEBHOOK_SECRET, rawBody, signature)) {
return res.status(401).json({ error: 'invalid signature' });
}
const order = JSON.parse(rawBody);
// Process order...
});
3.3 Webhook Body (Order Payload)¶
The webhook body is a JSON object with the complete order details:
{
"uuid": "ord-550e8400-e29b-41d4-a716-446655440000",
"orderRefNo": "ORD-2024-001",
"dailyQueueNo": "A12",
"storeUuid": "store-uuid-123",
"storeName": "Downtown Branch",
"deliveryMethod": "DELIVERY",
"status": "PAID",
"currency": "AED",
"isPreorder": false,
"items": [
{
"plu": "SKU-BURGER-01",
"name": "Classic Burger",
"quantity": 2,
"itemOnlyPrice": 35.00,
"modifierOnlyPrice": 5.00,
"itemPrice": 40.00,
"itemSubTotal": 80.00,
"modifiers": [
{
"modifierHeaderId": "mh-cheese",
"modifierOptionId": "mo-extra-cheese",
"modifierHeaderName": "Cheese",
"modifierOptionName": "Extra Cheese",
"price": 5.00,
"quantity": 1
}
]
}
],
"subtotal": 80.00,
"discountTotal": 0.00,
"serviceCharge": 0.00,
"deliveryFee": 5.00,
"totalPay": 85.00,
"payment": {
"amount": 85.00,
"tip": 5.00,
"method": "CARD"
},
"customer": {
"uuid": "cust-123",
"name": "John Doe",
"email": "john@example.com",
"phone": "+971501234567"
},
"delivery": {
"address": "123 Main St, Dubai",
"notes": "Leave at door"
},
"createdAt": "2024-12-01T14:30:00Z"
}
Key Fields for Order Processing:
| Field | Type | Use |
|---|---|---|
uuid |
UUID | Unique order identifier — use this to track the order in Cata |
orderRefNo |
string | Human-readable order reference (for receipts, kitchen display) |
dailyQueueNo |
string | Queue number for your KDS |
items |
array | Line items with modifiers |
totalPay |
decimal | Final amount paid (including fees, discounts) |
deliveryMethod |
enum | DELIVERY, PICKUP, DINE_IN, TAKEOUT |
customer |
object | Customer details for delivery/contact |
createdAt |
ISO-8601 | When the order was placed |
3.4 Handling Duplicate Deliveries¶
Cata may deliver the same webhook multiple times (network retries, etc.). Use the X-Cata-Delivery-ID header as an idempotency key:
@app.post('/webhooks/cata/orders')
def handle_order_webhook():
delivery_id = request.headers['X-Cata-Delivery-ID']
# Check if we've already processed this delivery
if OrderDelivery.objects.filter(delivery_id=delivery_id).exists():
return {'status': 'already processed'}, 200
order = json.loads(request.get_data())
# Process the order...
# Record the delivery as processed
OrderDelivery.objects.create(
delivery_id=delivery_id,
order_uuid=order['uuid'],
processed_at=now()
)
return {'status': 'accepted'}, 200
3.5 Webhook Response¶
You must respond with HTTP 200 OK (or any 2xx status) to confirm receipt:
{
"status": "accepted",
"message": "Order received and queued for kitchen"
}
Cata does not parse your response body — any non-2xx response triggers retries (backoff over several minutes).
4. Update Order Status¶
As the order moves through your kitchen/fulfillment pipeline, push status updates back to Cata. This allows the customer to track their order in real-time.
4.1 Status Update Endpoint¶
Endpoint: POST /api/v1/orders/{orderId}/status
URL Parameters:
- {orderId}: The order UUID from the webhook (e.g., ord-550e8400-e29b-41d4-a716-446655440000)
Required Headers:
- X-Api-Key: your-api-key
- Content-Type: application/json
Request Body:
{
"status": "ACCEPTED",
"posOrderId": "POS-12345",
"timestamp": "2024-12-01T14:35:00Z"
}
Field Explanations:
| Field | Type | Required | Description |
|---|---|---|---|
status |
string | Yes | The new order status (see 4.2 for valid values) |
posOrderId |
string | No | Your internal POS order ID (for reconciliation) |
timestamp |
ISO-8601 | Yes | When the status change occurred (UTC) |
4.2 Valid Status Values¶
The order must follow this state machine. Not all transitions are allowed:
PAID → ACCEPTED, CANCELLED, COMPLETED
ACCEPTED → IN PROGRESS, READY, DRIVER PICKED UP, COMPLETED, CANCELLED
IN PROGRESS → READY, DRIVER PICKED UP, COMPLETED, CANCELLED
READY → DRIVER PICKED UP, COMPLETED, CANCELLED
DRIVER PICKED UP → COMPLETED, CANCELLED
COMPLETED → CANCELLED (late-cancellation only)
CANCELLED → (terminal)
Status Descriptions:
| Status | Meaning | When to Send |
|---|---|---|
ACCEPTED |
Order received and confirmed | Kitchen staff acknowledged the order |
IN PROGRESS |
Order is being prepared | Started cooking |
READY |
Order is ready for pickup/delivery | Ready at pickup counter or with driver |
DRIVER PICKED UP |
Driver picked up the order (delivery only) | Driver confirmed they have the order |
COMPLETED |
Order completed | Delivered to customer or picked up |
CANCELLED |
Order cancelled | Customer or POS cancelled the order |
4.3 Important Notes on Status Updates¶
- Exact Status String Format
- Note the literal spaces in
"IN PROGRESS"and"DRIVER PICKED UP" - No underscores, no case-folding
-
Example:
"IN PROGRESS"(not"in_progress"or"inProgress") -
Cancellation Requires a Reason
-
When setting status to
CANCELLED, include areasonfield:{ "status": "CANCELLED", "reason": "Out of stock", "timestamp": "2024-12-01T14:45:00Z" } -
Idempotency
- Replaying the same status twice is safe
- First transition:
PAID → ACCEPTEDat timestampT1 - Replay
ACCEPTEDat timestampT1orT2: no-op, originalT1timestamp preserved - Response will show
previousStatus == currentStatus
4.4 Success Response (200 OK)¶
{
"orderId": "ord-550e8400-e29b-41d4-a716-446655440000",
"currentStatus": "ACCEPTED",
"previousStatus": "PAID",
"transitionedAt": "2024-12-01T14:35:00Z"
}
4.5 Error Responses¶
400 Bad Request:
{
"error": {
"code": 400,
"message": "unsupported status: INVALID_STATUS",
"details": "partners may only push [ACCEPTED, IN PROGRESS, READY, DRIVER PICKED UP, COMPLETED, CANCELLED]"
}
}
401 Unauthorized:
{
"error": {
"code": 401,
"message": "invalid api key",
"details": "the provided X-Api-Key is invalid or expired"
}
}
404 Not Found:
{
"error": {
"code": 404,
"message": "order not found",
"details": "no dispatched order found for the given orderId in this tenant"
}
}
409 Conflict (Invalid State Transition):
{
"error": {
"code": 409,
"message": "invalid status transition",
"details": "cannot change order status from PAID to READY"
}
}
5. Complete Integration Checklist¶
Use this checklist to verify your integration is complete:
- [ ] Authentication
- [ ] Obtained API key from Cata partner manager
- [ ] Tested
/auth/whoamiendpoint successfully -
[ ] Stored key securely (environment variable, not in code)
-
[ ] Webhook Registration
- [ ] Called
POST /api/v1/webhooks/registeronce per outlet - [ ] Received webhook
secretand saved it securely - [ ] Webhook callback URL is publicly accessible over HTTPS
- [ ] Callback URL handles multiple webhooks concurrently
-
[ ] Stored
webhookIdfor future reference (updates, rotation, etc.) -
[ ] Webhook Receipt & Verification
- [ ] Callback handler checks
X-Cata-Signaturebefore processing - [ ] Signature verification uses correct secret and HMAC-SHA256
- [ ] Callback returns HTTP 200 on successful receipt
-
[ ] Callback returns HTTP 200 even on duplicate
X-Cata-Delivery-ID(idempotency) -
[ ] Order Processing
- [ ] Parse order JSON from webhook body
- [ ] Extract
uuidas the unique order identifier - [ ] Extract line items with modifiers and prices
- [ ] Create order in your POS system
-
[ ] Handle all delivery methods (
DELIVERY,PICKUP,DINE_IN,TAKEOUT) -
[ ] Status Updates
- [ ] Push status via
POST /api/v1/orders/{orderId}/statusas order progresses - [ ] Use exact status strings (
ACCEPTED,IN PROGRESS,READY, etc.) - [ ] Include
timestampin ISO-8601 format - [ ] Respect the state machine — not all transitions are valid
-
[ ] Include
reasonwhen status isCANCELLED -
[ ] Error Handling
- [ ] Retry webhook reception on non-2xx responses (with backoff)
- [ ] Handle
401 Unauthorizedgracefully (re-authenticate, don't retry) - [ ] Log webhook delivery IDs and timestamps for debugging
-
[ ] Monitor for missing/stale orders in POS
-
[ ] Testing
- [ ] Tested end-to-end with a real order in sandbox/staging
- [ ] Verified order appears in POS with correct items and prices
- [ ] Verified status updates appear in Cata UI in real-time
- [ ] Tested webhook signature verification with a known secret
- [ ] Tested idempotent replay (same
X-Cata-Delivery-IDtwice)
6. Troubleshooting¶
Webhook not received¶
- Check that
callbackUrlis publicly accessible (no firewall/NAT blocking) - Test manually:
curl -X POST https://your-pos-api/webhooks/cata/orders - Check firewall rules allow inbound HTTPS from Cata's IP ranges
- Verify callback handler logs are being written (enable debug logging)
Signature verification fails¶
- Verify you're using the correct
secret(not thewebhookId) - Verify you're signing the raw body bytes, not the parsed JSON
- Verify the header name is exactly
X-Cata-Signature - Verify you're using HMAC-SHA256 (not SHA256, HMAC-MD5, etc.)
- Test with the example payloads in the troubleshooting section (below)
Status updates are rejected (400/409)¶
- Verify the
statusstring matches exactly (spaces, case, etc.) - Verify the current order status allows the transition
- Verify you're using the
uuidfrom the webhook, notorderRefNo
API key keeps returning 401¶
- Verify the key hasn't expired (check
expiresAtfrom/auth/whoami) - Verify the subdomain matches the tenant (e.g.,
golden-dragon.sgp1...) - Ask Cata to rotate the key if it's old
- Verify header name is exactly
X-Api-Key(case-sensitive)
7. Code Examples¶
Python (Flask)¶
from flask import Flask, request, jsonify
import hmac
import hashlib
import json
from datetime import datetime
app = Flask(__name__)
WEBHOOK_SECRET = 'whsec_abc123xyz789...'
API_KEY = 'your-api-key'
TENANT_SUBDOMAIN = 'golden-dragon'
BASE_URL = f'https://{TENANT_SUBDOMAIN}.sgp1.samba-technologies.xyz/service/pos-integration/api/v1'
def verify_webhook(secret, raw_body, signature_header):
expected_sig = 'sha256=' + hmac.new(
secret.encode('utf-8'),
raw_body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected_sig, signature_header)
@app.post('/webhooks/cata/orders')
def handle_order():
raw_body = request.get_data()
signature = request.headers.get('X-Cata-Signature')
delivery_id = request.headers.get('X-Cata-Delivery-ID')
if not verify_webhook(WEBHOOK_SECRET, raw_body, signature):
return {'error': 'invalid signature'}, 401
order = json.loads(raw_body)
# TODO: Create order in your POS system
print(f"Order received: {order['uuid']}, items: {len(order['items'])}")
# TODO: After order is created in your KDS:
update_order_status(order['uuid'], 'ACCEPTED')
return {'status': 'accepted'}, 200
def update_order_status(order_uuid, status):
"""Push order status back to Cata."""
import requests
response = requests.post(
f'{BASE_URL}/orders/{order_uuid}/status',
headers={'X-Api-Key': API_KEY},
json={
'status': status,
'timestamp': datetime.utcnow().isoformat() + 'Z'
}
)
if response.status_code != 200:
print(f"Status update failed: {response.status_code} {response.text}")
else:
print(f"Status updated to {status}")
if __name__ == '__main__':
app.run(port=5000)
Node.js (Express)¶
const express = require('express');
const crypto = require('crypto');
const axios = require('axios');
const app = express();
app.use(express.raw({ type: 'application/json' })); // Keep body as Buffer
const WEBHOOK_SECRET = 'whsec_abc123xyz789...';
const API_KEY = 'your-api-key';
const BASE_URL = 'https://golden-dragon.sgp1.samba-technologies.xyz/service/pos-integration/api/v1';
function verifyWebhook(secret, rawBody, signatureHeader) {
const expectedSig = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expectedSig),
Buffer.from(signatureHeader)
);
}
app.post('/webhooks/cata/orders', (req, res) => {
const signature = req.get('X-Cata-Signature');
const deliveryId = req.get('X-Cata-Delivery-ID');
if (!verifyWebhook(WEBHOOK_SECRET, req.body, signature)) {
return res.status(401).json({ error: 'invalid signature' });
}
const order = JSON.parse(req.body);
console.log(`Order received: ${order.uuid}, items: ${order.items.length}`);
// TODO: Create order in your POS system
// TODO: After order is created:
updateOrderStatus(order.uuid, 'ACCEPTED');
res.json({ status: 'accepted' });
});
async function updateOrderStatus(orderId, status) {
try {
const response = await axios.post(
`${BASE_URL}/orders/${orderId}/status`,
{
status: status,
timestamp: new Date().toISOString()
},
{
headers: { 'X-Api-Key': API_KEY }
}
);
console.log(`Status updated to ${status}`);
} catch (error) {
console.error(`Status update failed: ${error.response?.status} ${error.response?.data}`);
}
}
app.listen(3000, () => console.log('Listening on port 3000'));
8. Future Enhancements (TODO)¶
The following features are planned but not yet implemented:
8.1 TODO: OAuth 2.0 Authentication¶
When: Future release
What: Alongside the current API key flow, support OAuth 2.0 with scoped permissions
Scopes (proposed):
- orders:read — read order details
- orders:write — submit/update orders
- products:read — read menu/catalog
- webhooks:* — manage webhooks
Impact: No migration required for current API-key integrations. Will be purely additive.
8.2 TODO: Additional Webhook Events¶
When: Future
What: Expand beyond just order.paid to include:
| Event | Trigger | Status |
|---|---|---|
order.paid |
Order is paid | ✅ Live |
order.cancelled |
Order was cancelled | 🔄 TODO |
menu.updated |
Menu was published | 🔄 TODO |
outlet.status_changed |
Outlet opened/closed | 🔄 TODO |
8.3 TODO: Bulk Order API¶
When: Future
What: Accept multiple orders in a single request (useful for back-office integrations)
Endpoint: POST /api/v1/orders/bulk-dispatch
Payload: Array of order payloads
8.4 TODO: Customer Auto-Registration¶
When: Before POS that require pre-existing customers go live (e.g., iSeller)
What: Cata will auto-create customers in your POS if they don't exist
Current Workaround: Customers must be manually registered in your POS before Cata dispatches orders.
8.5 TODO: Idempotency Headers¶
When: Future
What: Support Idempotency-Key header on order dispatch for stricter deduplication
Format: Standard UUID or any unique string
Behavior: Replaying with the same key within a 24-hour window returns the same response without re-processing
8.6 TODO: Order Cancellation from POS¶
When: Future
What: Allow your POS to request order cancellation in Cata (currently Cata can cancel, but POS cannot initiate)
Endpoint: POST /api/v1/orders/{orderId}/cancel-request
Payload: Reason + confirmation
9. Support & Contact¶
For integration questions or issues:
- Check this guide for common problems (section 6)
- Check the API reference at
https://dev.docs.cata.sg(or the docs URL for your environment) - Contact Cata: integration-support@cata.sg
- GitHub Issues: If you find a bug in the API, open an issue with steps to reproduce
Appendix: Example Payloads¶
Appendix A: Order Webhook Example¶
Headers:
X-Cata-Event: order.paid
X-Cata-Delivery-ID: evt-550e8400-e29b-41d4-a716-446655440000
X-Cata-Timestamp: 1725112200
X-Cata-Signature: sha256=abc123xyz789...
Body (raw JSON):
{
"uuid": "ord-550e8400-e29b-41d4-a716-446655440000",
"orderRefNo": "ORD-2024-001",
"dailyQueueNo": "A12",
"storeUuid": "store-uuid-123",
"storeName": "Golden Dragon - Downtown",
"deliveryMethod": "DELIVERY",
"status": "PAID",
"currency": "AED",
"isPreorder": false,
"items": [
{
"plu": "SKU-KUNG-PAO",
"name": "Kung Pao Chicken",
"quantity": 1,
"itemOnlyPrice": 42.00,
"modifierOnlyPrice": 3.00,
"itemPrice": 45.00,
"itemSubTotal": 45.00,
"modifiers": [
{
"modifierHeaderId": "mh-spice",
"modifierOptionId": "mo-spice-medium",
"modifierHeaderName": "Spice Level",
"modifierOptionName": "Medium",
"price": 0.00,
"quantity": 1
},
{
"modifierHeaderId": "mh-sauce",
"modifierOptionId": "mo-sauce-extra",
"modifierHeaderName": "Extra Sauce",
"modifierOptionName": "Extra",
"price": 3.00,
"quantity": 1
}
]
},
{
"plu": "SKU-FRIED-RICE",
"name": "Fried Rice",
"quantity": 2,
"itemOnlyPrice": 18.00,
"modifierOnlyPrice": 0.00,
"itemPrice": 18.00,
"itemSubTotal": 36.00,
"modifiers": []
}
],
"subtotal": 81.00,
"discountTotal": 5.00,
"serviceCharge": 0.00,
"deliveryFee": 15.00,
"totalPay": 91.00,
"payment": {
"amount": 91.00,
"tip": 0.00,
"method": "CARD"
},
"customer": {
"uuid": "cust-550e8400",
"name": "Ahmed Al Mansouri",
"email": "ahmed@example.com",
"phone": "+971501234567"
},
"delivery": {
"address": "123 Sheikh Zayed Road, Dubai, UAE",
"notes": "Call on arrival, building entrance on left"
},
"createdAt": "2024-09-01T14:30:00Z"
}
Appendix B: Webhook Registration Example¶
Request:
curl -X POST "https://golden-dragon.sgp1.samba-technologies.xyz/service/pos-integration/api/v1/webhooks/register" \
-H "X-Api-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"outletId": "store-uuid-123",
"provider": "your-pos-system",
"callbackUrl": "https://api.your-pos.example.com/webhooks/cata/orders",
"events": ["order.paid"]
}'
Response (201):
{
"code": 201,
"isSuccess": true,
"message": "webhook registered",
"webhook": {
"id": 42,
"outletId": "store-uuid-123",
"provider": "your-pos-system",
"callbackUrl": "https://api.your-pos.example.com/webhooks/cata/orders",
"events": ["order.paid"],
"secret": "whsec_0123456789abcdef",
"isActive": true,
"createdAt": "2024-09-01T10:00:00Z"
}
}
Last updated: September 1, 2024
Version: 1.0.0