Documentación para integradores
Ver endpoints

Automatice llamadas telefónicas desde su propio sistema

Esta guía cubre los 22 endpoints públicos de OctoCall: cómo cargar una lista de contactos, lanzar las llamadas, seguir su avance y recuperar los resultados con su transcripción, su clasificación y sus archivos adjuntos. Léala completa antes de armar su colección en Postman o Apidog: la mitad de los problemas de integración se resuelven entendiendo la diferencia entre una campaña y un lote.

Conceptos clave

Cuatro palabras que aparecen en casi todos los endpoints. Si las confunde, va a mandar el identificador correcto al campo equivocado.

Campaña
La configuración reutilizable: qué dice el agente, a qué departamento pertenece y qué variables acepta. Se crea una vez y se usa muchas veces. En el JSON viaja como campaign_id.
Lote
Una ejecución concreta de una campaña sobre una lista de contactos. Cada vez que lanza llamadas está creando un lote. Es lo que se pausa, se reanuda y de lo que se leen resultados.
Agente
La voz que llama. Ya configurado en su organización; usted solo elige cuál usar con agent_id.
Resultado
El registro de una llamada: a quién se llamó, cuánto duró, qué se dijo, cómo se clasificó y qué archivos se adjuntaron.
El detalle que más confunde

Una campaña se define una vez y se ejecuta muchas veces. Cada ejecución es un lote distinto. Por eso, cuando lanza llamadas, el campo campaign_id del cuerpo apunta a la campaña (la configuración), mientras que el identificador que recibe de vuelta es el del lote recién creado.

Hay un detalle heredado que conviene tener presente: en las rutas de lotes el parámetro de la URL figura técnicamente como campaign_id, pero ahí siempre va el identificador del lote — el que le devolvió el lanzamiento, no el de la campaña. En esta guía lo escribimos como {batch_id} para evitar confusiones; el valor que usted envía es el mismo.

Autenticación

Todas las peticiones requieren una clave de acceso en la cabecera Authorization.

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx

La clave la genera un administrador de su organización desde el panel o desde el endpoint de creación. Se muestra una sola vez, en el momento de crearla: si la pierde, hay que revocarla y emitir una nueva.

Cada clave pertenece a una organización y solo ve los datos de esa organización. No hay forma de consultar recursos ajenos: si pide algo que no le pertenece, la respuesta es la misma que si no existiera.

En Postman o Apidog

Configure la autenticación a nivel de colección, no request por request: tipo Bearer Token con su clave. Guarde la URL base como variable de entorno y así podrá alternar entre pruebas y producción sin tocar cada petición.

Flujo típico

El orden en que conviene llamar a los endpoints la primera vez. Los pasos 1 a 3 se hacen una vez; del 4 en adelante, cada vez que quiera llamar.

  1. Averigüe con qué puede trabajar

    Liste sus agentes, sus campañas y sus números telefónicos. Anote los identificadores: los necesitará en el lanzamiento.

  2. Revise cómo se clasifican las llamadas

    Consulte la taxonomía del departamento de su campaña. Ahí están las etiquetas con las que se clasificará cada llamada, y de ahí saldrán los códigos que use para configurar reintentos.

  3. Decida su política de reintentos

    Cuántas veces reintentar un contacto que no atiende, cada cuánto, y ante qué resultados. Si no configura nada, se aplica un comportamiento por defecto conservador: un solo intento.

  4. Lance el lote

    Envíe la lista de contactos con sus variables a lanzar lote. Recibirá el identificador del lote y las llamadas empezarán a salir.

  5. Siga el avance

    Consulte el estado del lote o las estadísticas para ver cuántas llamadas se completaron y cómo se están clasificando.

  6. Recupere e importe los resultados

    Lea los resultados, tráigalos a su sistema y márquelos como procesados para no volver a traerlos en la siguiente consulta.

Forma de las respuestas

Las listas no usan todas el mismo envoltorio. Conviene saberlo antes de escribir el código que las recorre.

