Connect
Tu integración por API

API de control

La referencia REST de todo lo que no es una tool: catálogo, conexiones, sesiones, sincronizaciones y webhooks.

Ejecutar una tool es siempre POST /v1/tools/{id}/execute, y su contrato completo vive en la referencia y en el OpenAPI. Alrededor de eso el gateway expone una superficie de control: qué puedes llamar, qué tienes conectado, en qué va una sincronización y a dónde se entregan los eventos. Esta página documenta esa superficie completa.

Cobertura del OpenAPI

Los contratos OpenAPI publicados describen la ejecución de tools. El contrato completo también incluye la creación de enlaces y las solicitudes de carpeta tributaria puntual. Los demás endpoints de control se documentan en esta página.

Convenciones

La base es https://connect.emisso.ai/api/v1. Salvo GET /v1/health, GET /v1 y GET /v1/openapi.json, todos los endpoints exigen Authorization: Bearer connect_sk_… y responden 401 unauthorized con el challenge WWW-Authenticate si el token falta o no sirve. Si la infraestructura de autenticación está caída, la respuesta es 503 service_unavailable (retryable): una caída nuestra nunca se disfraza de «tu clave está mala».

Reglas que aplican a toda la superficie:

  • Todo cuerpo de petición está limitado a 256 KB: por encima responde 413 payload_too_large, y un JSON inválido responde 400 malformed_request.
  • Toda respuesta de éxito envuelve el resultado en { "data": … }; todo error viene como { "error": { "code", "message", "request_id", "suggested_fix" } } con el código del catálogo de errores.
  • Los GET de esta página no escriben en la bitácora: no ejecutan ninguna tool. Solo execute audita.

Rutas para conexiones y sincronizaciones

Las rutas de esta tabla son la lista cerrada para listar conexiones, pedir una sincronización y seguir su estado. En los ejemplos, /v1/... siempre lleva delante https://connect.emisso.ai/api.

OperaciónMétodo y ruta exactosCuerpo
Listar conexiones accesibles a tu claveGET /v1/connectionsSin cuerpo
Ver el estado de una conexión y sus últimos trabajosPOST /v1/tools/conexiones.estado.consultar/execute{"input":{"conexionId":"conn_..."}}
Pedir uno o varios mesesPOST /v1/connections/{conn}/syncs{"periodos":["2026-08","2026-09"]}
Seguir un trabajo recibidoGET /v1/syncs/{id}Sin cuerpo
Ejecutar una tool del catálogoPOST /v1/tools/{id}/execute{"input":{...}}, según su ficha

No existe GET /v1/connections/{id}, GET /v1/connections/{id}/estado ni GET /v1/connections/{id}/syncs. El título «Consultar el estado de las conexiones» corresponde a la tool conexiones.estado.consultar, llamada por POST. GET /v1/connections no devuelve trabajos; la tool devuelve los cinco últimos, no todas las corridas. Para seguir cada solicitud conserva sus job_ids y consulta cada uno con GET /v1/syncs/{id}.

Todas las tools de un sistema conectado exigen X-Connect-Connection: conn_..., incluso con una sola conexión. Las de plataforma o datos abiertos no lo exigen: conexiones.*, core.*, indicadores.* y echo.* son ejemplos. Toda ejecución de tool exige además Content-Type: application/json; omitirlo responde 415 unsupported_media_type. La tool de plataforma conexiones.estado.consultar recibe el filtro en input.conexionId y no exige ese header. Requiere el permiso conexiones:read. En /connections/{conn}/syncs, la conexión va en la ruta.

Deshabilitar, habilitar y eliminar una conexión son tools conexiones.conexion.* por POST /v1/tools/{id}/execute; no tienen rutas REST propias bajo /v1/connections/{id}. Crear un enlace también es una tool, conexiones.enlace.crear, por la misma ruta de ejecución; además existe la alternativa POST /v1/connect_sessions documentada en esta página. Los títulos de las fichas describen operaciones y no definen rutas adicionales.

Descubrimiento

