Documentación de la API

Bienvenido a la API de Atendo. Desde aquí puedes gestionar conversaciones de WhatsApp, enviar mensajes, cambiar estados, asignar agentes y más, todo de forma programática.

Base URL https://atendo.com.do/api/v1

Todos los endpoints requieren autenticación mediante un token Bearer y el header X-Tenant-ID. Lee la sección de Autenticación antes de comenzar.

Autenticación

La API usa tokens Bearer (Laravel Sanctum). Para obtener un token, haz login con tus credenciales. El token devuelto tiene una expiración de 24 horas.

POST /auth/login

Parámetros

CampoTipoDescripción
emailstringrequeridoCorreo electrónico de la cuenta
passwordstringrequeridoContraseña de la cuenta
cURL
JavaScript
PHP
curl -X POST "https://atendo.com.do/api/v1/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"tu@email.com","password":"tuContraseña"}'
const res = await fetch("https://atendo.com.do/api/v1/auth/login", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    email: "tu@email.com",
    password: "tuContraseña",
  }),
});
const { token, tenant } = await res.json();
$ch = curl_init("https://atendo.com.do/api/v1/auth/login");
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST           => true,
  CURLOPT_HTTPHEADER     => ["Content-Type: application/json"],
  CURLOPT_POSTFIELDS     => json_encode([
    "email"    => "tu@email.com",
    "password" => "tuContraseña",
  ]),
]);
$data = json_decode(curl_exec($ch), true);
$token    = $data["token"];
$tenantId = $data["tenant"]["id"];
200 OK
{
  "token":      "138|abc123...",
  "expires_at": "2026-08-11T14:00:00.000000Z",
  "user": {
    "id":    1,
    "name":  "Gabriel Martinez",
    "email": "tu@email.com"
  },
  "tenant": {
    "id":   1,
    "name": "Mi Empresa"
  }
}

Headers requeridos

Todos los endpoints (excepto login) requieren los siguientes headers en cada petición:

HeaderValorDescripción
AuthorizationBearer {token}Token obtenido en login
X-Tenant-IDintegerID del tenant (campo tenant.id del login)
Content-Typeapplication/jsonRequerido en peticiones POST y PATCH
Ejemplo
Authorization: Bearer 138|abc123...
X-Tenant-ID:    1
Content-Type:   application/json

Errores

La API devuelve errores estándar HTTP. El cuerpo siempre es JSON.

401
Token inválido o expirado. Haz login nuevamente para obtener un token fresco.
422
Validación fallida. El campo errors describe qué campo falló.
404
El recurso no existe o no pertenece a tu tenant.
GET

/whatsapp-channels/{channel_id}/conversations

Retorna la lista paginada de conversaciones de un canal de WhatsApp. Soporta filtrado por estado y búsqueda.

Query params

ParámetroTipoDescripción
statusstringopcionalopen (defecto), assigned, closed, archived
limitintegeropcionalResultados por página. Máximo 100, defecto 20.
searchstringopcionalBusca por nombre, teléfono o último mensaje.
cursorstringopcionalCursor para paginación. Usa el valor next_cursor de la respuesta anterior.
cURL
JavaScript
PHP
curl "https://atendo.com.do/api/v1/whatsapp-channels/1/conversations?status=open&limit=20" \
  -H "Authorization: Bearer {token}" \
  -H "X-Tenant-ID: 1"
const res = await fetch(
  "https://atendo.com.do/api/v1/whatsapp-channels/1/conversations?status=open",
  { headers: { "Authorization": "Bearer {token}", "X-Tenant-ID": "1" } }
);
const { data, next_cursor, has_more } = await res.json();
$ch = curl_init("https://atendo.com.do/api/v1/whatsapp-channels/1/conversations?status=open");
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer {token}",
    "X-Tenant-ID: 1",
  ],
]);
$data = json_decode(curl_exec($ch), true);
200 OK
{
  "data": [
    {
      "id":                   58,
      "status":               "open",
      "contact_phone":        "+18492107660",
      "contact_wa_id":        "18492107660",
      "contact_name":         "Juan Pérez",
      "assigned_to_user_id":  null,
      "assigned_to_name":     null,
      "last_message_preview": "Hola, necesito ayuda",
      "last_message_at":      "2026-08-10T14:26:53.000000Z",
      "unread_count":         3,
      "labels":               []
    }
  ],
  "next_cursor": "eyJpZCI6NTd9",
  "has_more":    true
}
GET

/whatsapp-channels/{channel_id}/conversations/{id}

Retorna los detalles de una conversación junto con sus mensajes y actividades.

Query params

ParámetroTipoDescripción
limitintegeropcionalMensajes por página. Máximo 100, defecto 50.
after_idintegeropcionalSolo retorna mensajes con ID mayor a este valor (para polling en tiempo real).
cURL
JavaScript
curl "https://atendo.com.do/api/v1/whatsapp-channels/1/conversations/58" \
  -H "Authorization: Bearer {token}" \
  -H "X-Tenant-ID: 1"
const res = await fetch(
  "https://atendo.com.do/api/v1/whatsapp-channels/1/conversations/58",
  { headers: { "Authorization": "Bearer {token}", "X-Tenant-ID": "1" } }
);
const { conversation, messages, activities } = await res.json();
200 OK
{
  "conversation": { /* objeto completo de la conversación */ },
  "messages": [
    {
      "id":          1204,
      "direction":   "inbound",
      "type":        "text",
      "content":     "Hola, necesito ayuda",
      "sent_at":     "2026-08-10T14:26:46.000000Z"
    }
  ],
  "activities": [],
  "has_more":    false
}
PATCH

