WhatsApp + Instagram
REST API, v1.
Bearer auth. Cursor pagination. Idempotency keys. Webhooks assinados. A API que seu time teria construído se tivesse o fim de semana.
Escolha o runtime
const API_BASE = process.env.IR_API_URL ?? 'https://api.instantreply.co';
const headers = { 'Authorization': `Bearer ${process.env.IR_API_KEY}` };
const res = await fetch(`${API_BASE}/v1/conversations?status=active`, { headers });
const { data } = await res.json();
for (const c of data) {
if (c.last_message_preview?.includes('refund')) {
await fetch(`${API_BASE}/v1/conversations/${c.id}`, {
method: 'PATCH', headers: { ...headers, 'Content-Type': 'application/json' },
body: JSON.stringify({ tags: ['priority:refund'] }),
});
}
}Superfície v1
Rotas principais, um header de auth.
- GET
/v1/conversations - GET
/v1/conversations/:id - PATCH
/v1/conversations/:id - GET
/v1/conversations/:id/messages - POST
/v1/conversations/:id/messages - GET
/v1/messages - POST
/v1/messages - GET
/v1/messages/:id - GET
/v1/contacts - GET
/v1/contacts/:id - PATCH
/v1/contacts/:id - GET
/v1/channels - GET
/v1/analytics/summary - GET
/v1/usage - GET
/v1/keys - POST
/v1/keys - POST
/v1/keys/:id/rotate - DELETE
/v1/keys/:id - GET
/v1/webhooks - POST
/v1/webhooks - DELETE
/v1/webhooks/:id - GET
/v1/webhooks/:id/deliveries - POST
/v1/webhooks/send - POST
/v1/webhooks/trigger-campaign - POST
/v1/webhooks/sign-payload - GET
/v1/journeys - POST
/v1/trigger - GET
/v1/trigger/status/:id - GET
/v1/trigger/history - POST
/v1/trigger/validate - POST
/v1/trigger/batch - DELETE
/v1/trigger/enrollments - POST
/v1/events - GET
/v1/templates - POST
/v1/templates - GET
/v1/templates/:id - POST
/v1/templates/generate/validate - POST
/v1/templates/:id/validate - POST
/v1/templates/:id/submit - GET
/v1/campaigns - POST
/v1/campaigns - GET
/v1/campaigns/:id - PATCH
/v1/campaigns/:id - POST
/v1/campaigns/:id/send - GET
/v1/pipeline/leads - GET
/v1/pipeline/leads/:id - PATCH
/v1/pipeline/leads/:id - PATCH
/v1/pipeline/leads/:id/stage - GET
/v1/pipeline/stages - GET
/v1/automations - GET
/v1/automations/:id - POST
/v1/automations/:id/trigger - GET
/v1/comments - GET
/v1/comments/:id - POST
/v1/comments/:id/reply - GET
/v1/developer/capabilities - GET
/v1/developer/onboarding - GET
/v1/developer/limits - GET
/v1/developer/troubleshooting/errors/:code
Design
Decisões chatas, de propósito.
- 01
Cursor pagination, sempre
Todo endpoint de lista retorna has_more e next_cursor. Sem registros perdidos sob carga, sem off-by-one.
- 02
Idempotency-Key no POST
Passe um UUID e tente de novo com segurança por 24 horas. Side effects disparam exatamente uma vez.
- 03
X-Request-Id em toda resposta
Cole o ID no suporte e a gente traça a chamada exata, a resposta exata, a chamada downstream exata.
- 04
Erros com forma
Mesmo envelope JSON em toda falha. code, message, doc_url, request_id. Sem null surpresa.
Erros
Um envelope, sempre.
Sem flags de sucesso aninhados. Sem mistura de casing. Sem 200 silencioso na falha. Se a chamada quebrou, o body te diz exatamente qual chamada, o que ela esperava, e onde tão os docs.
// 422 Unprocessable Entity
{
"error": {
"code": "INVALID_PLATFORM",
"message": "Channel 'tiktok' is not yet supported on v1.",
"doc_url": "https://www.instantreply.co/api-docs#errors",
"request_id": "req_8f2a0b1c"
}
}Webhooks
Registre uma vez. Salve o segredo agora.
POST /v1/webhooks com a URL do seu endpoint e os eventos. A resposta retorna um segredo de assinatura whsec_ uma única vez — ele nunca é guardado de forma legível nem exibido de novo. Copie para INSTANTREPLY_WEBHOOK_SECRET. Perdeu? Não há endpoint para revelar: exclua o webhook e registre um novo para um segredo novo.
// POST /v1/webhooks (scope: webhooks:write)
// Request
{
"url": "https://your-app.com/instantreply/webhook",
"events": ["*"],
"description": "Inbound events"
}
// 201 Created — the secret is returned ONCE, here only.
{
"id": "b1e7…",
"url": "https://your-app.com/instantreply/webhook",
"events": ["*"],
"secret": "whsec_9f2c…" // ← store this now; never shown again
}