Skip to content

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

  1. Exact Status String Format
  2. Note the literal spaces in "IN PROGRESS" and "DRIVER PICKED UP"
  3. No underscores, no case-folding
  4. Example: "IN PROGRESS" (not "in_progress" or "inProgress")

  5. Cancellation Requires a Reason

  6. When setting status to CANCELLED, include a reason field:

    {
      "status": "CANCELLED",
      "reason": "Out of stock",
      "timestamp": "2024-12-01T14:45:00Z"
    }
    

  7. Idempotency

  8. Replaying the same status twice is safe
  9. First transition: PAID → ACCEPTED at timestamp T1
  10. Replay ACCEPTED at timestamp T1 or T2: no-op, original T1 timestamp preserved
  11. 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/whoami endpoint successfully
  • [ ] Stored key securely (environment variable, not in code)

  • [ ] Webhook Registration

  • [ ] Called POST /api/v1/webhooks/register once per outlet
  • [ ] Received webhook secret and saved it securely
  • [ ] Webhook callback URL is publicly accessible over HTTPS
  • [ ] Callback URL handles multiple webhooks concurrently
  • [ ] Stored webhookId for future reference (updates, rotation, etc.)

  • [ ] Webhook Receipt & Verification

  • [ ] Callback handler checks X-Cata-Signature before 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 uuid as 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}/status as order progresses
  • [ ] Use exact status strings (ACCEPTED, IN PROGRESS, READY, etc.)
  • [ ] Include timestamp in ISO-8601 format
  • [ ] Respect the state machine — not all transitions are valid
  • [ ] Include reason when status is CANCELLED

  • [ ] Error Handling

  • [ ] Retry webhook reception on non-2xx responses (with backoff)
  • [ ] Handle 401 Unauthorized gracefully (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-ID twice)

6. Troubleshooting

Webhook not received

  1. Check that callbackUrl is publicly accessible (no firewall/NAT blocking)
  2. Test manually: curl -X POST https://your-pos-api/webhooks/cata/orders
  3. Check firewall rules allow inbound HTTPS from Cata's IP ranges
  4. Verify callback handler logs are being written (enable debug logging)

Signature verification fails

  1. Verify you're using the correct secret (not the webhookId)
  2. Verify you're signing the raw body bytes, not the parsed JSON
  3. Verify the header name is exactly X-Cata-Signature
  4. Verify you're using HMAC-SHA256 (not SHA256, HMAC-MD5, etc.)
  5. Test with the example payloads in the troubleshooting section (below)

Status updates are rejected (400/409)

  1. Verify the status string matches exactly (spaces, case, etc.)
  2. Verify the current order status allows the transition
  3. Verify you're using the uuid from the webhook, not orderRefNo

API key keeps returning 401

  1. Verify the key hasn't expired (check expiresAt from /auth/whoami)
  2. Verify the subdomain matches the tenant (e.g., golden-dragon.sgp1...)
  3. Ask Cata to rotate the key if it's old
  4. 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:

  1. Check this guide for common problems (section 6)
  2. Check the API reference at https://dev.docs.cata.sg (or the docs URL for your environment)
  3. Contact Cata: integration-support@cata.sg
  4. 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