GET /v1/health

Sin credencial. Dice si el gateway está arriba y cuántas tools tiene el registro. El conteo varía con el catálogo.

curl https://connect.emisso.ai/api/v1/health

Salida esperada (el conteo es variable):

data.status = "ok"
data.registry.tools = número actual de tools del registro

GET /v1

Sin credencial. El puntero raíz del API; a diferencia del resto, responde sin el envelope data.

curl https://connect.emisso.ai/api/v1
{
  "data_url": "/api/v1",
  "openapi": "/api/v1/openapi.json",
  "docs": "https://connect.emisso.ai/docs"
}

GET /v1/tools

El catálogo filtrado para tu organización: solo los conectores que tienes habilitados y solo lo que cubren los scopes de tu clave. Dos organizaciones ven listas distintas. Cada entrada trae la ficha completa, incluidos los JSON-Schema de entrada y salida y, cuando la tool lo declara, un example ejecutable:

curl https://connect.emisso.ai/api/v1/tools \
  -H "Authorization: Bearer connect_sk_..."
{
  "data": [
    {
      "id": "sii.rcv.consultar",
      "mcpName": "sii__rcv__consultar",
      "connector": "sii", "resource": "rcv", "verb": "consultar",
      "title": "Consultar RCV del SII",
      "description": "…",
      "plane": "action",
      "reads": "rcv",
      "scope": "sii:read",
      "auth": "none",
      "sensitive": true,
      "version": 4,
      "deprecated": false,
      "annotations": { "readOnly": true, "destructive": false, "idempotent": true, "openWorld": false, "title": "Consultar RCV del SII" },
      "inputSchema": { "…": "draft 2020-12" },
      "outputSchema": { "…": "draft 2020-12" },
      "example": { "input": { "…": "…" }, "output": { "…": "…" } }
    }
  ],
  "pagination": { "cursor": null, "hasMore": false }
}

plane dice si la tool persiste; reads aparece solo en las tools de consulta y nombra el alcance que leen. El modelo completo está en sincronizar y consultar.

GET /v1/tools/{id}

La misma ficha, para un id concreto. Este endpoint no filtra por organización: devuelve la ficha de cualquier tool del catálogo, esté o no conectado su sistema, porque descubrir no es ejecutar. Un id inexistente responde 404 tool_not_found.

curl https://connect.emisso.ai/api/v1/tools/sii.rcv.consultar \
  -H "Authorization: Bearer connect_sk_..."
{ "data": { "id": "sii.rcv.consultar", "…": "la misma ficha de GET /v1/tools" } }

GET /v1/connectors

Los conectores de uso general, con su estado de habilitación para tu organización. Los sistemas conectables (SII y bancos) no aparecen aquí: este endpoint sirve solo el catálogo público. Para obtener los códigos de conector sin adivinar, incluidos los conectables, usa la tool conexiones.sistemas.listar, que además dice qué ya está conectado.

curl https://connect.emisso.ai/api/v1/connectors \
  -H "Authorization: Bearer connect_sk_..."
{ "data": [{ "code": "core", "name": "Core", "plan": "free", "enabled": true }] }

Este endpoint lista solo el catálogo público

/v1/connectors sirve los conectores de uso general (core, echo, indicadores, conexiones). Las fuentes private/tenant como el SII o los bancos no aparecen aquí aunque las tengas conectadas y aunque sus tools sí salgan en /v1/tools. Para ver lo que tu organización tiene conectado, usa /v1/connections o la tool conexiones.estado.consultar.

GET /v1/openapi.json

Sin credencial. El contrato OpenAPI 3.1 del catálogo público, servido por el propio runtime. El contrato del catálogo documentado completo (SII y bancos incluidos) es otro artefacto: /docs/openapi.json.

curl -s https://connect.emisso.ai/api/v1/openapi.json | jq .info
{
  "title": "Emisso Connect API",
  "version": "0.1.0"
}

Conexiones

GET /v1/connections

Tus conexiones, cada una la unidad de facturación. De aquí salen los conn_… que necesitas para el header X-Connect-Connection.