EndpointsEnvoltorioPaginación
Agentes, campañas, lotes, resultados items, total, skip, limit
Números telefónicos phone_numbers, total No — devuelve todos
Departamentos items, total No — devuelve todos
Claves de acceso data, count

Donde hay paginación funciona igual: skip es cuántos registros saltar y limit cuántos traer. El campo total es el total real, no el de la página, así que sirve para saber cuántas páginas faltan.

Las fechas se devuelven en formato ISO 8601 (2026-07-20T14:32:10) y los identificadores son UUID.

Agentes

Las voces disponibles para llamar. Solo lectura: los agentes se configuran desde el panel.

GET /api/v1/external/agents

Lista los agentes de su organización.

Filtros

ParámetroQué hacePor defecto
skipCuántos saltar0
limitCuántos traer (máximo 100)50
is_activeSolo activos o solo inactivostodos
business_area_idFiltra por área de negociotodas

Cada agente incluye

agent_id (el que usará al lanzar), name, description, is_active, el área de negocio a la que pertenece y su fecha de creación.

GET /api/v1/external/agents/{agent_id}

Trae un agente puntual. Devuelve los mismos campos que el listado.

Si el agente no existe, responde 404.

Campañas

Las configuraciones reutilizables. De aquí sale el campaign_id que necesita para lanzar.

GET /api/v1/external/campaigns

Lista las campañas disponibles, de la más reciente a la más antigua.

Filtros

ParámetroQué hacePor defecto
skipCuántas saltar0
limitCuántas traer (máximo 100)50
department_idFiltra por departamentotodos
business_area_idFiltra por área de negociotodas

Cada campaña incluye

CampoPara qué sirve
idEl valor que enviará como campaign_id al lanzar un lote
campaign_nameNombre legible de la campaña
department_idDepartamento al que pertenece — úselo para consultar la taxonomía
variable_keysNombres de las variables que el agente puede mencionar en la llamada
Sobre variable_keys

Es la lista de datos que el agente sabe decir: por ejemplo nombre_cliente o monto_deuda. Al cargar cada contacto puede enviar valores para esas variables y el agente los usará durante la conversación. Si envía una variable que no está en esta lista, simplemente no se menciona.

Números telefónicos

Desde qué número saldrán las llamadas.

GET /api/v1/external/phone-numbers

Lista los números disponibles para su organización: tanto los propios como los de uso general. Los inactivos no aparecen.

De cada número obtiene su phone_number_id, el número en formato internacional, un nombre amigable y si tiene SMS habilitado.

No admite filtros ni paginación: devuelve todos.

Es opcional al lanzar

Si no indica un número en el lanzamiento, se asigna automáticamente el primero disponible. Especifíquelo solo si necesita que sus llamadas salgan desde un número concreto.

Taxonomía

El vocabulario con el que se clasifica cada llamada terminada. Consúltelo antes de configurar reintentos o filtrar resultados.

GET /api/v1/external/taxonomy/departments

Lista los departamentos de su organización. Empiece por aquí: necesita un department_id para consultar la taxonomía.

También puede tomar el department_id directamente de una campaña.

GET /api/v1/external/taxonomy

Devuelve las etiquetas de clasificación disponibles para un departamento.

Parámetros

ParámetroQué hacePor defecto
department_idObligatorio. De qué departamento quiere la taxonomía
viewgrouped agrupa por familias; catalog separa las etiquetas base de las propias de su organizacióngrouped

Qué contiene cada etiqueta

CampoPara qué sirve
slugEl código de la etiqueta. Es el que aparece como resultado_label en los resultados y el que usa para configurar reintentos
display_nameEl nombre legible, para mostrar en su interfaz
success_flagIndica si esa etiqueta cuenta como llamada exitosa
sourceSi la etiqueta es del catálogo base o creada por su organización

