Skip to content

Onboarding a New POS — Framework & Playbook

This is the step-by-step companion to ADR 0005. It defines what we ask the integrator, in what order we build, and when we're done when connecting a new POS to Cata's Standard API.

It is written to be driven by an AI agent in a conversation: the agent asks the questions below, you paste an API-docs URL and sample payloads, and the agent produces the adapter scripts. Nothing here requires a Go code change — see ADR 0001.

The five required topics

Every integration must implement these, in this dependency order:

Order Topic Direction Output contract
1 test_connection Cata → POS contract
2 list_remote_outlets Cata → POS contract
3 sync_products POS → Cata contract
4 order_dispatch Cata → POS contract
5 order_status_update POS → Cata contract

Optional, provider-dependent: sync_outlet, snooze_items. Add them only if the POS and the business case need them.

The gate. We do not generate a topic's script until we have (a) the endpoint(s) it calls and (b) a real sample payload for it. Sample payloads win over vendor prose when they disagree.


Part A — Intake questionnaire (what the agent asks)

Answer as much as you can up front; the agent will ask follow-ups via the generation pipeline's needs_clarification step (central.adapter_generation_jobs) when it hits a gap.

A1. Provider basics

  1. Provider display name and proposed slug (lowercase, e.g. iseller).
  2. Vendor API documentation URL(s). Is it public, or behind partner/login auth?
  3. Do we have sandbox/test credentials? A production account?
  4. Is there a GitHub repo (ours or theirs) of API docs/samples we should register as a knowledge_bases entry?

A2. Authentication

  1. Auth model: api_key · oauth · webhook_only · other?
  2. Exact header(s) / format. (e.g. Revel: API-AUTHENTICATION: {key}:{secret}.)
  3. For OAuth: token + refresh flow, scopes, token lifetime, where the refresh token lives.
  4. Where do credentials live?
  5. Tenant-wide creds (key/secret/base URL) → provider_connections (apiKey, apiSecret, baseUrl, config).
  6. Per-outlet config (location id, dining-option ids, etc.) → outlet_providers.settings.
  7. Remember: secrets are never exposed to the JS sandbox; HMAC/credential material is resolved in Go (ADR 0003).

