API REST v1

Autenticación, formato de respuestas, errores, paginación y límites.

Antes de empezar

  • Una API key creada en Configuración, Desarrolladores

La API vive en https://api.tinkay.app/v1. Todas las respuestas son JSON y todos los endpoints requieren autenticación.

El workspace se deduce de la API key en el servidor: nunca se envía un identificador de workspace desde el cliente.

Autenticación

Mandá la key en el header Authorization. Las keys se crean y revocan en Configuración, Desarrolladores.

curl https://api.tinkay.app/v1/contacts \  -H "Authorization: Bearer dk_live_xxx"

La API key es secreta: usala solo desde tu servidor. Para el navegador existe el token público del Messenger.

Scopes

Cada key tiene permisos acotados. Si le falta uno, la respuesta es 403 con el scope que hace falta.

CampoTipoDescripción
contacts:read / contacts:writescopeLeer y crear contactos.
conversations:read / conversations:writescopeLeer conversaciones y enviar mensajes.
tickets:read / tickets:writescopeLeer y crear tickets.
articles:readscopeLeer artículos del centro de ayuda.
events:readscopeLeer el feed de eventos.
*scopeAcceso total, incluida la gestión de webhooks.

Formato de respuesta

Las listas devuelven data, next_cursor y has_more. Los objetos individuales devuelven data.

{  "data": [    { "id": "ct_8f2a", "name": "Camila Rodríguez", "email": "[email protected]" }  ],  "next_cursor": "ct_8f2a",  "has_more": true}

Errores

Todos los errores devuelven el mismo shape, con un code estable para tu lógica y un message en español para tus logs.

Códigos de estado

CampoTipoDescripción
400invalid_json / missing_parameterEl cuerpo no es JSON válido o falta un parámetro obligatorio.
401unauthorizedFalta el header o la key no existe.
403forbiddenLa key no tiene el scope necesario.
404not_foundEl recurso no existe en este workspace.
409conflictEl recurso ya existe (por ejemplo, un contacto con ese email).
422validation_errorEl cuerpo es JSON válido pero los campos no pasan la validación.
429rate_limitedSuperaste el límite de requests.
JSON
{  "error": {    "code": "validation_error",    "message": "Hay campos inválidos.",    "details": [{ "path": ["email"], "message": "Invalid email" }]  }}

Paginación por cursor

Pasá limit (1 a 100, por defecto 25) y cursor. El cursor es el id del último elemento de la página anterior, que viene en next_cursor.

Cuando has_more es false, terminaste.

async function* allContacts() {  let cursor = null;  do {    const url = new URL("https://api.tinkay.app/v1/contacts");    url.searchParams.set("limit", "100");    if (cursor) url.searchParams.set("cursor", cursor);    const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.TINKAY_API_KEY}` } });    const page = await res.json();    yield* page.data;    cursor = page.next_cursor;  } while (cursor);}

Límites

600 requests por minuto por API key. Cada respuesta trae los headers para que puedas frenar antes de recibir un 429.

Texto
X-RateLimit-Limit: 600X-RateLimit-Remaining: 587X-RateLimit-Reset: 1772668800

Si tenés que sincronizar seguido, usá webhooks en lugar de consultar en bucle: es más rápido y no consume límite.

Cómo saber que quedó bien

  • `GET /v1/contacts` devuelve 200 con la key
  • Sin el header devuelve 401