Las etiquetas vienen organizadas en familias: las de no contacto agrupan los casos en que no se habló con nadie, las de contacto efectivo los casos en que sí. Esa agrupación es la que conviene usar para decidir qué reintentar.

Lotes

Crear ejecuciones, seguirlas y controlarlas. Aquí está el endpoint más importante de toda la API.

POST /api/v1/external/batches/launch

Crea un lote y empieza a llamar, en una sola petición. Responde 201.

Lo mínimo que necesita

{
  "name": "Cobranza julio - primera pasada",
  "agent_id": "a3f1...",
  "campaign_id": "7b2c...",
  "contacts": [
    {
      "phone": "+59891828169",
      "name": "María Pérez",
      "variables": { "monto_deuda": "4520" }
    }
  ]
}

Campos obligatorios

CampoQué esReglas
nameNombre del lote, para reconocerlo después1 a 200 caracteres. Se guarda tal cual, sin prefijos. Único entre sus lotes: si repite un nombre ya usado, se rechaza
agent_idQué agente llamaDel listado de agentes
campaign_idQué campaña se ejecutaDebe tener un departamento configurado
contactsA quién llamarAl menos uno. Teléfonos repetidos: se carga la primera ocurrencia y se ignoran las demás (duplicates en la respuesta)

Cada contacto

CampoQué esReglas
phoneNúmero a marcarObligatorio. Marcable: 6–20 caracteres, solo dígitos (admite +, espacios, guiones, paréntesis). Si no es marcable (p. ej. "00"), el contacto se carga pero no se llama (Skipped)
nameNombre de la personaOpcional. Hasta 100 caracteres
variablesDatos que el agente puede mencionarOpcional. Use los nombres de variable_keys

Cuándo llamar

CampoQué haceSi lo omite
dateUn único día, en formato YYYY-MM-DDSe llama hoy
start_date
end_date
Un rango de días. Van juntos o ningunoSe llama hoy
call_hours_startHora de inicio, formato HH:MM09:00
call_hours_endHora de fin, formato HH:MM21:00

date y el par start_date/end_date son excluyentes: use uno u otro, nunca los dos.

Opciones de la llamada

CampoQué hacePor defecto
phone_number_idDesde qué número salen las llamadasEl primero disponible
enable_voicemailDejar mensaje si atiende un buzón de vozfalse
enable_dtmfPermitir transferir a un agente humanofalse
dtmf_numberA qué extensión transferirObligatorio si activa la transferencia
sort_byEn qué orden llamar, por ejemplo ["monto_deuda:desc"]Orden de carga. Hasta 3 criterios

Reintentos

El bloque retry controla qué pasa cuando una llamada no logra su objetivo. Si lo omite, se aplica un único intento por contacto.

{
  "retry": {
    "max_attempts": 3,          // intentos por contacto (0 a 50)
    "delay_minutes": 30,        // espera entre intentos (0 a 1440)
    "taxonomy": {
      "enabled": true,
      "retry_eligible_labels": ["no_contesta", "buzon_voz"],
      "batch_at_list_end": false
    }
  }
}
CampoQué hace
max_attemptsCuántas veces se marca a un mismo contacto. 1 significa un solo intento, sin reintentos
delay_minutesCuánto esperar antes de volver a marcar
retry_eligible_labelsAnte qué clasificaciones se reintenta. Use los slug de la taxonomía
batch_at_list_endfalse reintenta apenas cuelga; true espera a terminar toda la lista y reintenta en una segunda pasada

Qué recibe

El id del lote creado — guárdelo, es el que usará para consultar resultados —, su estado, el total de contactos importados y un mensaje de confirmación. También incluye callable_contacts, skipped_contacts y, si aplica, el array skipped con los contactos cargados pero no marcados (teléfono inválido → estado de cola Skipped). Si el mismo teléfono aparece más de una vez, se carga solo la primera ocurrencia (first-wins) y la respuesta incluye duplicate_contacts y duplicates (ocurrencias ignoradas, no importadas; distintos de skipped). Los índices de skipped[] y duplicates[] son 0-based respecto al array contacts del request.