A3. Connectivity

  1. Base URL — global, or per-tenant (e.g. https://{account}.vendor.com)?
  2. Environments (sandbox vs prod base URLs).
  3. Rate limits (requests/min, burst, 429 behaviour).
  4. Pagination style — offset/limit, cursor, meta.next, DRF next? (The runtime's context.http.getAll handles Revel-style meta.next and DRF-style body.next; anything else needs a manual loop.)
  5. Error envelope — does the API return non-2xx on error, or HTTP 200 with an error body (e.g. {"status":"ERROR", ...})? Give an example.

A4. Data formats

  1. Price units — integer cents or decimal? (Cata uses decimal; the script converts.)
  2. ID types — integers (need String(id)) or already strings?
  3. Timestamps — UTC or local? Format? Timezone source?
  4. Currency — fixed per outlet, or on the payload?

A5. Per-topic — endpoints + a sample for each

For each required topic, provide the endpoint(s) and a representative sample payload (real response/request, redacted as needed):

  • test_connection — the cheapest read-only call that proves the credentials work (e.g. "list locations", "get account"). Sample 200 body.
  • list_remote_outlets — the locations/outlets endpoint. Sample response. What field is the stable location id?
  • sync_products — catalog endpoint(s): products, modifier groups, modifier options. Sample payloads. How are bundles/combos modelled? What is the SKU/ item-code field? (Cata product sync is flat — no menu tree/categories.)
  • order_dispatch — the create-order endpoint, full request schema, a sample request and a sample success response, plus a sample error. Which outlet_providers.settings fields does it need (location id, payment type, dining options, …)? How is the external order id returned so we can reconcile?
  • order_status_update — the webhook surface: which events fire, the signature scheme (e.g. HMAC-SHA256 over the raw body + which header), and a sample webhook body per event. Map each POS status to a Cata status (ACCEPTED / IN PROGRESS / READY / DRIVER PICKED UP / COMPLETED / CANCELLED). Are there non-Cata events we must skip (e.g. in-store orders)?

A6. Optional topics & reconciliation

  1. sync_outlet — needed? endpoint + sample.
  2. snooze_items — does the POS support disabling products/modifier options? Endpoint(s)?
  3. Idempotency — does replaying a create-order dedupe, or must we track the external id ourselves?

Part B — Step-by-step build

Step 0 — Scope

Confirm which of the five required topics apply (all, normally) and whether any optional topic is in scope. Record it at the top of the provider's knowledge pack.

Step 1 — Run intake

Work through Part A. Stop and collect missing samples before proceeding — the gate applies per topic, not per provider, so you can start test_connection while still gathering the order_dispatch sample.

Step 2 — Register provider + draft the knowledge pack

  • Add a central.providers row (slug, display_name, auth_type, status) — seeded via the dashboard-app, not hand-edited in prod.
  • Register a central.knowledge_bases row if there's a docs repo.
  • Create docs/guides/adapters/<slug>.md from the knowledge-pack template and fill in everything you learned in intake.

Step 3 — Generate scripts, in dependency order

Generate test_connectionlist_remote_outletssync_productsorder_dispatchorder_status_update. For each:

  • Run it through the generation pipeline (AdapterGenerateServicecentral.adapter_generation_jobs). The job moves through gathering → generating → testing; if it lacks a fact it parks at needs_clarification with a question — answer it (human_response) rather than letting it guess.
  • The result is a candidate in central.adapter_scripts; runtime source is committed to scripts/adapters/<slug>/<topic>.js with the standard JSDoc header (@provider, @topic, @version).
  • Every script reads only the fields it needs and matches the topic's input/output shape in adapter-script-contracts.md.

Step 4 — Test each candidate

  • Validate output shape against the contract using the topic's sample payload.
  • For read topics, deploy and exercise via API (see adapter-scripts-dev-guide.md): POST /api/v1/provider-connections/<slug>/test, GET …/remote-outlets, POST /api/v1/products/sync.
  • Test against the real POS using a sandbox tenant's provider_connections.
  • Respect the budgets (30s order_dispatch, 10min sync_products); use getAll/getBatch, not naive sequential loops.

Step 5 — Review & activate

A human reviews the candidate and promotes candidate → active (which deprecates the prior active). This review is mandatory — see ADR 0005.

Step 6 — Document & wire up

  • Backfill the knowledge pack: final field maps, quirks, sample request/response.
  • Add a changelog entry in the pack.
  • Update the feature-parity note (which topics/features the provider supports vs N/A).
  • Add the provider to mkdocs.yml nav under POS Adapter Scripts → Providers.

Part C — Definition of Done

A new POS is "onboarded" when:

  • [ ] central.providers row exists; knowledge base registered (if any).
  • [ ] docs/guides/adapters/<slug>.md is complete (no [TBC] left for in-scope topics).
  • [ ] All five required scripts are active in central.adapter_scripts and committed under scripts/adapters/<slug>/.
  • [ ] Each script validated against a real sample payload and the topic contract.
  • [ ] order_dispatch verified end-to-end against the sandbox POS; the external order id is captured for reconciliation.
  • [ ] order_status_update maps every relevant POS status to a Cata status and skips non-Cata events.
  • [ ] Feature-parity + changelog updated; provider added to mkdocs nav.
  • [ ] Human review recorded (reviewed_by) on every activated script.

Part D — Knowledge-pack template

Every docs/guides/adapters/<slug>.md uses these headings (this is the curated, reviewed reference; adapters/revel.md is the worked example). Per-topic output shapes are not restated here — link to adapter-script-contracts.md.

# <Provider> — Adapter Guide

## Provider Info        (slug, auth type, base URL, API docs link, scope of topics)
## Authentication       (header format, input fields used, where creds live)
## API Endpoints        (table: endpoint | method | used for | pagination)
## Pagination           (style + helper pattern)
## Rate Limits          (limits + 429 behaviour)
## Quirks & Constraints (price units, ID types, timestamps, bundles, fees, …)
## Feature Parity       (which topics/features supported vs N/A)

## Topic: test_connection       (API call, script, sample 200 body)
## Topic: list_remote_outlets    (API call, script, expected output)
## Topic: sync_products          (API calls, field mapping, sample in/out, bundles)
## Topic: order_dispatch         (endpoint, required settings, body shape, field map,
                                  response/error handling)
## Topic: order_status_update    (webhook surface, signature, status mapping, skip rules)
## Topic: sync_outlet            (optional)
## Topic: snooze_items           (optional)

## Changelog            (newest-first: version, what changed, what was tested)
## Open uncertainties   (things still to confirm against the sandbox)