> For the complete documentation index, see [llms.txt](https://docs.ochats.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ochats.io/module-tutorial/settings/api-docs.md).

# API Docs

**Authentication**

All requests require a Bearer token in the `Authorization` header. Generate tokens on the [API Tokens](https://www.app.ochats.io/api-tokens) page.

```
Authorization: Bearer YOUR_API_TOKEN
```

**Base URL**

```
https://www.app.ochats.io/api/v1
```

**Content Type**

```
Content-Type: application/json
```

**Rate Limit**

```
60 requests / minute / token
```

**Response Envelope**

Success (2xx)

```
{ "success": true, "data": { ... }, "message": "..." }
```

Error (4xx / 5xx)

```
{ "success": false, "message": "Error description." }
```

**Contacts**

GET`/contacts/search:` Search contacts

POST`/contacts:` Create a contact

PUT`/contacts/{id}:` Update a contact

POST`/contacts/{id}/tags:` Add tags to a contact

GET`/contacts/{id}/channels:` Get contact channels

**Messages**

{% hint style="info" %}
**Channel Provider IDs:**&#x20;

1=WhatsApp Gupshup, 5=Facebook, 6=Instagram, 7=Telegram, 8=LINE, 11=Email, 12=WhatsApp Cloud API, 14=WeChat.&#x20;

Use `GET /contacts/{id}/channels` to discover which channels a contact has.
{% endhint %}

POST`/messages:` Send a text message

POST`/messages/template:` Send a template message

POST`/messages/attachment:` Send an attachment

POST`/messages/quick-replies:` Send quick replies

GET`/messages/{id}:` Get a message

**Webhooks**

Manage webhook subscriptions via API or from the [Webhooks UI](https://www.app.ochats.io/webhooks). Each subscription listens for one **trigger\_type**.

GET`/webhooks:` List webhook subscriptions

POST`/webhooks:` Create a webhook subscription

GET`/webhooks/{id}:` Get a webhook subscription

PUT`/webhooks/{id}:` Update a webhook subscription

DELETE`/webhooks/{id}:` Delete a webhook subscription

GET`/webhooks/{id}/logs:` Get delivery logs

POST`/webhooks/{id}/test:` Send a test event

**Custom Fields & Profiles**

GET`/custom-fields:` List custom fields

PUT`/profiles/{id}:` Update a profile

**Webhook Events & Payloads**

When an event occurs, oChats sends a `POST` request to your URL with a JSON body. Every payload includes `event`, `workspace_id`, and `timestamp`. Click an event to see its full example payload.

`contact.created:` A new contact was created in the workspace

`contact.updated:` Contact details were modified

`conversation.opened:` A conversation was opened or re-opened

`conversation.closed:` A conversation was marked as closed

`contact.tag_updated:` A tag was applied to a contact

`contact.assignee_updated:` Contact was assigned to a different agent

`message.incoming:` A new message was received from a contact

`message.outgoing:` A message was sent to a contact

`whisper.created:` An internal note (whisper) was added to the conversation

**Signature Verification**

When a subscription has a **secret**, every delivery includes the header:

```
X-OChats-Signature-256: sha256=<hmac-sha256-hex>
```

The HMAC is computed over the raw request body using your secret as the key.

**PHP**

```
$payload   = file_get_contents('php://input');
$header    = $_SERVER['HTTP_X_OCHATS_SIGNATURE_256'] ?? '';
$signature = ltrim($header, 'sha256=');
$expected  = hash_hmac('sha256', $payload, $your_secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}
```

**Node.js**

```
const crypto = require('crypto');

function verifyWebhook(rawBody, header, secret) {
  const signature = header.replace('sha256=', '');
  const expected  = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
```

**Error Reference**

| Status | Meaning                                            | Example                                                       |
| ------ | -------------------------------------------------- | ------------------------------------------------------------- |
| `401`  | Invalid or missing API token                       | `{"message": "Unauthenticated."}`                             |
| `403`  | Token lacks access to this workspace               | `{"success": false, "message": "Forbidden"}`                  |
| `404`  | Resource not found or belongs to another workspace | `{"success": false, "message": "No Data Found."}`             |
| `422`  | Validation error — missing or invalid parameters   | `{"message": "The name field is required.", "errors": {...}}` |
| `429`  | Rate limit exceeded (60 requests / minute)         | `{"message": "Too Many Attempts."}`                           |
| `500`  | Unexpected server error                            | `{"success": false, "message": "Something Went Wrong."}`      |