CampoQué significa
duplicates[].indexÍndice 0-based de la ocurrencia ignorada en el request
duplicates[].phoneTeléfono tal como llegó en esa fila
duplicates[].nameNombre si se envió
duplicates[].kept_indexÍndice 0-based de la fila que sí se cargó (la primera)

Indicador de capacidad — capacity_warning

La respuesta incluye capacity_warning siempre que se pueda calcular — es informativo, no bloqueante: el lote se lanza igual, incluso cuando el estado es insufficient. Estima cuántos contactos se pueden procesar en la ventana de fechas/horario elegida, usando los canales que se proyecta tendrá disponibles su organización (según su cupo asignado), una duración de llamada típica y un factor de ocupación de los canales — no una tasa fija por canal.

{
  "capacity_warning": {
    "status": "insufficient",
    "message": "~7543 contactos procesables en la ventana estimada (22 canal(es), 1 día(s) válido(s)) · Insuficiente para 27097 contacto(s) marcable(s)",
    "estimated_capacity": 7543,
    "ratio": 0.278,
    "total_hours": 10,
    "valid_days": 1,
    "channels_expected": 22,
    "occupancy_factor_assumed": 0.4
  }
}
CampoQué significa
statussufficient (ratio ≥ 1.2), tight (0.8–1.2) o insufficient (< 0.8)
ratioestimated_capacity / callable_contacts. 1.0 es justo
estimated_capacityContactos que se estima poder procesar en la ventana
total_hoursHoras efectivas consideradas. Si el lote arranca hoy, la primera jornada descuenta lo ya transcurrido (un lote lanzado a las 17:00 con ventana 09:00–21:00 cuenta 4h reales, no 12)
valid_daysDías hábiles dentro de la ventana (feriados excluidos si skip_holidays es true)
channels_expectedCanales que se proyecta tendrá disponibles su organización
occupancy_factor_assumedFracción del tiempo que se asume a esos canales discando activamente

Errores frecuentes

CódigoMotivo
400Falta campaign_id, no existe, o su campaña no tiene departamento configurado
400El número indicado no existe, está inactivo o no es de su organización
400Ningún contacto pudo importarse, o ningún teléfono del body es marcable
404El agente no existe
422Algún campo no cumple su formato (fecha, hora, sort_by, etc.)
422Ya existe un lote con ese name en su organización — elija otro nombre
Lanzamiento asíncrono — opt-in por organización

Si su organización activó el import asíncrono (contacte a soporte para activarlo — pensado para lotes grandes, decenas de miles de contactos), este mismo endpoint responde 202 Accepted en vez de 201. El request es idéntico; la diferencia es que el import de contactos y el inicio de llamadas corren en segundo plano en vez de dentro de la misma petición HTTP. Es opt-in por partner — si no lo activó, nada cambia.

{
  "id": "campaign-uuid-here",
  "status": "Queued",
  "submitted_contacts": 30000,
  "callable_contacts": 29500,
  "skipped_contacts": 350,
  "message": "Lote encolado para import asíncrono. 29850 contacto(s) a procesar. Consulte el progreso en import_status_url.",
  "import_status_url": "/api/v1/external/batches/campaign-uuid-here/import-status",
  "capacity_warning": null
}

submitted_contacts es el conteo crudo del request (antes de partición/dedupe) — no lo compare con total_contacts del 201, que es post-import. callable_contacts/skipped_contacts ya vienen calculados (post partición/dedupe) porque se resuelven en la misma petición. Use import_status_url para seguir el progreso.

GET /api/v1/external/batches/{batch_id}/import-status

Progreso del import asíncrono de un lote (ver arriba). Responde 404 si el lote no existe, 403 si existe pero es de otra organización.