curl https://connect.emisso.ai/api/v1/connections \
  -H "Authorization: Bearer connect_sk_..."
{
  "data": [
    {
      "id": "conn_4ly7hnmw2tigryuxfjkr4",
      "connector": "sii",
      "display_name": "SII prod",
      "empresa_rut": "76123456-0",
      "status": "active",
      "plan": "paid",
      "enabled_scopes": ["sii:read"],
      "credential_scheme": "portal_credentials_representante"
    }
  ],
  "pagination": { "cursor": null, "hasMore": false }
}

empresa_rut es el RUT de la empresa o del titular del acceso, sin puntos y con guion; es null mientras no se conoce, por ejemplo antes de que la persona complete el enlace. credential_scheme es el acceso con el que entró la conexión (los codigo de accesos en conexiones.sistemas.listar), o null si todavía no tiene credencial. En el SII, una conexión con portal_credentials_representante puede pasar a emitir con un enlace activar_emision; una con portal_credentials (clave de la empresa) no emite. Los conectores open y platform nunca aparecen: no hay nada que conectar.

Si eres un agente, prefiere la tool

conexiones.estado.consultar responde lo mismo y además: qué alcances tiene activos cada conexión, en qué van sus sincronizaciones, qué tools puedes invocar sobre ella y datosListos, la respuesta a «¿ya hay algo que leer?». Por ser una tool, se llama igual por MCP que por REST.

Sesiones de conexión

El flujo hosted completo (incrustar el iframe, postMessage, el webhook connect_session.consumed, el modelo de amenaza) vive en el enlace hosted. Aquí, el contrato de los dos endpoints.

POST /v1/connect_sessions

Crea un enlace de un solo uso para que un tercero entregue credenciales de una fuente concreta, sin cuenta y sin acceso al dashboard.

Exige conexiones:write en la API key o el token OAuth, también para elegir el sistema en el formulario y para reconectar. Sin ese permiso responde 403 scope_not_granted. La variante de carpeta tributaria puntual exige su permiso específico sii:carpeta_tributaria:generar en lugar del de enlaces.

CampoTipoNotas
mode"create" | "reauth" | "activar_emision" | "cambiar_clave_certificado"create (default) emite una conexión nueva; reauth reemplaza la credencial de una existente y exige connection_id; activar_emision pide la clave del certificado digital para que una conexión del SII con clave de persona pase a emitir, y exige connection_id; cambiar_clave_certificado pide la clave nueva del certificado de una conexión del SII que ya emite, y exige connection_id.
connector_codestringUna fuente conectable, por ejemplo sii, bch_empresas o itau_empresas. Los códigos válidos son los codigo que devuelve conexiones.sistemas.listar. El enlace queda fijado a esa fuente.
credential_schemestringOpcional, solo en create y con connector_code. El acceso con el que entra la persona (los codigo de accesos en conexiones.sistemas.listar). Omitido, lo elige ella.
emitirbooleanOpcional, solo en create y con connector_code. true exige un acceso que emita y la emisión habilitada para la organización; la persona entregará la clave del certificado digital. Omitido, lo decide ella.
alcancesstring[]Opcional, solo en create y con connector_code. Los módulos de datos que se habilitan, servidos por el acceso fijado (o por todos, si no fijas uno). Omitido, los elige ella.
display_namestringOpcional, solo en create. El nombre de la conexión que nazca del enlace, de 1 a 80 caracteres, sin saltos de línea; se quitan los espacios de los extremos. Lo ves en el panel, la bitácora, los cobros y conexiones.estado.consultar; la persona que conecta no lo ve. Omitido, se llama como su sistema (SII, SII 2). Si con connector_code fijado otra conexión de ese sistema ya usa el nombre, responde 400 validation_error; si el choque aparece después (dos enlaces pendientes con el mismo nombre, o un enlace sin sistema fijado), la conexión nueva lleva el sufijo correlativo (… 2).
connection_idstringObligatorio en reauth, activar_emision y cambiar_clave_certificado. Una conexión de otra organización degrada al mismo 400 validation_error: nunca un 404 que confirme que existe.
allowed_originsstring[]Hasta 5 orígenes https exactos, sin path ni comodín. Allowlist del iframe y destino del postMessage.
redirect_uristringhttps, sin fragmento y, si registraste orígenes, dentro de ese conjunto.

