API documentation
Connect IntegraWhats to your ERP, CRM, store or in-house system. The API is REST, speaks JSON, and webhooks tell your system when something happens.
The API and webhooks are available from the Pro plan up.
Quick start
- In Settings › Developers, create a token and tick the abilities you need. The token is shown only once.
- Make your first call to check the token's company and plan.
- Send a test message to a number of your own.
curl https://integrawhats.app/api/v1/me \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
curl -X POST https://integrawhats.app/api/v1/messages \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"to":"5511999990000","text":"Olá, Maria. Seu pedido saiu para entrega."}'
Authentication
Each token belongs to one company and only reaches that company's data. Send it in the Authorization header using the Bearer format. Keep it on your server, never in code that runs in the browser. You can revoke a token in the panel and it stops working immediately.
Authorization: Bearer iw_<prefix>_<secret>
Token abilities
read- Read conversations, contacts, scheduling, leads and tickets.
write- Create and change appointments and tickets, and resolve conversations.
messages- Send WhatsApp messages.
orders- Read, create and update orders.
Conventions
- Base URL
- All routes start with the address below. Send Accept: application/json on every call.
- Identifiers
- Ids are stable public strings. For orders, the path also accepts your store's order number (external_id).
- Phone numbers
- Digits only, with the country code. A Brazilian number with 10 or 11 digits gets the 55 added automatically.
- Dates
- Responses use ISO 8601 with a time zone. In scheduling, a date sent without a time zone is read in the company's time zone.
- Amounts
- Always in cents, as an integer: R$ 159.00 is 15900.
- Pagination
- Lists run from newest to oldest, in pages of 50 items (100 for messages and contacts). For the next page, send the next_cursor value in the cursor parameter. When next_cursor is null, the list is over.
- Rate limit
- 120 requests per minute per token. Above that the response is 429, with retry_after in seconds.
- Retrying without duplicates
- On the marked routes, send an Idempotency-Key header of up to 100 characters. For 24 hours, repeating the same key with the same body returns the first response, with the Idempotent-Replayed: true header, and creates nothing new. Only successful responses are stored: after a validation error, fix it and resend with the same key.
https://integrawhats.app/api/v1
Errors
Authentication, permission and business rule errors carry an error field with a stable code and a message for people. Validation errors carry message and errors, listed by field.
| HTTP | Code | When it happens |
|---|---|---|
| 401 | unauthenticated | Token missing, invalid or revoked. |
| 403 | forbidden | The company has no access, the plan does not include the API, or the token lacks the route's ability. |
| 404 | The resource does not exist in this company. | |
| 404 | not_found | The route's app is not installed. |
| 409 | channel_disconnected | The number used in the conversation is disconnected. |
| 409 | idempotency_in_progress | Another request with the same Idempotency-Key is still running. |
| 409 | not_upcoming | Only upcoming appointments can be rescheduled. |
| 413 | payload_too_large | The order is larger than 256 KB. |
| 422 | Validation: check the errors object. | |
| 422 | slot_unavailable | The requested time is not free. |
| 422 | invalid_idempotency_key | The Idempotency-Key is longer than 100 characters. |
| 422 | idempotency_conflict | The key was already used with a different request body. |
| 429 | rate_limited | Rate limit reached. Wait for the seconds in retry_after. |
Account
The token's company, plan and limit usage.
GET
/me
Returns the token's company, plan and usage of each limit.
Ability: read
Request
curl https://integrawhats.app/api/v1/me \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": {
"workspace": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"name": "Clínica Exemplo",
"locale": "pt_BR",
"timezone": "America/Sao_Paulo"
},
"plan": "pro",
"usage": {
"users": {
"limit": 10,
"usage": 4,
"tracked": true
}
}
}
}
Conversations and messages
Read the inbox and send text messages. Sending is queued: the 202 response confirms receipt, and the final status arrives through the message.status webhook.
GET
/conversations
Lists conversations.
Ability: read
Parameters
| Field | Type | Description |
|---|---|---|
status
|
string | Filters by status. open, resolved |
department
|
string | Filters by department id. |
phone
|
string | Filters by the contact's phone. |
Request
curl https://integrawhats.app/api/v1/conversations \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": [
{
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"status": "open",
"channel": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"department": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"name": "Comercial"
},
"assigned_to": {
"name": "Ana",
"email": "ana@exemplo.com"
},
"tags": [
"orçamento"
],
"opened_at": "2026-11-03T10:15:00-03:00",
"resolved_at": null
}
],
"next_cursor": "eyJpZCI6MTIwLCJfcG9pbnRzVG9OZXh0SXRlbXMiOnRydWV9"
}
GET
/conversations/{conversation}
Returns one conversation.
Ability: read
Request
curl https://integrawhats.app/api/v1/conversations/01JC4Z8N5Q3V7W2K9M6T1R0YHD \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"status": "open",
"channel": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"department": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"name": "Comercial"
},
"assigned_to": {
"name": "Ana",
"email": "ana@exemplo.com"
},
"tags": [
"orçamento"
],
"opened_at": "2026-11-03T10:15:00-03:00",
"resolved_at": null
}
}
GET
/conversations/{conversation}/messages
Lists a conversation's messages, newest first.
Ability: read
Request
curl https://integrawhats.app/api/v1/conversations/01JC4Z8N5Q3V7W2K9M6T1R0YHD/messages \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": [
{
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"conversation": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"direction": "out",
"type": "text",
"body": "Olá, Maria. Seu pedido saiu para entrega.",
"media": null,
"status": "queued",
"risk": null,
"reply_to": null,
"reactions": [],
"edited_at": null,
"revoked_at": null,
"hold_reason": null,
"hold_message": null,
"send_after": null,
"timestamp": null
}
],
"next_cursor": "eyJpZCI6MTIwLCJfcG9pbnRzVG9OZXh0SXRlbXMiOnRydWV9"
}
POST
/conversations/{conversation}/resolve
Marks the conversation as resolved.
Ability: write
Request
curl -X POST https://integrawhats.app/api/v1/conversations/01JC4Z8N5Q3V7W2K9M6T1R0YHD/resolve \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": {
"status": "resolved",
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"channel": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"department": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"name": "Comercial"
},
"assigned_to": {
"name": "Ana",
"email": "ana@exemplo.com"
},
"tags": [
"orçamento"
],
"opened_at": "2026-11-03T10:15:00-03:00",
"resolved_at": null
}
}
POST
/messages
Sends text to a conversation or a phone number. With a phone number, it uses the open conversation or starts a new one. Provide conversation or to. Send protection may hold a cold message: it then comes back with status held and the reason in hold_reason and hold_message.
Ability: messages
Accepts Idempotency-Key
Parameters
| Field | Type | Description |
|---|---|---|
conversation
|
string | Conversation id. Required if to is missing. |
to
|
string | Destination phone. Required if conversation is missing. |
text
required |
string | Message text, up to 4096 characters. |
channel
|
string | Id of the sending number, when the company has more than one. |
department
|
string | Department id. |
origin
|
string | Use system for a notice generated by your system, not a campaign. system |
Request
curl -X POST https://integrawhats.app/api/v1/messages \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"to":"5511999990000","text":"Olá, Maria. Seu pedido saiu para entrega."}'
Response 202
{
"data": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"conversation": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"direction": "out",
"type": "text",
"body": "Olá, Maria. Seu pedido saiu para entrega.",
"media": null,
"status": "queued",
"risk": null,
"reply_to": null,
"reactions": [],
"edited_at": null,
"revoked_at": null,
"hold_reason": null,
"hold_message": null,
"send_after": null,
"timestamp": null
}
}
Contacts
Search the company's contact base. Contacts are created by conversations, appointments and orders.
GET
/contacts
Lists contacts, with search by name or phone.
Ability: read
Parameters
| Field | Type | Description |
|---|---|---|
search
|
string | Part of the name or phone. |
Request
curl https://integrawhats.app/api/v1/contacts \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": [
{
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
}
],
"next_cursor": "eyJpZCI6MTIwLCJfcG9pbnRzVG9OZXh0SXRlbXMiOnRydWV9"
}
Scheduling
Check free times and create, reschedule or cancel appointments, under the same rules as the panel and WhatsApp.
GET
/calendars
Lists the company's calendars.
Ability: read
Request
curl https://integrawhats.app/api/v1/calendars \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": [
{
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"name": "Consultas",
"slot_minutes": 30,
"max_days_ahead": 30,
"active": true
}
]
}
GET
/calendars/{calendar}/slots
Lists a calendar's free times.
Ability: read
Parameters
| Field | Type | Description |
|---|---|---|
date
|
date | First day, as YYYY-MM-DD. |
days
|
integer | Number of days, from 1 to 31. Default: 1. |
Request
curl https://integrawhats.app/api/v1/calendars/01JC4Z8N5Q3V7W2K9M6T1R0YHD/slots \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": [
"2026-11-10T09:00:00-03:00",
"2026-11-10T09:30:00-03:00"
],
"timezone": "America/Sao_Paulo"
}
GET
/appointments
Lists appointments.
Ability: read
Parameters
| Field | Type | Description |
|---|---|---|
calendar
|
string | Filters by calendar id. |
status
|
string | Filters by status. scheduled, confirmed, cancelled, done, no_show |
phone
|
string | Filters by the contact's phone. |
from
|
datetime | Start of the period. |
to
|
datetime | End of the period. |
Request
curl https://integrawhats.app/api/v1/appointments \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": [
{
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"calendar": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"name": "Consultas",
"slot_minutes": 30,
"max_days_ahead": 30,
"active": true
},
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"conversation": null,
"starts_at": "2026-11-10T09:00:00-03:00",
"ends_at": "2026-11-10T09:30:00-03:00",
"status": "scheduled",
"notes": null,
"source": "api",
"created_at": "2026-11-03T10:15:00-03:00"
}
],
"next_cursor": "eyJpZCI6MTIwLCJfcG9pbnRzVG9OZXh0SXRlbXMiOnRydWV9"
}
GET
/appointments/{appointment}
Returns one appointment.
Ability: read
Request
curl https://integrawhats.app/api/v1/appointments/01JC4Z8N5Q3V7W2K9M6T1R0YHD \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"calendar": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"name": "Consultas",
"slot_minutes": 30,
"max_days_ahead": 30,
"active": true
},
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"conversation": null,
"starts_at": "2026-11-10T09:00:00-03:00",
"ends_at": "2026-11-10T09:30:00-03:00",
"status": "scheduled",
"notes": null,
"source": "api",
"created_at": "2026-11-03T10:15:00-03:00"
}
}
POST
/appointments
Books an appointment at a free time. The contact is created if it does not exist yet.
Ability: write
Accepts Idempotency-Key
Parameters
| Field | Type | Description |
|---|---|---|
calendar
required |
string | Calendar id. |
phone
required |
string | Contact's phone. |
starts_at
required |
datetime | Start date and time. |
name
|
string | Contact name, used if the contact is created now. |
notes
|
string | Notes, up to 2000 characters. |
notify
|
boolean | Tells the customer on WhatsApp. Default: true. |
Request
curl -X POST https://integrawhats.app/api/v1/appointments \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"calendar":"01JC4Z8N5Q3V7W2K9M6T1R0YHD","phone":"5511999990000","starts_at":"2026-11-10T09:00:00-03:00","name":"Maria Silva"}'
Response 201
{
"data": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"calendar": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"name": "Consultas",
"slot_minutes": 30,
"max_days_ahead": 30,
"active": true
},
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"conversation": null,
"starts_at": "2026-11-10T09:00:00-03:00",
"ends_at": "2026-11-10T09:30:00-03:00",
"status": "scheduled",
"notes": null,
"source": "api",
"created_at": "2026-11-03T10:15:00-03:00"
}
}
POST
/appointments/{appointment}/reschedule
Moves an upcoming appointment to another free time.
Ability: write
Accepts Idempotency-Key
Parameters
| Field | Type | Description |
|---|---|---|
starts_at
required |
datetime | Start date and time. |
notify
|
boolean | Tells the customer on WhatsApp. Default: true. |
Request
curl -X POST https://integrawhats.app/api/v1/appointments/01JC4Z8N5Q3V7W2K9M6T1R0YHD/reschedule \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"starts_at":"2026-11-11T14:00:00-03:00"}'
Response 200
{
"data": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"calendar": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"name": "Consultas",
"slot_minutes": 30,
"max_days_ahead": 30,
"active": true
},
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"conversation": null,
"starts_at": "2026-11-10T09:00:00-03:00",
"ends_at": "2026-11-10T09:30:00-03:00",
"status": "scheduled",
"notes": null,
"source": "api",
"created_at": "2026-11-03T10:15:00-03:00"
}
}
POST
/appointments/{appointment}/cancel
Cancels an appointment.
Ability: write
Accepts Idempotency-Key
Parameters
| Field | Type | Description |
|---|---|---|
notify
|
boolean | Tells the customer on WhatsApp. Default: true. |
Request
curl -X POST https://integrawhats.app/api/v1/appointments/01JC4Z8N5Q3V7W2K9M6T1R0YHD/cancel \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"notify":false}'
Response 200
{
"data": {
"status": "cancelled",
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"calendar": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"name": "Consultas",
"slot_minutes": 30,
"max_days_ahead": 30,
"active": true
},
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"conversation": null,
"starts_at": "2026-11-10T09:00:00-03:00",
"ends_at": "2026-11-10T09:30:00-03:00",
"notes": null,
"source": "api",
"created_at": "2026-11-03T10:15:00-03:00"
}
}
Site leads
Leads received through forms and the capture pop-up. Read only.
Requires the Forms or Lead capture app.
GET
/leads
Lists site leads.
Ability: read
Parameters
| Field | Type | Description |
|---|---|---|
status
|
string | Filters by status. new, contacted, converted, discarded |
source
|
string | Filters by source. form, popup |
Request
curl https://integrawhats.app/api/v1/leads \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": [
{
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"source": "form",
"status": "new",
"name": "Maria Silva",
"phone": "5511999990000",
"email": "maria@exemplo.com",
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "promo-novembro",
"consent_at": "2026-11-03T10:15:00-03:00",
"confirmed_at": null,
"created_at": "2026-11-03T10:15:00-03:00"
}
],
"next_cursor": "eyJpZCI6MTIwLCJfcG9pbnRzVG9OZXh0SXRlbXMiOnRydWV9"
}
GET
/leads/{lead}
Returns one lead.
Ability: read
Request
curl https://integrawhats.app/api/v1/leads/01JC4Z8N5Q3V7W2K9M6T1R0YHD \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"source": "form",
"status": "new",
"name": "Maria Silva",
"phone": "5511999990000",
"email": "maria@exemplo.com",
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "promo-novembro",
"consent_at": "2026-11-03T10:15:00-03:00",
"confirmed_at": null,
"created_at": "2026-11-03T10:15:00-03:00"
}
}
Orders
Send your store's orders to see the real revenue of each campaign.
Requires the Orders API app.
GET
/orders
Lists orders.
Ability: orders
Parameters
| Field | Type | Description |
|---|---|---|
status
|
string | Filters by status. pending, paid, shipped, delivered, cancelled, refunded |
source
|
string | Filters by source. api, pixel, bio, manual, kori |
phone
|
string | Filters by the contact's phone. |
Request
curl https://integrawhats.app/api/v1/orders \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": [
{
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"external_id": "10231",
"source_key": "",
"source": "api",
"status": "paid",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"customer_name": "Maria Silva",
"customer_phone": "5511999990000",
"customer_email": null,
"currency": "BRL",
"subtotal_cents": 15900,
"shipping_cents": 0,
"discount_cents": 0,
"total_cents": 15900,
"placed_at": "2026-11-03T10:15:00-03:00",
"paid_at": "2026-11-03T10:15:00-03:00",
"cancelled_at": null,
"refunded_at": null,
"confirmed_at": "2026-11-03T10:15:00-03:00",
"attribution": null,
"utm_source": null,
"utm_medium": null,
"utm_campaign": null,
"items": [
{
"sku": "CAFE-250",
"title": "Café especial 250 g",
"quantity": 2,
"unit_price_cents": 7950
}
]
}
],
"next_cursor": "eyJpZCI6MTIwLCJfcG9pbnRzVG9OZXh0SXRlbXMiOnRydWV9"
}
GET
/orders/{order}
Returns one order, by id or by store order number.
Ability: orders
Request
curl https://integrawhats.app/api/v1/orders/01JC4Z8N5Q3V7W2K9M6T1R0YHD \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"external_id": "10231",
"source_key": "",
"source": "api",
"status": "paid",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"customer_name": "Maria Silva",
"customer_phone": "5511999990000",
"customer_email": null,
"currency": "BRL",
"subtotal_cents": 15900,
"shipping_cents": 0,
"discount_cents": 0,
"total_cents": 15900,
"placed_at": "2026-11-03T10:15:00-03:00",
"paid_at": "2026-11-03T10:15:00-03:00",
"cancelled_at": null,
"refunded_at": null,
"confirmed_at": "2026-11-03T10:15:00-03:00",
"attribution": null,
"utm_source": null,
"utm_medium": null,
"utm_campaign": null,
"items": [
{
"sku": "CAFE-250",
"title": "Café especial 250 g",
"quantity": 2,
"unit_price_cents": 7950
}
]
}
}
POST
/orders
Creates the order or updates the one with the same external_id. The response is 201 on create and 200 on update. The applied field says whether the status sent was accepted.
Ability: orders
Accepts Idempotency-Key
Parameters
| Field | Type | Description |
|---|---|---|
external_id
required |
string | Your store's order number, up to 80 characters. |
source_key
|
string | Identifies the store when you have more than one. |
status
|
string | Order status. pending, paid, shipped, delivered, cancelled, refunded |
status_at
|
datetime | When the status changed. |
currency
|
string | 3-letter currency code. Example: BRL. |
subtotal_cents
|
integer | Amount in cents. |
shipping_cents
|
integer | Amount in cents. |
discount_cents
|
integer | Amount in cents. |
total_cents
|
integer | Amount in cents. |
customer_name
|
string | Buyer's name. |
customer_phone
|
string | Buyer's phone. Links the order to the contact. |
customer_email
|
string | Buyer's email. |
placed_at
|
datetime | Order date. |
pixel
|
string | Code of the pixel that attributes the order. |
visitor_id
|
string | Visitor id provided by the pixel. |
gxclid
|
string | Tracked click id. |
items
|
array | Up to 100 items, each with title, quantity and unit_price_cents, and an optional sku. |
Request
curl -X POST https://integrawhats.app/api/v1/orders \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"external_id":"10231","status":"paid","total_cents":15900,"customer_name":"Maria Silva","customer_phone":"5511999990000","items":[{"sku":"CAFE-250","title":"Café especial 250 g","quantity":2,"unit_price_cents":7950}]}'
Response 201
{
"data": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"external_id": "10231",
"source_key": "",
"source": "api",
"status": "paid",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"customer_name": "Maria Silva",
"customer_phone": "5511999990000",
"customer_email": null,
"currency": "BRL",
"subtotal_cents": 15900,
"shipping_cents": 0,
"discount_cents": 0,
"total_cents": 15900,
"placed_at": "2026-11-03T10:15:00-03:00",
"paid_at": "2026-11-03T10:15:00-03:00",
"cancelled_at": null,
"refunded_at": null,
"confirmed_at": "2026-11-03T10:15:00-03:00",
"attribution": null,
"utm_source": null,
"utm_medium": null,
"utm_campaign": null,
"items": [
{
"sku": "CAFE-250",
"title": "Café especial 250 g",
"quantity": 2,
"unit_price_cents": 7950
}
]
},
"applied": true
}
POST
/orders/{order}/status
Changes the order status. Status only moves forward, and applied comes back false when the change is not allowed.
Ability: orders
Accepts Idempotency-Key
Parameters
| Field | Type | Description |
|---|---|---|
status
required |
string | Order status. pending, paid, shipped, delivered, cancelled, refunded |
at
|
datetime | When the change happened. |
Request
curl -X POST https://integrawhats.app/api/v1/orders/01JC4Z8N5Q3V7W2K9M6T1R0YHD/status \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"status":"shipped"}'
Response 200
{
"data": {
"status": "shipped",
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"external_id": "10231",
"source_key": "",
"source": "api",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"customer_name": "Maria Silva",
"customer_phone": "5511999990000",
"customer_email": null,
"currency": "BRL",
"subtotal_cents": 15900,
"shipping_cents": 0,
"discount_cents": 0,
"total_cents": 15900,
"placed_at": "2026-11-03T10:15:00-03:00",
"paid_at": "2026-11-03T10:15:00-03:00",
"cancelled_at": null,
"refunded_at": null,
"confirmed_at": "2026-11-03T10:15:00-03:00",
"attribution": null,
"utm_source": null,
"utm_medium": null,
"utm_campaign": null,
"items": [
{
"sku": "CAFE-250",
"title": "Café especial 250 g",
"quantity": 2,
"unit_price_cents": 7950
}
]
},
"applied": true
}
Tickets
Open and follow tickets from your own system.
Requires the Tickets app.
GET
/tickets
Lists tickets.
Ability: read
Parameters
| Field | Type | Description |
|---|---|---|
status
|
string | Filters by status. new, in_progress, waiting_customer, waiting_third_party, resolved, closed |
priority
|
string | Filters by priority. low, normal, high, urgent |
phone
|
string | Filters by the contact's phone. |
Request
curl https://integrawhats.app/api/v1/tickets \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": [
{
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"number": 128,
"subject": "Produto chegou com defeito",
"description": null,
"status": "new",
"priority": "high",
"source": "api",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"channel": null,
"category": null,
"department": null,
"assigned_to": null,
"first_response_due_at": "2026-11-03T14:15:00-03:00",
"resolve_due_at": "2026-11-04T10:15:00-03:00",
"first_response_at": null,
"customer_replied_at": null,
"resolved_at": null,
"closed_at": null,
"reopen_count": 0,
"created_at": "2026-11-03T10:15:00-03:00"
}
],
"next_cursor": "eyJpZCI6MTIwLCJfcG9pbnRzVG9OZXh0SXRlbXMiOnRydWV9"
}
GET
/tickets/{ticket}
Returns one ticket.
Ability: read
Request
curl https://integrawhats.app/api/v1/tickets/01JC4Z8N5Q3V7W2K9M6T1R0YHD \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json"
Response 200
{
"data": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"number": 128,
"subject": "Produto chegou com defeito",
"description": null,
"status": "new",
"priority": "high",
"source": "api",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"channel": null,
"category": null,
"department": null,
"assigned_to": null,
"first_response_due_at": "2026-11-03T14:15:00-03:00",
"resolve_due_at": "2026-11-04T10:15:00-03:00",
"first_response_at": null,
"customer_replied_at": null,
"resolved_at": null,
"closed_at": null,
"reopen_count": 0,
"created_at": "2026-11-03T10:15:00-03:00"
}
}
POST
/tickets
Opens a ticket.
Ability: write
Accepts Idempotency-Key
Parameters
| Field | Type | Description |
|---|---|---|
subject
required |
string | Subject, up to 200 characters. |
description
|
string | Description, up to 8000 characters. |
priority
|
string | Priority. low, normal, high, urgent |
contact
|
string | Contact id. |
phone
|
string | Phone of an existing contact. |
conversation
|
string | Id of the conversation linked to the ticket. |
category
|
string | Name of a ticket category. |
department
|
string | Department id. |
Request
curl -X POST https://integrawhats.app/api/v1/tickets \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"subject":"Produto chegou com defeito","phone":"5511999990000","priority":"high"}'
Response 201
{
"data": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"number": 128,
"subject": "Produto chegou com defeito",
"description": null,
"status": "new",
"priority": "high",
"source": "api",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"channel": null,
"category": null,
"department": null,
"assigned_to": null,
"first_response_due_at": "2026-11-03T14:15:00-03:00",
"resolve_due_at": "2026-11-04T10:15:00-03:00",
"first_response_at": null,
"customer_replied_at": null,
"resolved_at": null,
"closed_at": null,
"reopen_count": 0,
"created_at": "2026-11-03T10:15:00-03:00"
}
}
POST
/tickets/{ticket}/status
Changes the ticket status.
Ability: write
Accepts Idempotency-Key
Parameters
| Field | Type | Description |
|---|---|---|
status
required |
string | Ticket status. new, in_progress, waiting_customer, waiting_third_party, resolved, closed |
Request
curl -X POST https://integrawhats.app/api/v1/tickets/01JC4Z8N5Q3V7W2K9M6T1R0YHD/status \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"status":"in_progress"}'
Response 200
{
"data": {
"status": "in_progress",
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"number": 128,
"subject": "Produto chegou com defeito",
"description": null,
"priority": "high",
"source": "api",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"channel": null,
"category": null,
"department": null,
"assigned_to": null,
"first_response_due_at": "2026-11-03T14:15:00-03:00",
"resolve_due_at": "2026-11-04T10:15:00-03:00",
"first_response_at": null,
"customer_replied_at": null,
"resolved_at": null,
"closed_at": null,
"reopen_count": 0,
"created_at": "2026-11-03T10:15:00-03:00"
}
}
POST
/tickets/{ticket}/notes
Adds an internal note to the ticket.
Ability: write
Accepts Idempotency-Key
Parameters
| Field | Type | Description |
|---|---|---|
body
required |
string | Note text, up to 4000 characters. |
Request
curl -X POST https://integrawhats.app/api/v1/tickets/01JC4Z8N5Q3V7W2K9M6T1R0YHD/notes \
-H "Authorization: Bearer $INTEGRA_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"body":"Cliente enviou as fotos pelo WhatsApp."}'
Response 201
{
"data": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"number": 128,
"subject": "Produto chegou com defeito",
"description": null,
"status": "new",
"priority": "high",
"source": "api",
"contact": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"phone": "5511999990000",
"name": "Maria Silva",
"push_name": "Maria",
"created_at": "2026-11-03T10:15:00-03:00"
},
"channel": null,
"category": null,
"department": null,
"assigned_to": null,
"first_response_due_at": "2026-11-03T14:15:00-03:00",
"resolve_due_at": "2026-11-04T10:15:00-03:00",
"first_response_at": null,
"customer_replied_at": null,
"resolved_at": null,
"closed_at": null,
"reopen_count": 0,
"created_at": "2026-11-03T10:15:00-03:00"
}
}
Webhooks
Register up to 10 public HTTPS addresses in Settings › Developers and pick the events. For each event, we send a JSON POST to the address.
Delivery body
The data object carries the event's resource, in the same format as the API, and properties carries details of the change. Use the delivery id to ignore repeats.
{
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"event": "message.received",
"created_at": "2026-11-03T10:15:00-03:00",
"data": {
"message": {
"id": "01JC4Z8N5Q3V7W2K9M6T1R0YHD",
"direction": "in",
"type": "text",
"body": "Olá!"
},
"properties": []
}
}
Headers
X-Integra-Event- Event name.
X-Integra-Delivery- Delivery id. It stays the same across retries.
X-Integra-Signature- Signature in the t=<unix>,v1=<hex> format.
Verifying the signature
Compute the HMAC-SHA256 of "<t>.<body>", using the webhook secret and the body exactly as received, and compare it with v1. The secret starts with whsec_ and is shown only once. Also reject a t that is too old.
PHP
$body = file_get_contents('php://input');
parse_str(strtr($_SERVER['HTTP_X_INTEGRA_SIGNATURE'], ',', '&'), $sig);
$expected = hash_hmac('sha256', $sig['t'].'.'.$body, $secret);
if (! hash_equals($expected, $sig['v1']) || time() - (int) $sig['t'] > 300) {
http_response_code(400);
exit;
}
Node.js
import crypto from 'node:crypto';
function isValid(header, rawBody, secret) {
const sig = Object.fromEntries(header.split(',').map((p) => p.split('=')));
const expected = crypto.createHmac('sha256', secret).update(`${sig.t}.${rawBody}`).digest('hex');
const fresh = Date.now() / 1000 - Number(sig.t) < 300;
return fresh && expected.length === sig.v1.length
&& crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig.v1));
}
Delivery and retries
Reply with a 2xx status within 10 seconds. If it fails, we retry after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 24 hours. Redirects are not followed. After 50 lost deliveries in a row, the address is turned off and can be reactivated in the panel.
Events
Ticket, order and deal events only appear when the app is installed. For sensitive forms, the event says a submission arrived and does not carry its content.
- Messages
- message.received, message.sent, message.status
- Conversations
- conversation.opened, conversation.assigned, conversation.resolved
- Contacts
- contact.created, contact.updated, contact.stage_changed
- Leads
- lead.created
- Forms
- form.submitted
- Pixel
- pixel.event
- Orders
- order.created, order.status_changed, order.paid
- Deals
- deal.created, deal.stage_changed, deal.won, deal.lost
- Numbers
- channel.status
- Scheduling
- appointment.created, appointment.rescheduled, appointment.cancelled
- Tickets
- ticket.created, ticket.assigned, ticket.status_changed, ticket.resolved, ticket.sla_breached
Need help with the integration?
Tell us what you want to connect and we reply within one business day.
Talk to the team