Skip to content

Getting Started

Authentication

Partner API calls authenticate with an API key in the X-Api-Key header:

X-Api-Key: your-partner-api-key

Request an API key from Cata

API keys are issued per tenant by the Cata team — they are not self-serve. Contact your Cata account manager (or email support+api@cata.sg) to request a key for your tenant. The key is long-lived; rotate it by asking Cata to issue a new one and revoke the old one.

OAuth 2.0 coming soon

A future release will add OAuth 2.0 with per-operation scopes (e.g. products:read, orders:write, loyalty:*) for partners that need granular access control. API-key auth stays supported as the simple path — no migration required for today's partners.

Dashboard users (Cata-owned UI) authenticate with a JWT Bearer token instead:

Authorization: Bearer your-jwt-token

Required Headers

Header Required Description
X-Api-Key Yes (partners) Partner API key issued by Cata.
Authorization Yes (dashboard) Bearer <jwt> for dashboard users.
X-Store-ID Yes (some endpoints) The outlet/store identifier when the endpoint needs it.

Tenant routing happens via subdomain — no header needed

The tenant is resolved from the request hostname (https://{tenant}.sgp1.samba-technologies.xyz/service/pos-integration/...). Partners do not pass a tenant header — pointing the request at the correct subdomain selects the tenant.

Base URL

Environment URL
Local http://localhost:8080
Development https://api-dev.cataprojects.com
Staging https://api-staging.cataprojects.com
Production https://api.cataprojects.com

Quick smoke test

Two one-liners to confirm your environment is wired correctly before integrating any business endpoint.

1. Health check — no auth

Confirms the service is reachable.

curl -i "$BASE/health"
HTTP/1.1 200 OK
Content-Type: application/json

{ "status": "healthy" }

No headers needed — /health is public.

2. Auth probe — verify your API key

Confirms your key works and the tenant subdomain resolves correctly.

curl -sS "$BASE/api/v1/auth/whoami" -H "X-Api-Key: $KEY" | jq .
{
  "authenticated": true,
  "tenantId": "7090aaaa-ba2e-4129-b7ed-345804f2f016",
  "subdomain": "demo",
  "apiKeyId": 37,
  "expiresAt": "2046-04-21T09:03:11Z",
  "serverTime": "2026-04-23T02:24:50Z"
}

A 401 here means the key is missing, invalid, or expired — re-check the value with Cata before moving on. A 400 invalid tenant means the subdomain didn't map to a known tenant; confirm the $BASE URL.

Error Handling

Overview

At-a-glance reference for the response shapes you'll see in practice. Details follow below.

Case Source HTTP Key field in body
Happy path (earn / use / balance) loyalty 200 isSuccess: true
Insufficient balance loyalty 200 code: 1012, isSuccess: false, message: "insufficient_points"
Missing / non-positive points proxy 400 error.message: "invalid request", error.details: "points must be greater than 0"
Missing customerUuid proxy 400 error.message: "missing required field", error.details: "customerUuid query parameter is required"
Missing API key proxy 401 error.message: "missing api key"
Invalid / expired API key proxy 401 error.message: "invalid api key"
Tenant not configured (loyalty) proxy 503 error.message: "loyalty not configured"
Upstream loyalty failure proxy 502 error.message: "loyalty upstream error"
Upstream loyalty timeout proxy 504 error.message: "loyalty upstream timeout"

Two response envelopes you'll see depending on which layer produced the error.

1. Standard error envelope (most endpoints)

Validation, auth, not-found, and server-side errors return an HTTP 4xx / 5xx with this shape:

{
  "error": {
    "code": 401,
    "message": "invalid api key",
    "details": "the provided X-Api-Key is invalid or expired"
  }
}

code mirrors the HTTP status. Partner-relevant statuses:

HTTP Retry? Meaning
400 No — fix input Validation failed (missing/invalid field).
401 No — re-auth API key missing, invalid, or expired.
404 Depends Referenced resource does not exist.
409 Depends Conflict (e.g. duplicate externalId).
429 Yes, backoff Rate limited (reserved; no limit today).
500 Yes, backoff Server-side error.
502 Yes, backoff Upstream dependency (e.g. loyalty) returned an error.
503 Wait for admin Tenant not fully configured.
504 Yes, backoff Upstream timeout.

2. Proxied-upstream envelope (loyalty endpoints)

HTTP 200 does not always mean success

Proxied endpoints (currently: /api/v1/loyalty/*) forward the upstream service's own response envelope. Business errors come back as HTTP 200 with isSuccess: false and a non-zero code. Always check isSuccess, not just the HTTP status.

Example — redeeming more points than the customer has:

HTTP/1.1 200 OK
{
  "code": 1012,
  "isSuccess": false,
  "message": "insufficient_points"
}

Validation handled at the proxy layer (missing customerUuid, non-positive points, missing refCode) still returns the standard 4xx envelope above — loyalty business rules are the ones that use 200 + isSuccess.

See Loyalty Points API Example for the full happy-path + error walkthrough.

Async Operations

Some operations are long-running and return immediately with a jobId:

{
  "jobId": "job_01HXYZ123ABC",
  "status": "queued",
  "submittedAt": "2026-02-26T10:00:00Z"
}

Poll the status via GET /api/v1/jobs/{jobId} or register a webhook to be notified automatically.

Async endpoints

  • POST /api/v1/orders — Create order
  • POST /api/v1/menu — Submit menu

Next: full API reference

Every partner-callable endpoint, request/response schema, and example lives in the public API portal:

https://apidocs.cata.sg/