En activar_emision, connector_code es opcional y solo admite sii; credential_scheme, emitir, alcances y display_name no aplican. Si la conexión no puede pasar a emitir, la respuesta dice por qué: 409 requiere_clave_de_persona (entra con la clave de la empresa; crea una conexión nueva con clave de persona y emitir: true), 409 emision_ya_activa, 428 connection_credential_required (renueva primero la credencial con reauth) o 403 connection_disabled. El flujo completo está en activar la emisión en una conexión existente.

cambiar_clave_certificado tiene la misma forma. Si la conexión no lo admite, responde 409 emision_no_activa (todavía no emite; usa activar_emision), 409 requiere_clave_de_persona, 428 connection_credential_required o 403 connection_disabled. El flujo está en cambiar la clave del certificado.

El esquema es estricto: un campo desconocido responde 400 validation_error. La emisión está limitada a 60 enlaces por hora por organización; superado el tope, la respuesta es 429 rate_limited con Retry-After. El enlace vence a las 24 horas en create, activar_emision y cambiar_clave_certificado, y a la 1 hora en reauth, y admite 5 intentos reales de credencial.

Sin un plan activo la respuesta es 402 subscription_required, y con un pago vencido, 402 billing_past_due: el enlace no se emite. Es el mismo corte de la tool conexiones.enlace.crear. La variante de carpeta tributaria puntual no pasa por él.

curl -X POST https://connect.emisso.ai/api/v1/connect_sessions \
  -H "Authorization: Bearer connect_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "create",
    "connector_code": "sii",
    "display_name": "Comercial Andes SpA",
    "allowed_origins": ["https://app.tu-producto.cl"],
    "redirect_uri": "https://app.tu-producto.cl/conexiones/listo"
  }'

Respuesta (201):

{
  "data": {
    "id": "cs_7f3ab9c1d2e4f5061728",
    "mode": "create",
    "connector_code": "sii",
    "connection_id": null,
    "token_prefix": "connect_cs_AbC…",
    "allowed_origins": ["https://app.tu-producto.cl"],
    "redirect_uri": "https://app.tu-producto.cl/conexiones/listo",
    "status": "pending",
    "attempts": 0,
    "max_attempts": 5,
    "expires_at": "2026-08-08T12:00:00.000Z",
    "consumed_at": null,
    "resulting_connection_id": null,
    "created_at": "2026-08-07T12:00:00.000Z",
    "credential_scheme": null,
    "emitir": null,
    "alcances": null,
    "display_name": "Comercial Andes SpA",
    "url": "https://connect.emisso.ai/c/connect_cs_..."
  },
  "meta": { "request_id": "req_..." }
}

El token aparece una sola vez

El token en claro viaja solo en esta respuesta: la base guarda su sha256 y un prefijo visible para nombrarlo en una lista. Si lo pierdes, emite otra sesión y revoca la anterior.

La carpeta tributaria puntual usa una variante de este mismo endpoint con el bloque collection y su propio permiso. En esa variante, Idempotency-Key es obligatoria y permite recuperar el mismo enlace mientras espera autorización. Después de aceptarlo, el enlace no se recupera: consulta la solicitud existente antes de crear otra.

GET /v1/connect_sessions

Lista las sesiones con su token_prefix, su estado (pending, consumed, revoked, expired) y sus intentos; nunca el token. Acepta ?connection_id=conn_… para acotar a una conexión.