{
  "campaign_id": "campaign-uuid-here",
  "status": "processing",
  "submitted_contacts": 30000,
  "importable_contacts_count": 29850,
  "processed_contacts": 18000,
  "error_detail": null,
  "note": null
}
CampoQué significa
statuspending (todavía no arrancó), processing, done o error
importable_contacts_countDenominador real de processed_contacts (post partición/dedupe) — no submitted_contacts
processed_contactsContactos ya procesados. Converge a importable_contacts_count
error_detailMotivo del fallo si status es error
notePoblado solo si el lote se lanzó por el camino síncrono (flag apagado) o es previo a esta funcionalidad — ahí el estado se deriva de la campaña, no de un job real
GET /api/v1/external/batches

Lista sus lotes, con su estado y su avance de análisis.

Filtros

ParámetroQué hace
statusPor estado del lote
agent_idSolo los de un agente
campaign_idSolo los de una campaña
last_call_sinceSolo los que tuvieron llamadas desde una fecha
skip / limitPaginación (máximo 100 por página)

El bloque analysis

Cada lote trae cuántas llamadas ya tienen su análisis terminado (analyzed), cuántas hay en total (total) y un indicador ready que es true cuando todas están listas.

Úselo antes de importar

Espere a que ready sea true antes de traer los resultados a su sistema. Si importa antes, se llevará llamadas cuya clasificación todavía se está calculando.

GET /api/v1/external/batches/{batch_id}

Trae un lote puntual, con los mismos campos del listado. Responde 404 si no existe.

POST /api/v1/external/batches/{batch_id}/pause

Detiene un lote en curso. Las llamadas ya iniciadas terminan; no se marcan nuevas.

Solo funciona sobre lotes activos. Si el lote ya estaba pausado, responde 400 indicando su estado actual.

POST /api/v1/external/batches/{batch_id}/deploy

Reanuda un lote pausado, o activa uno en borrador.

Acepta opcionalmente max_concurrent_calls para ajustar cuántas llamadas simultáneas permitir al reanudar.

Solo funciona sobre lotes pausados o en borrador. Si el lote ya está activo, responde 400.

Resultados

Qué pasó en cada llamada. Es la parte que va a consultar todos los días.

GET /api/v1/external/results/batches/{batch_id}

Lista los resultados de un lote. Por defecto trae solo las llamadas cuyo análisis ya terminó.

Filtros

ParámetroQué hacePor defecto
statusPor estado de la llamadatodos
resultado_labelPor clasificación, usando el slug de la taxonomíatodas
client_processedfalse trae solo lo que aún no importótodos
date_from / date_toRango de fechas, formato YYYY-MM-DDsin límite
time_from / time_toFranja horaria, formato HH:MMsin límite
include_transcriptIncluir la transcripción completatrue
include_summaryIncluir el resumentrue
include_pendingIncluir llamadas sin análisis terminadofalse
skip / limitPaginación (máximo 200 por página)0 / 50
Para sincronizar a diario

La combinación más útil es client_processed=false: trae únicamente lo que todavía no importó. Impórtelo, márquelo como procesado, y la próxima consulta ya no lo devolverá. Así no necesita llevar la cuenta por su lado.

Qué trae cada resultado

CampoQué es
idIdentificador del resultado
phone_numberNúmero que se marcó
statusCómo terminó la llamada
resultado_labelClasificación asignada al analizar la conversación
duration_secondsCuánto duró
started_at / ended_atCuándo empezó y terminó
end_reasonPor qué terminó — por ejemplo, buzón de voz u ocupado
transcriptTranscripción de la conversación
summaryResumen breve de lo hablado
analysisDatos extraídos de la conversación (ver abajo)
attachmentsArchivos del expediente (ver Adjuntos)
contextLas variables con que se cargó el contacto
client_processedSi ya lo importó a su sistema
dtmf_usedSi hubo transferencia a un agente humano
batch_nameNombre del lote al que pertenece

El bloque analysis

