Skip to main content

Worked channels samples

The generated blocks below document every parameter and response shape; this overlay walks the chain an Apple Messages for Business integration actually ships: list connected agents → register one → transition its status → remove it, plus the WhatsApp Flow inventory your inbox composer polls. Every authenticated call on this page carries X-API-Key; the two webhook routes (POST .../channels/amb/webhook, POST .../channels/whatsapp/flows/endpoint) are provider-facing and authenticate by signature, not by key — you never call them from your own backend. Every JSON response follows the { data, meta } envelope — data carries the payload, meta carries the request_id and timestamp. Quote meta.request_id when you report a bad payload. The Node SDK does not wrap the channels namespace yet, so the typed tabs below use the SDK’s orbit.request escape hatch (the same convention the API recipes guide uses for uncovered resources) — you get the SDK’s auth, retries, and envelope unwrapping against the raw REST path.

1. List connected AMB agents

GET /api/v1/channels/amb/agents returns the tenant’s Apple Messages for Business agents, newest first (capped at 200). Poll it on your channel-settings screen to render connection state: the status field is the approval lifecycle (pendingapprovedsuspended), and has_secret: true confirms the agent carries a credential. The secret itself is encrypted at rest and never serialised — a rotated secret still reads as has_secret: true with no material exposed.
200
An empty tenant answers {"data": []} — render the connect prompt rather than branching on null. A first-booted tenant whose AMB tables have not finished provisioning also answers [] (a clean 200), so an empty list never means the endpoint is down.

2. Register an AMB agent

POST /api/v1/channels/amb/agents creates the agent. You need the business_id Apple Business Register issued and the base64 secret_key assigned to the agent — the secret is encrypted with the platform envelope before it persists and is never returned by any read. The idempotent answer on a repeated submit is driven by the business_id: it is unique per tenant, so re-POSTing the same one conflicts — see the 409 below.
201
Keep the returned data.id — updates and deletes address the agent by that id, not by business_id. Registration also mirrors the business_id → tenant mapping into the webhook registry, so inbound Apple Messages start routing to your inbox the moment the POST succeeds.

3. Transition status / rotate the secret

PATCH /api/v1/channels/amb/agents/{id} is a partial update — only the fields you send change. The two calls you make in practice: flip status when Apple approves (or when you suspend the channel), and send a new secret_key to rotate credentials (the replacement is encrypted before it persists).
200
A PATCH against an id that does not exist on your tenant is a 404 — re-list (section 1) and re-read the id instead of retrying the same one; the roster is the source of truth after any delete or re-register.

4. Disconnect an agent

DELETE /api/v1/channels/amb/agents/{id} removes the agent and drops its business_id from the webhook registry, so inbound Apple Messages stop routing to your inbox immediately. The response is the deleted id plus a deleted: true marker.
200

5. Inventory WhatsApp Flows

GET /api/v1/channels/whatsapp/flows lists the tenant’s Meta WhatsApp Flows (up to 100, newest first). Your inbox composer polls this to offer a local-flow picker while a completion event is in flight: each row carries the remote Meta flow_id, the lifecycle status (draft / published / deprecated), and first_screen for the launch surface. Flows POST /api/v1/channels/whatsapp/flows/endpoint receives are landings of these same flows — an unknown flow_id in a completion event means the flow was deprecated upstream; re-list here before surfacing an error.
200
A flow_id: null row is a draft that has not been published to Meta yet — filter it out of any picker that launches live flows.

Errors worth branching on

The matrix below is scoped to what a channel-config client actually hits; the platform-wide retry-vs-terminal decision table lives in the error handling guide.

409 — the channel is already connected

A second POST of a business_id your tenant already registered conflicts — business_id is unique per tenant, and the create is not upsert-shaped. The idempotent connect playbook is: POST once, and on 409 PATCH the existing agent (rotate the secret, restate capabilities) instead of re-POSTing.
409

403 — a read-scoped key tried to write

Create, update, and disconnect need a write-capable key (dashboard role owner/admin/developer). A key scoped to read-only gets a 403 — fix the key’s scope set on the developer page; retrying with the same key never heals it.
403

422 — the provider fields did not validate

Body schema violations return VALIDATION_ERROR with error.details naming the field — a business_id Apple rejects, a secret_key shorter than 16 or longer than 2048 base64 chars, a non-enum status, or an agent id path segment that is not a UUID. Branch on error.details and resend with the corrected field; a blind retry repeats the same 422.
422

Retry matrix