curl "https://connect.emisso.ai/api/v1/connect_sessions?connection_id=conn_..." \
  -H "Authorization: Bearer connect_sk_..."
{
  "data": [
    {
      "id": "cs_7f3ab9c1d2e4f5061728",
      "mode": "reauth",
      "connector_code": "sii",
      "connection_id": "conn_4ly7hnmw2tigryuxfjkr4",
      "token_prefix": "connect_cs_AbC…",
      "allowed_origins": [],
      "redirect_uri": null,
      "status": "consumed",
      "attempts": 1,
      "max_attempts": 5,
      "expires_at": "2026-08-07T13:00:00.000Z",
      "consumed_at": "2026-08-07T12:14:09.000Z",
      "resulting_connection_id": "conn_4ly7hnmw2tigryuxfjkr4",
      "created_at": "2026-08-07T12:00:00.000Z"
    }
  ],
  "pagination": { "cursor": null, "hasMore": false }
}

Carpeta tributaria puntual

Requiere sii:carpeta_tributaria:generar. La guía de carpeta tributaria describe la autorización de la empresa, los estados y la retención. Estas son sus rutas de control:

Método y rutaQué devuelve
POST /v1/connect_sessions con collectionEl enlace pendiente y el ID de solicitud, o los IDs y el estado actual al reintentar una solicitud ya aceptada. Requiere Idempotency-Key y habilitación del piloto.
GET /v1/collection_requests/{id}Estado, causa y metadatos del documento, cuando existe.
POST /v1/collection_requests/{id}/cancelEl estado final si ya terminó; de lo contrario, cancela antes de iniciar la emisión cuando no hay trabajo activo.
GET /v1/collection_documents/{id}/downloadURL firmada por cinco minutos, solo con la solicitud ready y el documento dentro de su retención.

La creación comparte con los enlaces generales el cupo de 60 solicitudes por hora y organización: 429 rate_limited incluye Retry-After. Una carpeta sin habilitación responde 403 collection_not_enabled; sin destinatario configurado, 428 collection_configuration_missing. Un replay pendiente cuyo enlace venció responde 410 collection_expired; cambiar el contenido con la misma clave responde 409 idempotency_conflict.

Consultar, cancelar o descargar un recurso ajeno o no disponible responde 404 collection_not_found. Cancelar durante el trabajo responde 409 connection_busy; no revoca una carpeta emitida por el SII. La entrega por webhook exige que el plan incluya esa función y un endpoint habilitado con filtros compatibles. Conserva el ID de solicitud para consultar el resultado aunque no llegue el aviso.

Sincronizaciones

La tool <sistema>.conexion.sincronizar y este endpoint encolan el trabajo: ninguno espera el login ni devuelve los datos sincronizados en esa llamada. La tool responde 200 con data.estado: "encolado" y data.jobId; este endpoint responde 202 con data.job_ids, un arreglo para pedir varios períodos. Guarda los identificadores y consulta su resultado antes de dar los datos por actualizados. La tool pide un período y sus alcances por llamada. El endpoint de control, sin alcances, toma todos los habilitados de la conexión. Los webhooks también permiten seguir el resultado si tu plan los incluye.

POST /v1/connections/{conn}/syncs

Exige el mismo permiso que la tool <conector>.conexion.sincronizar de la conexión solicitada; por ejemplo, sii:read para SII o bci_pyme:read para Bci. Un permiso de otro sistema o conexiones:write no autoriza el sync. La credencial sin el permiso requerido recibe 403 scope_not_granted antes de leer el cuerpo o encolar trabajo.

CampoTipoNotas
periodosstring[]Opcional. Cada uno con forma AAAA-MM, hasta el mes corriente de Chile; sin él se encola ese mes. Máximo 24 períodos por petición.
alcancesstring[]Opcional. Sin él se toman todos los alcances habilitados de la conexión. Cada uno debe estar habilitado en esa conexión.
curl -X POST https://connect.emisso.ai/api/v1/connections/conn_.../syncs \
  -H "Authorization: Bearer connect_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"periodos":["2026-08"],"alcances":["rcv"]}'

Respuesta (202), un trabajo por período encolado:

{ "data": { "job_ids": ["sjb_..."] }, "meta": { "request_id": "req_..." } }

