WhatsApp + Instagram
REST API, v1.
Bearer auth. Cursor pagination. Idempotency keys. Webhooks firmados. La API que tu equipo habría construido si tuviera el fin de semana.
Elige el 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'] }),
});
}
}Superficie v1
Rutas principales, un 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
Diseño
Decisiones aburridas, a propósito.
- 01
Cursor pagination, siempre
Cada endpoint de lista devuelve has_more y next_cursor. Sin records perdidos bajo carga, sin off-by-one.
- 02
Idempotency-Key en POST
Pasa un UUID y reintenta seguro por 24 horas. Los side effects disparan exactamente una vez.
- 03
X-Request-Id en cada respuesta
Pega el ID en soporte y trazamos exactamente la llamada, la respuesta y la llamada downstream.
- 04
Errores con forma
Mismo envelope JSON en cada falla. code, message, doc_url, request_id. Sin nulls sorpresa.
Errores
Un solo formato, siempre.
Sin flags de éxito anidados. Sin mezclas de casing. Sin 200s silenciosos en falla. Si la llamada se rompió, el body te dice exactamente qué llamada, qué esperaba y dónde están los 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
Regístralo una vez. Guarda el secreto ahora.
POST /v1/webhooks con la URL de tu endpoint y los eventos. La respuesta devuelve un secreto de firma whsec_ una sola vez — nunca se guarda de forma legible ni se vuelve a mostrar. Cópialo en INSTANTREPLY_WEBHOOK_SECRET. ¿Lo perdiste? No hay endpoint para recuperarlo: elimina el webhook y registra uno nuevo para obtener un secreto nuevo.
// 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
}