# Channel Integrations Per-location credentials for outbound channels (WhatsApp, Facebook Messenger, Instagram DM, Google My Business). Credentials are encrypted at rest. The OAuth callback endpoint that exchanges authorization codes for tokens is intentionally excluded from public docs (internal redirect target). ## List channel integrations `GET /api/channel-integrations` Lists the channel integrations of this location — WhatsApp, email, SMS — newest first. Filter by location, channel, or status. ### Query parameters - `location_id` (integer) — Scope to a location. - `channel` (string) — Filter by channel. One of `whatsapp`, `messenger`, `instagram`, `gmb`. - `status` (string) — Filter by status (e.g. `active`, `disconnected`, `expired`). - `per_page` (integer) — Rows per page. Default 20, maximum 100. See [Lists, paging and filters](#lists-paging-and-filters). ### Example request ```bash curl --request GET \ --get "https://klozzo.com/api/channel-integrations?location_id=1&channel=whatsapp&status=active&per_page=20" \ --header "Authorization: Bearer {YOUR_API_TOKEN}" \ --header "Content-Type: application/json" \ --header "Accept: application/json" ``` ### Response `200` ```json { "data": [ { "id": null, "location_id": null, "channel": "whatsapp", "status": "connected", "metadata": { "account_id": "acct_g2gh67JMFZ" }, "connected_at": "2026-08-26T02:19:50+00:00", "disconnected_at": null, "expires_at": "2026-08-26T04:19:50+00:00", "created_at": null }, { "id": null, "location_id": null, "channel": "whatsapp", "status": "connected", "metadata": { "account_id": "acct_ElVYf4Z2Vn" }, "connected_at": "2026-08-26T02:19:50+00:00", "disconnected_at": null, "expires_at": "2026-08-26T04:19:50+00:00", "created_at": null } ], "links": { "first": "/?page=1", "last": "/?page=1", "prev": null, "next": null }, "meta": { "current_page": 1, "from": 1, "last_page": 1, "links": [ { "url": null, "label": "« Previous", "page": null, "active": false }, { "url": "/?page=1", "label": "1", "page": 1, "active": true }, { "url": null, "label": "Next »", "page": null, "active": false } ], "path": "/", "per_page": 20, "to": 2, "total": 2 } } ``` ## Connect a channel integration `POST /api/channel-integrations` Stores encrypted credentials and marks the integration `active`. For OAuth flows, prefer letting the user complete the in-product OAuth dance; use this endpoint when you already have tokens (e.g. via your own OAuth client). Only locations you belong to are accepted; omit `location_id` to use your current one. WhatsApp is additionally capped at the account's maximum number of linked numbers (10 by default). ### Body parameters - `channel` (string, required) — One of `whatsapp`, `messenger`, `instagram`, `gmb`. - `location_id` (integer) — A location you are a member of. Defaults to your current location. - `credentials` (object, required) — Provider credentials. Must include `access_token`. - `access_token` (string, required) — Long-lived access token. - `refresh_token` (string) — Optional refresh token. - `metadata` (object) — Provider-specific metadata (e.g. `{ "phone_number_id": "..." }` for WhatsApp). - `expires_in` (integer) — Seconds until access token expires. Used to compute `expires_at`. ### Example request ```bash curl --request POST \ "https://klozzo.com/api/channel-integrations" \ --header "Authorization: Bearer {YOUR_API_TOKEN}" \ --header "Content-Type: application/json" \ --header "Accept: application/json" \ --data "{ \"channel\": \"whatsapp\", \"location_id\": 1, \"credentials\": { \"access_token\": \"architecto\", \"refresh_token\": \"architecto\" }, \"metadata\": [], \"expires_in\": 3600 }" ``` ### Response `200` ```json { "data": { "id": null, "location_id": null, "channel": "whatsapp", "status": "connected", "metadata": { "account_id": "acct_ZmVG5xkxyX" }, "connected_at": "2026-08-26T02:19:50+00:00", "disconnected_at": null, "expires_at": "2026-08-26T04:19:50+00:00", "created_at": null } } ``` ### Response `422` — A channel that does not exist ```json { "message": "Channel no es una opción válida.", "errors": { "channel": [ "Channel no es una opción válida." ] } } ``` ### Response `422` — No credentials ```json { "message": "Falta credentials.access_token.", "errors": { "credentials.access_token": [ "Falta credentials.access_token." ] } } ``` ### Response `422` — A location you do not belong to ```json { "message": "Location id no es válido.", "errors": { "location_id": [ "Location id no es válido." ] } } ``` ## Fetch a channel integration `GET /api/channel-integrations/{channelIntegration_id}` Returns one channel integration by id. Credentials come back in encrypted/redacted form; only metadata and status are usable client-side. ### Path parameters - `channelIntegration_id` (integer, required) — Integration ID. ### Example request ```bash curl --request GET \ --get "https://klozzo.com/api/channel-integrations/4" \ --header "Authorization: Bearer {YOUR_API_TOKEN}" \ --header "Content-Type: application/json" \ --header "Accept: application/json" ``` ### Response `200` ```json { "data": { "id": null, "location_id": null, "channel": "whatsapp", "status": "connected", "metadata": { "account_id": "acct_yB1hXM3BMo" }, "connected_at": "2026-08-26T02:19:50+00:00", "disconnected_at": null, "expires_at": "2026-08-26T04:19:50+00:00", "created_at": null } } ``` ### Response `404` — Does not exist, or belongs to another location ```json { "message": "No query results for model." } ``` ## Disconnect a channel integration `DELETE /api/channel-integrations/{channelIntegration_id}` Marks the integration `disconnected` and clears stored credentials. Existing conversations remain readable; outbound messages on this channel will fail until reconnected. ### Path parameters - `channelIntegration_id` (integer, required) — Integration ID. ### Example request ```bash curl --request DELETE \ "https://klozzo.com/api/channel-integrations/4" \ --header "Authorization: Bearer {YOUR_API_TOKEN}" \ --header "Content-Type: application/json" \ --header "Accept: application/json" ``` ### Response `200` ```json { "message": "Channel integration disconnected." } ``` ## Refresh integration tokens `POST /api/channel-integrations/{channelIntegration_id}/refresh` Exchanges the stored refresh token for a new access token at the provider. Updates `expires_at` and `status`. Returns 502 with the provider's error message when the refresh call fails (typically expired refresh token — the user must re-OAuth in product). ### Path parameters - `channelIntegration_id` (integer, required) — Integration ID. ### Example request ```bash curl --request POST \ "https://klozzo.com/api/channel-integrations/4/refresh" \ --header "Authorization: Bearer {YOUR_API_TOKEN}" \ --header "Content-Type: application/json" \ --header "Accept: application/json" ``` ### Response `200` ```json { "data": { "id": null, "location_id": null, "channel": "whatsapp", "status": "connected", "metadata": { "account_id": "acct_sKkxJlPy6M" }, "connected_at": "2026-08-26T02:19:50+00:00", "disconnected_at": null, "expires_at": "2026-08-26T04:19:50+00:00", "created_at": null } } ``` ### Response `502` — refresh failed ```json { "message": "Refresh token rejected by provider" } ```