Un mes mal formado o futuro se rechaza con 400 validation_error antes de ocupar un cupo. En la prueba, SII permite los tres meses más recientes (incluido el mes corriente de Chile); pedir meses anteriores responde 403 feature_not_in_plan. Pedir guías fuera de su ventana de seis meses, un mes de Santander que terminó antes de sus últimos 90 días, o sincronizar Previred durante el cierre del 10 al 13 para períodos fuera de los tres meses del alta, responde 400 validation_error. Un sistema sin tool de sincronización encolable responde 404 tool_not_found. Si se supera el límite de pendientes de la organización, responde 429 too_many_pending. Si todos los períodos pedidos ya están activos, responde 409 connection_sync_in_progress. Si solo algunos lo están, puede encolar los restantes y devolver 202: revisa cada trabajo por su periodo, sin asumir que el tamaño de job_ids coincide con el de periodos. Cada mes de una conexión se puede pedir una vez cada 10 minutos, contando también lo que se pidió desde el panel o al conectar. Si alguno de los períodos que faltan se pidió en ese lapso, responde 429 rate_limited con Retry-After en segundos y no encola ninguno; lo ya guardado se puede consultar.

No hay un parámetro de prioridad para clientes. Si una sincronización es urgente o lleva demasiado tiempo sin avanzar, escríbenos desde el chat con el conn_..., el período y el sjb_... si lo tienes; lo revisamos. Esto no garantiza adelanto ni un plazo de término.

Sin un plan activo o con un pago vencido responde 402 (subscription_required o billing_past_due) y no encola nada. Reintentar no cambia el resultado: la sincronización se reanuda al regularizar la cuenta en /billing.

Pedir agosto y septiembre y ver su estado

Ejemplo para una conexión SII con rcv habilitado, con la API key que puede usarla y el permiso sii:read. En prueba solo se pueden pedir los tres meses más recientes, incluido el corriente de Chile: agosto y septiembre de 2026 solo caben juntos en esa ventana durante septiembre u octubre de 2026; para meses anteriores necesitas un plan activo. Requiere curl y jq. Reemplaza los dos valores antes de copiar el bloque:

(
set -euo pipefail
export EMISSO_CONNECT_API_KEY='connect_sk_REEMPLAZA'
export EMISSO_CONNECT_CONNECTION='conn_REEMPLAZA'

# Lista ids y sistemas; comprueba que elegiste la conexión SII correcta.
curl --fail-with-body -sS https://connect.emisso.ai/api/v1/connections \
  -H "Authorization: Bearer $EMISSO_CONNECT_API_KEY" | jq .

# Es periodos (plural), sin sobre input. Conserva la respuesta.
curl --fail-with-body -sS -X POST \
  "https://connect.emisso.ai/api/v1/connections/$EMISSO_CONNECT_CONNECTION/syncs" \
  -H "Authorization: Bearer $EMISSO_CONNECT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"periodos":["2026-08","2026-09"],"alcances":["rcv"]}' \
  -o solicitud-sync.json

# Consulta cada id devuelto; repite este seguimiento hasta que termine.
# No repitas el POST para sondear ni construyas un id a mano.
jq -r '.data.job_ids[]' solicitud-sync.json | while IFS= read -r job_id; do
  curl --fail-with-body -sS "https://connect.emisso.ai/api/v1/syncs/$job_id" \
    -H "Authorization: Bearer $EMISSO_CONNECT_API_KEY" | jq .data
done
)

Ejemplo recortado de una consulta de estado; la siguiente corresponde al otro id y período:

{
  "job_id": "sjb_...",
  "periodo": "2026-08",
  "status": "queued",
  "outcomes": null
}

Un 202 confirma el encolado. queued o running aún no son resultados; sigue los mismos ids. Un resultado final exige revisar outcomes, no solo el estado general. Si recibes 409, sigue el trabajo que ya tenías o revisa la conexión en el panel. Conserva los ids también después de cerrar la terminal. Para consultar los documentos de esos meses usa sii.rcv.consultar con periodo y el header X-Connect-Connection; el respaldo XML sii.documentos.* exige acceso de representante y no está disponible con la clave tributaria de la propia empresa.