Cuando la llamada fue efectiva, aquí llegan los datos concretos que el agente logró recoger — una fecha de pago comprometida, un monto, un motivo — dentro de extracted_data, junto con un nivel de confianza y un estado que indica si el análisis se realizó o se omitió por no haber conversación que analizar.

GET /api/v1/external/results/batches/{batch_id}/stats

Resumen agregado de un lote, sin traer las llamadas una por una.

Devuelve el total de llamadas, cuántas se completaron, cuántas fallaron, la duración promedio y el desglose por clasificación.

Parámetros

ParámetroQué hacePor defecto
date_from / date_toAcota el rango de fechastodo el lote
is_detailedCon true, cada clasificación incluye además la lista de llamadas que la componenfalse
GET /api/v1/external/results/{result_id}

El detalle completo de una llamada, con los mismos campos del listado.

Los adjuntos solo llegan aquí

Este es el único endpoint que devuelve el campo attachments con contenido. En el listado de un lote siempre llega vacío, para que traer 200 resultados no implique preparar cientos de enlaces de descarga.

PATCH /api/v1/external/results/{result_id}/processed

Marca un resultado como ya importado a su sistema.

{ "client_processed": true }

Devuelve el resultado actualizado.

Dos respuestas que conviene prever

409 significa que el análisis de esa llamada todavía no terminó: espere y reintente, no la marque aún.

429 significa que está marcando de a uno demasiado rápido. Este endpoint admite pocas peticiones por minuto a propósito — para volúmenes altos use la versión masiva.

PATCH /api/v1/external/results/processed/bulk

Marca hasta 500 resultados de una vez. Es la forma recomendada de cerrar una sincronización.

{
  "result_ids": ["9f8e...", "1a2b..."],
  "client_processed": true
}

Qué recibe

CampoQué contiene
updatedCuántos se marcaron correctamente
not_found_idsIdentificadores que no existen
access_denied_idsIdentificadores que no son de su organización
not_ready_idsLlamadas cuyo análisis aún no terminó — reintente estas más tarde

La operación no es todo o nada: los que se pueden marcar se marcan, y los demás se le informan por separado.

Adjuntos

Archivos asociados al expediente de una llamada: comprobantes, capturas, documentos.

ReglaValor
Archivos por llamadaHasta 8
Tamaño por archivoHasta 10 MB
Formatos aceptadosPNG, JPEG, WEBP, GIF y PDF
Cómo se valida el formatoPor el contenido real del archivo, no por su extensión
Vigencia de los enlacesAlrededor de 1 hora
Los enlaces de descarga caducan

Cada archivo llega con un enlace temporal que se genera en el momento de la consulta. No lo guarde en su base de datos: dejará de funcionar en aproximadamente una hora. Guarde el identificador del adjunto y pida un enlace nuevo cuando lo necesite.

POST /api/v1/external/results/{result_id}/attachments

Sube un archivo. Envío tipo formulario con el campo file.

Responde 201 con los datos del archivo y su enlace de descarga. Si el archivo no cumple alguna regla, responde 400 explicando el motivo.

POST /api/v1/external/results/{result_id}/attachments/bulk

Sube varios archivos en una sola petición. Envío tipo formulario con el campo files repetido una vez por archivo.

curl -X POST \
  "https://api.octocall.ai/api/v1/external/results/{result_id}/attachments/bulk" \
  -H "Authorization: Bearer sk_live_su_clave" \
  -F "files=@./expediente/comprobante.png" \
  -F "files=@./expediente/recibo.pdf" \
  -F "files=@./expediente/cedula.jpg"

Éxito parcial

Responde 200 aunque algunos archivos sean rechazados. Nunca es todo o nada: los válidos se guardan y los demás se le informan con su motivo, en la misma respuesta.

{
  "uploaded": [
    {
      "id": "9f8e...",
      "filename": "comprobante.png",
      "content_type": "image/png",
      "size_bytes": 245678,
      "url": "https://..."
    }
  ],
  "failed": [
    {
      "filename": "contrato.docx",
      "error": "El contenido del archivo no coincide con un tipo permitido."
    }
  ],
  "total_after": 1
}

