## Overview

The **API channel** is a first-class inbox. Any module of the platform reaches it the same way it
reaches WhatsApp or the web widget: it creates a message on a conversation. That message is then
POSTed — signed — to your inbox **webhook URL**. Because every message payload carries the full
`content_type` **and** `content_attributes`, structured content (interactive buttons, payment CTAs,
catalog cards, calendar events and reactions) reaches your integration natively — you render it.

Everything here is **additive and backward-compatible**: existing integrations keep working and can
ignore any field they don't recognize. There are no new mandatory fields.

## Prerequisites

- An API inbox with a configured **webhook URL**.
- The inbox **secret** to verify the webhook signature (and optionally `hmac_token` for inbound HMAC).
- An **access token** for the REST API when you send data back.

## Step by step

1. Create an API inbox and set its webhook URL.
2. Receive events at that URL and verify the signature with the inbox secret.
3. Read `content_type` + `content_attributes` on each message payload to render rich content.
4. Send inbound messages, delivery receipts and reactions back through the REST API.
5. (Optional) Restrict which events you receive with `webhook_subscriptions`.

## Outbound content types (what the webhook delivers)

Each `message_created` / `message_updated` payload includes `content_type`, `content`,
`content_attributes` and `attachments`. Beyond plain `text`, the API inbox may deliver:

- **`input_select`** — interactive options in `content_attributes.items` (`[{title, value}]`). When a
  channel can't render options, the platform also appends a numbered menu to `content`.
- **`content_attributes.payment_interactive`** — a pay action: `{ body, buttons: [{ type: "cta_url",
  text, url } | { type: "cta_copy", text, code }] }`. The full charge (amount, PIX code, boleto,
  links) also arrives as `content_attributes.payment_charge` on the summary message.
- **`content_attributes.catalog_product`** — a product card: `{ mode: "single" | "list", products:
  [{ id, name, price, currency, image_url, ... }] }`.
- **`content_attributes.calendar_event`** — a booking confirmation or reminder: `{ id, title,
  starts_at, ends_at, location, meet_url, kind: "confirmation" | "reminder" }` (ISO-8601 times).
- **`content_attributes.reactions`** — an array of `{ emoji, sender_jid }`. The operator is `me`; a
  contact is stored under its own identifier. Reactions ride the **`message_updated`** event.
- **Templates** — the sent template metadata rides `additional_attributes.template_params`
  (`{ name, language, category, processed_params }`).
- **Media, location, contacts, stickers** — delivered as real `attachments` (plus
  `content_attributes.media_kind` for stickers).

## Inbound (what you send back)

- **Incoming message** — `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/messages`
  with `message_type: "incoming"`. It accepts `content`, `content_type`, `content_attributes` and
  `attachments`, so an interactive reply is symmetric with the outbound contract.
- **Delivery receipts** — `PUT/PATCH .../messages/{id}` (API inboxes only) with `status` of
  `sent` / `delivered` / `read` / `failed` (and an optional `external_error`). This flips the
  message status, which is relayed via `message_updated`.
- **Reactions** — `POST .../messages/{id}/react` with `emoji` (an empty emoji removes it). Pass
  `by=contact` to record the **contact's** reaction (the default records the operator's). No provider
  is contacted for an API inbox — the reaction is persisted and relayed via `message_updated`.

## Campaigns

One-off campaigns can target an API inbox. Each audience contact receives a real conversation and an
outgoing message, which rides your webhook exactly like any other outbound message.

## Settings & options

- **`webhook_subscriptions`** — an optional array on the API channel's `additional_attributes`
  (update the inbox via the API with `channel[additional_attributes][webhook_subscriptions]`). When set, only
  those events are delivered; when absent or empty, **all** events are delivered (the default). Event
  names must be valid platform events (e.g. `message_created`, `message_updated`,
  `conversation_created`, `conversation_status_changed`, `conversation_typing_on`).
- **`hmac_mandatory`** — reject inbound requests that can't be HMAC-verified.

## Use cases

- Bridge the inbox into a custom app that renders payment CTAs, catalog cards and calendar bookings.
- Relay a contact's reaction from your own client back onto the message.
- Mirror booking confirmations and reminders into the customer's channel of record.

## Tips, limits & best practices

- Always verify the webhook signature before acting on a payload.
- Deduplicate by the delivery id / event; expect retries.
- Prefer `content_attributes` for structured rendering; `content` is the plain-text fallback.
- Subscribe only to the events you use to reduce noise.

## Troubleshooting

- **No events arriving**: confirm the webhook URL is set and, if you configured
  `webhook_subscriptions`, that the event you expect is in the list.
- **`422` on subscriptions**: the list contains an unknown event name — remove it.
- **Reaction not attributed to the contact**: pass `by=contact` on the react call.

## See also

- [REST API, tokens and webhooks](/hc/ajuda/articles/api-developers-rest-tokens-webhooks-en)
- [Per-module events](/hc/ajuda/articles/api-developers-eventos-por-modulo-en)
- [API reference (Swagger / OpenAPI)](/hc/ajuda/articles/api-developers-swagger-reference-en)