GET /v1/syncs/{id}

El estado del trabajo. status es uno de queued, running, succeeded, failed o partial.

curl https://connect.emisso.ai/api/v1/syncs/sjb_... \
  -H "Authorization: Bearer connect_sk_..."
{
  "data": {
    "job_id": "sjb_...",
    "status": "succeeded",
    "targets": ["rcv"],
    "outcomes": [{ "alcance": "rcv", "status": "ok", "recordsSynced": 12 }],
    "alcance": "rcv",
    "periodo": "2026-08",
    "trigger": "manual",
    "attempts": 1,
    "records_synced": 12,
    "last_error": null,
    "created_at": "2026-08-06T17:11:30.000Z",
    "updated_at": "2026-08-06T17:11:44.526Z"
  }
}

outcomes desglosa el resultado por alcance (ok, partial o failed). Puede ser null cuando no hay resultados registrados; también puede conservar progreso de un trabajo aún en curso. Mientras status sea queued o running, sigue consultando el mismo id aunque ya tenga contadores.

succeeded no garantiza que todos los alcances estén completos: revisa los que solicitaste en outcomes, incluidos sus campos de completitud cuando los declaren. Con failed, consulta last_error. La guía de seguimiento explica cada caso y ofrece código con espera acotada. Si prefieres recibir avisos, los eventos sync.* llegan por webhook firmado; un sync.succeeded también puede contener alcances parciales.

En un trabajo fallido, outcomes puede conservar una entrada con el error y su motivo, o, en Previred, resultados que un lote anterior alcanzó a confirmar. Un alcance partial también trae su motivo, igual que cada entrada de perspectivasFallidas. El motivo sale de una lista cerrada que dice qué pasó y quién tiene que actuar; está en el catálogo de errores.

Webhooks

Todas las consultas requieren webhooks:read. Crear, modificar, deshabilitar, rotar secretos y reenviar requieren webhooks:write. Los permisos son independientes y se otorgan al crear una API key o consentir OAuth. Una credencial sin el permiso requerido recibe 403 scope_not_granted antes de resolver el recurso.

La firma de las entregas, los cuerpos de cada evento y las políticas de reintento están en webhooks. El índice de la superficie:

Método y rutaQué hace
POST /v1/webhooksCrea un endpoint. La única respuesta que muestra el secret.
GET /v1/webhooksLista tus endpoints.
GET /v1/webhooks/{id}Un endpoint puntual.
PATCH /v1/webhooks/{id}Modifica url, event_types o enabled.
DELETE /v1/webhooks/{id}Deshabilita el endpoint. Es un apagado, no un borrado: reaparece con enabled: false.
POST /v1/webhooks/{id}/roll-secretRota el secret y devuelve el nuevo, una única vez.
GET /v1/webhooks/{id}/deliveriesLas entregas del endpoint. ?limit= entre 1 y 100, default 50.
POST /v1/webhooks/{id}/deliveries/{deliveryId}/resendReenvía una entrega puntual.

Los eventos suscribibles son sync.succeeded, sync.failed, sync.partial, connect_session.consumed, sii.carpeta_tributaria.ready y sii.carpeta_tributaria.failed, además de los de boletas de honorarios y de su anulación que lista webhooks. Un event_types vacío suscribe a todos.

POST /v1/webhooks

CampoTipoNotas
urlstringhttps y resoluble a una dirección pública; si no, 422 invalid_webhook_url.
event_typesstring[]Opcional. Vacío = todos los eventos.
connection_idstringOpcional. Acota el endpoint a los eventos de una conexión; debe ser de tu organización.
curl -X POST https://connect.emisso.ai/api/v1/webhooks \
  -H "Authorization: Bearer connect_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://app.tu-producto.cl/hooks/connect","event_types":["sync.succeeded","sync.failed"]}'

Respuesta (201):