total_after es cuántos adjuntos tiene la llamada después de esta petición, contando los que ya tenía.

Límites de la petición

SituaciónRespuesta
Más de 8 archivos en un envío413 — no se procesa ninguno
Ningún archivo en el envío422
Un archivo inválido entre varios válidos200 — el inválido va en failed
Se supera el tope de 8 por llamada200 — el excedente va en failed
Por qué a veces no ve el rechazo por tope

Como el máximo por envío (8) coincide con el máximo por llamada (8), ese rechazo solo aparece cuando la llamada ya tenía archivos. Por ejemplo: con 6 adjuntos previos y 4 nuevos, se aceptan 2 y se rechazan 2. En cambio, un envío de 12 archivos se rechaza entero antes de evaluar nada.

GET /api/v1/external/results/{result_id}/attachments/{attachment_id}/url

Genera un enlace de descarga nuevo para un archivo que ya subió.

Úselo cuando el enlace que tenía haya caducado. Evita tener que volver a pedir el detalle completo de la llamada solo para refrescar una dirección.

Devuelve los mismos datos del archivo, con un enlace recién emitido.

Claves de acceso

Gestión de las credenciales de su organización. Requiere permisos de administrador.

POST /api/v1/external/api-keys

Crea una clave nueva.

{
  "name": "Integración ERP - producción",
  "scopes": ["read", "write"],
  "expires_at": "2027-01-01T00:00:00"
}

Solo name es obligatorio. Si indica una fecha de expiración, debe ser futura.

Se muestra una sola vez

La clave completa viene en el campo key de esta respuesta y no se puede recuperar después. Guárdela en su gestor de secretos antes de cerrar la ventana. Si la pierde, revoque esa clave y cree otra.

GET /api/v1/external/api-keys

Lista las claves de su organización. Por seguridad nunca devuelve la clave completa, solo su prefijo para poder identificarla.

De cada una obtiene su nombre, si sigue activa, cuándo expira y cuándo se usó por última vez — útil para detectar credenciales olvidadas.

La respuesta viene en data con el total en count.

DELETE /api/v1/external/api-keys/{api_key_id}

Revoca una clave. Deja de funcionar de inmediato.

La clave no se borra: queda registrada como inactiva para conservar el historial de uso.

Errores y límites

Qué significa cada código y qué hacer al recibirlo.

CódigoQué pasóQué hacer
400Algún dato del envío no es válidoLea el mensaje: indica el campo exacto
401Falta la clave o no es válidaRevise la cabecera Authorization
403El recurso es de otra organizaciónVerifique que el identificador sea suyo
404El recurso no existeVerifique el identificador
409El análisis de la llamada aún no terminóEspere y reintente
413Demasiados archivos en un envíoDivida en envíos de hasta 8
422Falta un campo obligatorio o tiene formato incorrectoRevise el detalle: señala qué campo falló
429Demasiadas peticiones seguidasEspere antes de reintentar
503La modalidad pedida no está disponibleReintente más tarde o contacte a soporte

Sobre los límites de uso

Hay dos techos: 50 peticiones por minuto por API key y 200 por minuto por organización. Si una key se pasa, las demás de la misma org siguen; si la org llega a 200, todas esperan. El 429 caduca solo al cerrar la ventana (1 minuto, o 5 si el exceso se repite). Que la key no tenga fecha de vencimiento no deja el bloqueo permanente.

El marcado individual de resultados como procesados tiene un límite más estricto, a propósito: está pensado para correcciones puntuales. Para volúmenes reales use siempre la versión masiva, que acepta 500 por petición.

Los adjuntos responden 404, no 403

En la mayoría de los endpoints, pedir un recurso ajeno devuelve 403. En los de adjuntos devuelve 404, igual que si no existiera. Es deliberado: así no se revela la existencia de expedientes de otras organizaciones. No lo interprete como un error de su integración.