/whatsapp-channels/{channel_id}/conversations/{id}

Actualiza el estado, agente asignado, nombre del contacto o etiquetas de una conversación. Puedes enviar solo los campos que quieres cambiar.

Body (JSON)

CampoTipoDescripción
statusstringopcionalopen, assigned, closed, archived
assigned_to_user_idinteger|nullopcionalID del agente. null para desasignar.
assigned_to_namestring|nullopcionalNombre del agente (se muestra en el historial).
contact_namestring|nullopcionalActualiza el nombre del contacto.
labelsarrayopcionalArray de IDs de etiquetas.
actor_namestring|nullopcionalNombre que aparece en el registro de actividad.
cURL — Cerrar
cURL — Asignar
cURL — Contacto
# Cerrar conversación
curl -X PATCH \
  "https://atendo.com.do/api/v1/whatsapp-channels/1/conversations/58" \
  -H "Authorization: Bearer {token}" \
  -H "X-Tenant-ID: 1" \
  -H "Content-Type: application/json" \
  -d '{"status":"closed","actor_name":"Sistema"}'
# Asignar a un agente
curl -X PATCH \
  "https://atendo.com.do/api/v1/whatsapp-channels/1/conversations/58" \
  -H "Authorization: Bearer {token}" \
  -H "X-Tenant-ID: 1" \
  -H "Content-Type: application/json" \
  -d '{"assigned_to_user_id":3,"assigned_to_name":"Ana Gómez"}'
# Cambiar nombre del contacto
curl -X PATCH \
  "https://atendo.com.do/api/v1/whatsapp-channels/1/conversations/58" \
  -H "Authorization: Bearer {token}" \
  -H "X-Tenant-ID: 1" \
  -H "Content-Type: application/json" \
  -d '{"contact_name":"Juan Carlos Pérez"}'
200 OK — objeto conversación actualizado
POST

/whatsapp-channels/{channel_id}/conversations/{id}/reply

Envía un mensaje de texto a la conversación. El mensaje se entrega al contacto de WhatsApp y queda registrado en el historial.

WhatsApp solo permite enviar mensajes libres dentro de la ventana de 24 horas desde el último mensaje del contacto. Fuera de esa ventana debes usar una plantilla aprobada (/send-template).

Body (JSON)

CampoTipoDescripción
textstringrequeridoTexto del mensaje. Máximo 4096 caracteres.
reply_to_idintegeropcionalID del mensaje al que responder (crea una cita).
cURL
JavaScript
PHP
curl -X POST \
  "https://atendo.com.do/api/v1/whatsapp-channels/1/conversations/58/reply" \
  -H "Authorization: Bearer {token}" \
  -H "X-Tenant-ID: 1" \
  -H "Content-Type: application/json" \
  -d '{"text":"¡Hola! En un momento te atendemos."}'
await fetch(
  "https://atendo.com.do/api/v1/whatsapp-channels/1/conversations/58/reply",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer {token}",
      "X-Tenant-ID":  "1",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ text: "¡Hola! En un momento te atendemos." }),
  }
);
$ch = curl_init("https://atendo.com.do/api/v1/whatsapp-channels/1/conversations/58/reply");
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST           => true,
  CURLOPT_HTTPHEADER     => [
    "Authorization: Bearer {token}",
    "X-Tenant-ID: 1",
    "Content-Type: application/json",
  ],
  CURLOPT_POSTFIELDS => json_encode(["text" => "¡Hola! En un momento te atendemos."]),
]);
$response = json_decode(curl_exec($ch), true);
200 OK
{
  "id":         1205,
  "direction":  "outbound",
  "type":       "text",
  "content":    "¡Hola! En un momento te atendemos.",
  "status":     "sent",
  "sent_at":    "2026-08-10T15:00:00.000000Z"
}
POST

/whatsapp-channels/{channel_id}/conversations/start

Crea o reutiliza una conversación con un número de WhatsApp. Si ya existe una conversación con ese número, la retorna. Si no existe, la crea con estado open.

Body (JSON)

CampoTipoDescripción
phonestringrequeridoNúmero de WhatsApp del contacto. Ej: 18092345678 o +1 (809) 234-5678. Se normaliza automáticamente.
namestringopcionalNombre del contacto.
cURL
JavaScript
curl -X POST \
  "https://atendo.com.do/api/v1/whatsapp-channels/1/conversations/start" \
  -H "Authorization: Bearer {token}" \
  -H "X-Tenant-ID: 1" \
  -H "Content-Type: application/json" \
  -d '{"phone":"18092345678","name":"María López"}'
const res = await fetch(
  "https://atendo.com.do/api/v1/whatsapp-channels/1/conversations/start",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer {token}",
      "X-Tenant-ID":  "1",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ phone: "18092345678", name: "María López" }),
  }
);
const { conversation, is_new } = await res.json();
201 Created — conversación nueva
{
  "conversation": {
    "id":            72,
    "status":        "open",
    "contact_phone": "+18092345678",
    "contact_name":  "María López"
  },
  "messages": [],
  "is_new":      true
}
GET

/whatsapp-channels

Retorna los canales de WhatsApp configurados en tu cuenta. El id del canal es el {channel_id} que usarás en todos los demás endpoints.

cURL
curl "https://atendo.com.do/api/v1/whatsapp-channels" \
  -H "Authorization: Bearer {token}" \
  -H "X-Tenant-ID: 1"
200 OK
[
  {
    "id":                    1,
    "name":                 "Soporte Principal",
    "display_phone_number": "+1 809 850 9222",
    "status":               "active"
  }
]