{
  "data": {
    "id": "whk_...",
    "url": "https://app.tu-producto.cl/hooks/connect",
    "event_types": ["sync.succeeded", "sync.failed"],
    "connection_id": null,
    "enabled": true,
    "disabled_at": null,
    "last_success_at": null,
    "created_at": "2026-08-07T12:00:00.000Z",
    "secret": "whsec_..."
  },
  "meta": { "request_id": "req_..." }
}

Guarda el secret al recibirlo: las lecturas posteriores (GET /v1/webhooks, GET /v1/webhooks/{id}) devuelven el endpoint sin él.

GET /v1/webhooks/{id}/deliveries

curl "https://connect.emisso.ai/api/v1/webhooks/whk_.../deliveries?limit=2" \
  -H "Authorization: Bearer connect_sk_..."
{
  "data": [
    {
      "id": "whd_...",
      "event_type": "sync.succeeded",
      "status": "delivered",
      "attempts": 1,
      "response_status": 200,
      "error": null,
      "created_at": "2026-08-07T12:10:00.000Z",
      "updated_at": "2026-08-07T12:10:01.000Z"
    },
    {
      "id": "whd_...",
      "event_type": "sync.failed",
      "status": "failed",
      "attempts": 6,
      "response_status": 500,
      "error": "HTTP 500",
      "created_at": "2026-08-06T09:00:00.000Z",
      "updated_at": "2026-08-06T18:02:11.000Z"
    }
  ],
  "pagination": { "cursor": null, "hasMore": false }
}

status es uno de pending, delivering, delivered o failed.

POST /v1/webhooks/{id}/deliveries/{deliveryId}/resend

Reencola una entrega concreta, por ejemplo después de arreglar el receptor.

curl -X POST https://connect.emisso.ai/api/v1/webhooks/whk_.../deliveries/whd_.../resend \
  -H "Authorization: Bearer connect_sk_..."
{ "data": { "resent": true } }

Ejecutar una tool

Es una sola forma: POST /v1/tools/{id}/execute con el cuerpo { "input": { … } }, el header X-Connect-Connection: conn_… cuando el conector tiene conexión, y la respuesta { "data": …, "meta": { "request_id", "tool_id", "plane", "latency_ms", "audit_status" } }. La ficha de cada tool, con su ejemplo, está en la referencia.

Errores frecuentes por superficie

Todos salen del catálogo y traen request_id más suggested_fix.

SuperficieCódigos que vas a ver
Toda la API401 unauthorized (falta o falla el bearer, con challenge WWW-Authenticate) · 503 service_unavailable (falla transitoria nuestra, reintenta) · 413 payload_too_large · 400 malformed_request
Tools404 tool_not_found (el id no existe, o el conector no está habilitado para tu organización) · 400 validation_error · 403 scope_not_granted · 428 connection_credential_required
Sincronizaciones403 feature_not_in_plan (en prueba de SII o Previred, meses anteriores a los tres más recientes) · 400 validation_error (mes futuro, guías fuera de los seis meses, Santander fuera de sus últimos 90 días o Previred del 10 al 13 para períodos fuera de los tres meses del alta) · 404 tool_not_found (el sistema no ofrece sincronización encolable) · 403 scope_not_granted · 404 connection_not_found (id inexistente o fuera del acceso de tu clave) · 403 connection_disabled (conexión inactiva) · 403 alcance_not_enabled · 409 connection_sync_in_progress · 429 rate_limited (el mismo mes de la conexión antes de 10 minutos, con Retry-After) · 429 too_many_pending · 404 sync_job_not_found
Sesiones de conexión403 scope_not_granted · 400 validation_error (incluye connection_id ajeno o inconsistente con mode) · 429 rate_limited con Retry-After
Webhooks403 scope_not_granted · 404 webhook_endpoint_not_found · 404 webhook_delivery_not_found · 422 invalid_webhook_url · 403 feature_not_in_plan

Los 404 de esta tabla nunca distinguen «no existe» de «existe en otra organización»: esa ambigüedad es deliberada.

En esta página