Enlace hosted de conexión
Un enlace de un solo uso para que un tercero entregue la clave del SII o del banco: sin cuenta, sin acceso al dashboard y sin que la credencial pase por tu aplicación.
Quien tiene las credenciales de una fuente casi nunca es quien administra Emisso: la clave del SII la tiene el contador, la del banco la tiene el dueño. El enlace hosted resuelve eso con una sesión de conexión: un enlace de un solo uso que permite entregar credenciales de una fuente concreta, para una organización concreta, sin crear una cuenta y sin dar acceso a nada más del dashboard.
El ciclo son cinco pasos: creas la sesión, envías el enlace, la persona entrega sus credenciales, tu aplicación se entera por postMessage (si lo incrustaste) o por redirect_uri, y además recibes un webhook. Todo queda en la bitácora de la conexión.
La vía sin código
Cuando no estás incrustando el widget en un producto, no necesitas la API: un agente conectado por MCP acuña el enlace en medio de la conversación con conexiones.enlace.crear. La tool viaja dentro de la meta-tool execute_write, porque escribe:
{ "tool": "conexiones.enlace.crear", "params": { "sistema": "sii" } }Desde tu código, la misma tool se llama por REST, en POST /api/v1/tools/conexiones.enlace.crear/execute. Salida esperada, por cualquiera de los dos caminos (por REST llega dentro de data):
{
"url": "https://connect.emisso.ai/c/mYw2kQ81xR4tPnZs",
"dominio": "connect.emisso.ai",
"sistema": "sii",
"sistemaNombre": "Servicio de Impuestos Internos",
"modo": "crear",
"expiraEn": "2026-08-07T15:32:11.000Z",
"intentosMaximos": 5,
"acceso": null,
"emitir": null,
"alcances": null,
"advertencia": "Este enlace pide credenciales de acceso al sistema. Muéstralo siempre con su dominio completo y di quién lo pidió y para qué. No lo presentes como un aviso del banco ni del SII."
}Con acceso, emitir y alcances el agente fija lo mismo que credential_scheme, emitir y alcances en la API (ver la tabla de abajo); los códigos de acceso salen de accesos en conexiones.sistemas.listar. Si los omite, los elige la persona.
Este carril está deliberadamente recortado: el enlace vence en 1 hora (la persona está presente ahora), no acepta allowed_origins ni redirect_uri (los dos campos que lo volverían un vector de clickjacking y un open redirect en manos de un modelo de lenguaje) y tiene su propio tope de emisión por actor. La advertencia viaja ya escrita para que el agente la muestre tal cual.
Todo lo que sigue en esta página es la vía de integrador: POST /v1/connect_sessions con API key, que sí admite incrustar el widget y controlar el retorno.
1. Crear la sesión
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",
"credential_scheme": "portal_credentials_representante",
"emitir": true,
"alcances": ["rcv", "documentos"],
"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-07-29T12:00:00.000Z",
"consumed_at": null,
"resulting_connection_id": null,
"created_at": "2026-07-28T12:00:00.000Z",
"credential_scheme": "portal_credentials_representante",
"emitir": true,
"alcances": ["rcv", "documentos"],
"display_name": "Comercial Andes SpA",
"url": "https://connect.emisso.ai/c/connect_cs_..."
},
"meta": { "request_id": "req_..." }
}El token aparece una sola vez
La url con el token en claro se devuelve únicamente en esta respuesta. La base guarda solo su sha256 y un prefijo visible para nombrarlo en una lista, igual que una API key (connect_sk_). Si lo pierdes, emite otra sesión y revoca la anterior: no hay forma de recuperarlo.
| Parámetro | Qué hace |
|---|---|
mode | create (por defecto) emite una conexión nueva; reauth reemplaza la credencial de una conexión existente y exige connection_id; activar_emision hace que una conexión del SII que ya lee pase a emitir y exige connection_id (ver Activar la emisión en una conexión existente); cambiar_clave_certificado le pide a la empresa la clave nueva del certificado de una conexión que ya emite y exige connection_id (ver Cambiar la clave del certificado). |
connector_code | El código de una fuente conectable, por ejemplo sii, bch_empresas o itau_empresas. El enlace queda fijado a esa fuente: quien lo abre no elige otra. Los códigos válidos son los codigo que devuelve conexiones.sistemas.listar. |
credential_scheme | Opcional. El acceso con el que entra la persona, por ejemplo portal_credentials (clave de la empresa) o portal_credentials_representante (clave de una persona que la representa) en el SII. Queda fijo en la conexión. Omitido, lo elige quien abre el enlace. Los códigos son los codigo de accesos en conexiones.sistemas.listar. |
emitir | Opcional. true crea una conexión que emite documentos tributarios: exige un acceso que pueda emitir (si el sistema tiene uno solo, se fija ese) y que la emisión esté habilitada para tu organización. Quien abre el enlace tendrá que entregar la clave del certificado digital. false crea una conexión que solo lee. Omitido, lo decide la persona. |
alcances | Opcional. Los módulos de datos que se habilitan, servidos por el acceso fijado (o por todos los accesos, si no fijas uno). Omitido, los elige la persona. |
display_name | Opcional, solo en create. El nombre de la conexión que nazca del enlace, de 1 a 80 caracteres: el que ves en el panel, la bitácora y los cobros. Quien abre el enlace no lo ve. Omitido, la conexión se llama como su sistema (SII, SII 2). Si otra conexión de ese sistema ya lo usa, responde 400 validation_error. Para cambiarlo después, usa conexiones.conexion.renombrar. |
connection_id | Obligatorio en reauth, activar_emision y cambiar_clave_certificado. Una conexión de otra organización es imposible de referenciar: lo impide una llave foránea compuesta en el esquema, no una validación de código. |
allowed_origins | Hasta 5 orígenes https exactos, sin comodines ni path. Es la allowlist del iframe y el destino del postMessage. |
redirect_uri | A dónde volver al terminar. Debe ser https, sin fragmento y, si registraste orígenes, pertenecer a ese conjunto. |
credential_scheme, emitir y alcances exigen connector_code y mode: "create"; al volver a vincular, la conexión ya tiene su acceso. Una combinación imposible (un acceso que el sistema no tiene, emitir con un acceso que no emite, un módulo que el acceso no sirve) devuelve 400 validation_error sin crear nada. Todos son opcionales: una integración que no los manda sigue funcionando igual.
Un campo desconocido en el cuerpo devuelve 400 validation_error: el esquema es estricto a propósito, porque un campo mal escrito es alguien creyendo que está configurando algo. La emisión está limitada por tasa (60 enlaces por hora y por organización); al excederla la respuesta es 429 con Retry-After. Los topes completos están en límites.
Emitir un enlace abre una conexión facturable, así que sin un plan activo la respuesta es 402 subscription_required y con un pago vencido, 402 billing_past_due. Si la organización queda sin plan después de emitirlo, quien abre el enlace ve que no está disponible y no se le piden credenciales.
Vencimiento: 24 horas en mode: "create", mode: "activar_emision" y mode: "cambiar_clave_certificado" (margen para que el contador lo abra al día siguiente) y 1 hora en mode: "reauth" (se emite frente a una credencial ya rota, con la persona presente). Intentos: 5 por sesión; un formulario mal tipeado no gasta ninguno, solo cuenta un intento real contra la fuente. Consumo: solo al éxito, así que una clave equivocada no quema el enlace: se reintenta sin pedir otro.
GET /v1/connect_sessions lista las sesiones con su token_prefix, su estado y sus intentos; nunca el token. Acepta ?connection_id=conn_… para acotar la lista a una conexión.
También puedes emitir el enlace desde el dashboard, sin escribir código: en Conexiones para el modo create (ahí siempre eliges el acceso, la emisión y los datos antes de crearlo), y en los ajustes de una conexión para los modos reauth, activar_emision (en Emisión en el SII, «Pedir la clave a la empresa») y cambiar_clave_certificado (en Clave del certificado digital, «Pedir la clave a la empresa»). La guía Pedir la clave con un enlace recorre ese camino con una demo animada del panel y de la pantalla que recibe la persona; sirve para mandársela a quien no integra la API. Ahí mismo se revoca: la sesión pasa a status: "revoked", igual que se revoca una API key, porque no hay borrado en ningún punto de este flujo. El enlace emitido desde el dashboard nace sin allowed_origins, así que no es incrustable: para el iframe usa la API.
2. Abrir el enlace
La persona abre https://connect.emisso.ai/c/<token>, ve el nombre de tu organización y la fuente, entrega sus credenciales y recibe la confirmación. No hay registro, ni contraseña, ni acceso a ninguna otra pantalla.
La versión web de esta página trae una demo interactiva de esa pantalla: el mismo componente que corre detrás de un enlace de verdad, con una acción falsa que no crea ninguna conexión, no llama al SII y nunca lee la clave que escribas. Puedes recorrerla entera con datos inventados. Si estás leyendo el markdown, el recorrido equivalente está descrito paso a paso en Qué verá la persona.
Se monta al pulsarlo: la página no le manda el código del widget a quien no lo pide.
Si el token no existe, venció, ya fue consumido o agotó sus intentos, la página responde el mismo 404, sin cuerpo diferenciado. Así, quien pruebe tokens no puede distinguir cuáles existieron o fueron usados.
Qué verá la persona
El recorrido completo, para que puedas anticiparlo cuando entregues el enlace, y para que un agente que lo acuña con conexiones.enlace.crear sepa qué explicar:
- La cabecera dice para quién es. «Conexión para <tu organización>», y si el enlace lo pidió otra empresa, además «Solicitado por». Nunca se presenta como un aviso del banco ni del SII.
- Si no fijaste el acceso y la fuente tiene más de uno, lo elige primero. El SII ofrece «Con clave de empresa» y «Con clave de persona». Marcar un radio no avanza: hay que confirmar con «Continuar». Con
credential_schemefijado, este paso no aparece. La fuente ya viene fijada por el enlace; eso no se elige. - Escribe sus credenciales. Los campos salen del acceso (para el SII con clave de empresa, RUT de la empresa y clave) y el RUT se formatea solo. Si fijaste
emitir: true, el bloque de emisión aparece activo y pide la clave del certificado digital, que es obligatoria. La clave nunca entra a estado de React ni a la analítica. - Ve qué datos se van a conectar. Con
alcancesfijado, los ve como lista y no los cambia. Si no lo fijaste, «Datos que conectarás» abre una hoja donde puede elegirlos. - Espera mientras Emisso comprueba la clave. El indicador de progreso refleja hitos persistidos del intento (credencial guardada, acceso confirmado, módulos consultados, registros guardados). Un banco puede tardar cerca de un minuto. Puede cerrar la pestaña: el trabajo sigue en el servidor.
- Ve el cierre. Si el acceso quedó verificado, la confirmación y el aviso de que puede cerrar. Si la fuente rechazó la clave, el error aparece junto al campo y el enlace sigue vivo: reintenta ahí mismo, hasta agotar los 5 intentos, sin pedir otro enlace.
Lo que no ve en ningún momento: el dashboard, otras conexiones de tu organización, otros sistemas, ni una pantalla de registro.
Sin precios de Emisso
Quien abre el enlace nunca ve precios de Emisso, tampoco al marcar emitir. El costo de la conexión lo ve
quien la crea: en el panel, antes de crear el enlace; por un agente, en costoAdicional.
Con la marca de tu organización
La página puede mostrar tu nombre, tu logo y tu color en vez de la marca de Emisso. Se pide a soporte, que la
activa por organización; desde ahí, quien administra la organización la configura en Organización →
Ajustes → Marca de tus enlaces y se aplica a todos sus enlaces, también a los que crea la API y a la página
incrustada. No hay campos nuevos en POST /v1/connect_sessions.
- Nombre visible: entre 2 y 60 caracteres. No puede incluir el nombre de un banco, del SII u otro sistema conectable, ni «Emisso».
- Logo: exactamente 256 × 256 px, PNG o WebP, hasta 256 KB. Lo importante tiene que caber en el círculo central de 200 px, porque el cuadro tiene las esquinas redondeadas. Se muestra a 34 px en la cabecera y a 44 px en el cierre.
- Color de acento: un hexadecimal
#rrggbbpara el botón, la barra de avance y el fondo del logo. El color del texto encima se elige solo para que contraste.
Con o sin marca, la página sigue mostrando el dominio connect.emisso.ai, «Protegido por Emisso Connect» y el
logo oficial del sistema que se conecta. Así nadie puede hacer pasar el enlace por un aviso del banco o del SII.
3. Incrustarlo en tu producto
Con allowed_origins poblado, la página se puede incrustar. La cabecera frame-ancestors se construye por sesión desde esa lista, con 'none' como valor por defecto cuando está vacía.
<iframe
src="https://connect.emisso.ai/c/connect_cs_..."
title="Conectar el SII"
style="width:100%;height:640px;border:0"
></iframe>Reglas: orígenes https exactos (https://app.tu-producto.cl, sin path ni comodín), máximo 5, y si no registras ninguno el iframe no carga.
4. Escuchar el resultado en el navegador
Cuando el flujo llega a su estado final, la página emite un postMessage hacia cada origen exacto que registraste, nunca "*". El mensaje no lleva la credencial ni el token:
window.addEventListener("message", (event) => {
if (event.origin !== "https://connect.emisso.ai") return; // verifica SIEMPRE el origen
const msg = event.data as { type: string; status: string; connection_id: string | null };
if (msg.type !== "emisso:connect") return;
if (msg.status === "connected") {
console.log("entrega aceptada:", msg.connection_id);
} else {
console.warn("la entrega no fue aceptada; el enlace sigue vivo hasta que venza");
}
});El mensaje es exactamente { type: "emisso:connect", status: "connected" | "failed", connection_id: string | null } y nada más, y llega una sola vez: hay un único emisor.
Los dos estados son terminales, pero significan cosas distintas de lo que sugiere el nombre:
connected: Emisso aceptó la entrega, vinculó la credencial y consumió el enlace.connection_ididentifica la conexión creada o actualizada. No implica necesariamente que el login o la primera sincronización ya hayan terminado: cuando la comprobación no puede hacerse en línea, Emisso deja un trabajo durable en cola antes de emitir este estado.failed: el flujo terminó sin una entrega que el anfitrión pueda tratar como completada.connection_idesnullsiempre, aunque el intento haya alcanzado a crear una conexión o guardar una credencial. El mismo enlace retoma esa conexión sin duplicarla; si no quedó una comprobación durable en cola, la persona tendrá que ingresar la clave otra vez porque los campos secretos no sobreviven al cierre de la pestaña.
Una clave rechazada por la fuente no es un estado terminal y no emite nada: el enlace sigue vivo y la persona reintenta en la misma pantalla, hasta agotar los 5 intentos.
El reintento rota la credencial sobre la conexión que el enlace ya creó, nunca crea una segunda. Eso vale también si la persona recarga la página o vuelve a abrir el enlace más tarde: el vínculo vive en la sesión, no en la pestaña. Por eso una sesión todavía pending puede traer resulting_connection_id con un conn_… ya poblado: significa «este enlace ya creó esta conexión y está rotando sobre ella», no que se haya consumido. Lo que marca el consumo sigue siendo status: "consumed" con su consumed_at.
Si registraste un redirect_uri, al llegar a ese estado final la página navega una sola vez (con history.replace, para que el botón «atrás» no lleve a un enlace ya consumido) agregando status=connected|failed a tu URL, y connection_id solo cuando la entrega fue aceptada. El token nunca viaja en esa redirección; si tu redirect_uri traía un token propio, se elimina antes de navegar.
Si no registraste orígenes y no hay redirect_uri, no se emite ningún mensaje ni se navega: el resultado se consulta con GET /v1/connections o llega por webhook.
5. Recibir el webhook
Cuando el enlace se usa con éxito, Emisso emite el evento connect_session.consumed por el mismo bus firmado que los eventos sync.* (POST /v1/webhooks para registrar un endpoint; la entrega trae webhook-id, webhook-timestamp y webhook-signature, y la firma se verifica igual que siempre).
La carpeta tributaria puntual tiene su propio flujo: aceptar el enlace no
emite connect_session.consumed. Su resultado llega con sii.carpeta_tributaria.ready o
sii.carpeta_tributaria.failed, después de cerrar el acceso temporal.
{
"type": "connect_session.consumed",
"timestamp": "2026-07-28T12:00:00.000Z",
"data": {
"session": { "id": "cs_7f3ab9c1d2e4f5061728" },
"connection": { "id": "conn_...", "connector": "sii" },
"verified": true,
"consumed_at": "2026-07-28T12:00:00.000Z"
}
}verified distingue tres casos: true (la verificación contra la fuente corrió y pasó), false (corrió y falló; la conexión existe igual, con la credencial que se entregó) y null (no hubo un veredicto en línea). null puede significar que el conector no declara verificación inmediata o que la comprobación quedó diferida en un trabajo durable; no significa que la fuente ya haya aceptado la credencial ni que los datos estén disponibles. Para disponibilidad de datos, espera el webhook sync.succeeded o consulta el estado de la conexión.
La conexión no espera al webhook
Si tu endpoint está caído, la conexión igual quedó creada: la entrega se reintenta con backoff y el resultado real está siempre en GET /v1/connections. Nunca hagas depender el alta de haber recibido el evento.
6. Auditoría
Todo lo que hizo el enlace queda en la pestaña Bitácora de la conexión, atribuido con honestidad: las filas de configuración muestran enlace de conexión (cs_…) como actor (ni la persona que emitió el enlace, que no entregó nada, ni «sistema», que sería falso), y la verificación contra la fuente aparece en las ejecuciones porque pasa por el mismo gateway.execute() que cualquier otra llamada. Qué guarda cada fila y cómo leerla está en la bitácora.
Activar la emisión en una conexión existente
Si tu cliente conectó el SII solo para leer y ahora quiere emitir, no hace falta borrar la conexión ni crear otra. Un enlace con mode: "activar_emision" le pide solo la clave del certificado digital: la misma conexión, con el mismo conn_…, sus datos y su sincronización, pasa a emitir facturas, notas de crédito y boletas. Tu cliente no necesita cuenta en Emisso ni entrar al panel.
Sirve solo para conexiones que entraron con clave de persona (credential_scheme: "portal_credentials_representante" en GET /v1/connections). La clave tributaria de la empresa no emite y el acceso de una conexión no cambia: para esas conexiones crea una conexión nueva con mode: "create", credential_scheme: "portal_credentials_representante" y emitir: true.
curl -X POST https://connect.emisso.ai/api/v1/connect_sessions \
-H "Authorization: Bearer connect_sk_..." \
-H "Content-Type: application/json" \
-d '{
"mode": "activar_emision",
"connection_id": "conn_4ly7hnmw2tigryuxfjkr4",
"redirect_uri": "https://app.tu-producto.cl/conexiones/listo"
}'{
"data": {
"id": "cs_4b8ad2c7e1f3a5069172",
"mode": "activar_emision",
"connector_code": "sii",
"connection_id": "conn_4ly7hnmw2tigryuxfjkr4",
"token_prefix": "connect_cs_QrS…",
"allowed_origins": [],
"redirect_uri": "https://app.tu-producto.cl/conexiones/listo",
"status": "pending",
"attempts": 0,
"max_attempts": 5,
"expires_at": "2026-11-08T12:00:00.000Z",
"consumed_at": null,
"resulting_connection_id": null,
"created_at": "2026-11-07T12:00:00.000Z",
"credential_scheme": null,
"emitir": null,
"alcances": null,
"display_name": null,
"url": "https://connect.emisso.ai/c/connect_cs_..."
},
"meta": { "request_id": "req_..." }
}La respuesta es la misma de create, con mode: "activar_emision" y la url del enlace. connector_code es opcional (sale de la conexión); credential_scheme, emitir, alcances y display_name no aplican y devuelven 400 validation_error. allowed_origins y redirect_uri funcionan igual que en el alta, así que el enlace también se puede incrustar.
| Respuesta | Cuándo |
|---|---|
201 | El enlace quedó creado. Si había otro enlace de activación vivo para esa conexión, queda revocado. |
400 validation_error | La conexión no es de tu organización o no es del SII, el cuerpo trae un campo que no aplica, o la emisión no está habilitada para tu organización. |
409 requiere_clave_de_persona | La conexión entra con la clave tributaria de la empresa. Crea una conexión nueva con clave de persona y emitir: true. |
409 emision_ya_activa | La conexión ya emite. No hay nada que pedir. |
428 connection_credential_required | La credencial de la conexión falta o no sirve. Renuévala primero con mode: "reauth". |
403 connection_disabled | La conexión está pausada. |
402 subscription_required / billing_past_due | El mismo corte por cobranza del alta: emitir hace que la conexión cuente como emisora. |
La guía Activar la emisión con un enlace desde tu sistema recorre esta llamada y la pantalla que ve tu cliente, con una demo animada.
Lo que ve tu cliente: quién lo pide, el RUT de la empresa (que no se edita), que la lectura sigue igual y que se suma emitir facturas, notas de crédito y boletas. Escribe la clave del certificado y presiona «Activar emisión». Emisso comprueba en el SII que la empresa esté inscrita en el Facturador Gratuito y que haya un certificado digital para firmar. Si el SII tiene más de un giro o una dirección para la empresa, elige cuál va en los documentos. No ve precios de Emisso.
Envía el enlace solo a quien tiene la clave del certificado: funciona como una autorización y quien lo completa activa la emisión de la empresa. Si la clave no es la correcta, el primer documento no sale y pides la nueva con mode: "cambiar_clave_certificado".
El enlace se consume solo cuando la emisión queda activa. Si la empresa no está inscrita en el Facturador o no tiene un certificado cargado en el SII, la pantalla dice qué hacer y el enlace sigue vivo hasta que vence, para que tu cliente lo resuelva en sii.cl y vuelva a intentarlo. Cada intento que llega al SII gasta uno de los 5.
Para saber que terminó: el webhook connect_session.consumed de ese enlace (su session.id es el que recibiste al crearlo) llega cuando la conexión ya emite. Desde ahí emites con sii.dte.emitir o sii.boleta.emitir y el mismo connectionId. Al pasar a emitir, la conexión cuenta como conexión que emite en tu plan.
Un agente pide el mismo enlace con conexiones.enlace.crear, modo: "activar_emision" y conexionId. Desde el panel, en los ajustes de la conexión, Emisión en el SII → Pedir la clave a la empresa.
Cambiar la clave del certificado
Cuando la empresa renueva su certificado digital, la clave suele cambiar, y el SII rechaza la firma de la clave anterior. Si tu cliente no entra al panel, un enlace con mode: "cambiar_clave_certificado" le pide solo la clave nueva del certificado. La conexión sigue emitiendo con el mismo conn_…; no cambia su acceso, su empresa ni su clave tributaria.
Sirve para conexiones del SII que ya emiten. Para una conexión que todavía no emite, usa activar_emision, que también pide la clave del certificado.
curl -X POST https://connect.emisso.ai/api/v1/connect_sessions \
-H "Authorization: Bearer connect_sk_..." \
-H "Content-Type: application/json" \
-d '{
"mode": "cambiar_clave_certificado",
"connection_id": "conn_4ly7hnmw2tigryuxfjkr4"
}'{
"data": {
"id": "cs_9c2de7a1b3f4e5061829",
"mode": "cambiar_clave_certificado",
"connector_code": "sii",
"connection_id": "conn_4ly7hnmw2tigryuxfjkr4",
"token_prefix": "connect_cs_XyZ…",
"allowed_origins": [],
"redirect_uri": null,
"status": "pending",
"attempts": 0,
"max_attempts": 5,
"expires_at": "2026-11-10T12:00:00.000Z",
"consumed_at": null,
"resulting_connection_id": null,
"created_at": "2026-11-09T12:00:00.000Z",
"credential_scheme": null,
"emitir": null,
"alcances": null,
"display_name": null,
"url": "https://connect.emisso.ai/c/connect_cs_..."
},
"meta": { "request_id": "req_..." }
}La forma del cuerpo es la misma de activar_emision: connector_code es opcional, credential_scheme, emitir, alcances y display_name no aplican, y allowed_origins y redirect_uri funcionan igual que en el alta. Este enlace no suma nada a tu cobro: la conexión ya emitía.
| Respuesta | Cuándo |
|---|---|
201 | El enlace quedó creado. Si había otro enlace vivo para cambiar la clave de esa conexión, queda revocado. |
400 validation_error | La conexión no es de tu organización o no es del SII, el cuerpo trae un campo que no aplica, o la emisión no está habilitada para tu organización. |
409 emision_no_activa | La conexión todavía no emite. Pide un enlace con mode: "activar_emision". |
409 requiere_clave_de_persona | La conexión entra con la clave tributaria de la empresa, que no firma documentos. |
428 connection_credential_required | La credencial de la conexión falta o no sirve. Renuévala primero con mode: "reauth". |
403 connection_disabled | La conexión está pausada. |
Lo que ve tu cliente: quién lo pide, el RUT de la empresa, que la lectura de datos y la emisión siguen igual, y un solo campo para la clave del certificado. Presiona «Guardar clave» y ve «Clave guardada». No ve precios de Emisso.
La clave se comprueba con el próximo documento que emitas. Una clave del certificado solo se puede probar firmando, así que Emisso la guarda sin comprobarla y la verifica en la siguiente vista previa. Si la empresa se equivocó, la vista previa responde sii_signing_material_invalid y puedes pedir otro enlace. Guardar la clave no gasta intentos: el enlace se consume apenas la empresa la guarda.
Para saber que terminó: el webhook connect_session.consumed de ese enlace llega con verified: false, porque la clave todavía no se usó para firmar.
Un agente pide el mismo enlace con conexiones.enlace.crear, modo: "cambiar_clave_certificado" y conexionId. Desde el panel, en los ajustes de la conexión, Clave del certificado digital → Pedir la clave a la empresa.
Modelo de amenaza, en corto
| Riesgo | Qué lo acota |
|---|---|
| Fuerza bruta del token | 256 bits de entropía, búsqueda por igualdad exacta sobre índice único, tope de intentos, expiración corta, el mismo 404 en los cuatro fallos y un limitador de tasa por IP |
| Reuso del enlace | Un solo uso ganado por la base de datos, no por un chequeo previo en código |
| Clickjacking | frame-ancestors por sesión, orígenes exactos, sin comodines, 'none' por defecto |
Exfiltración por postMessage | targetOrigin siempre exacto; el mensaje nunca lleva la credencial ni el token |
| Redirector abierto | redirect_uri obligatoriamente https, sin fragmento, y dentro de allowed_origins cuando los registraste |
| Reenvío del enlace a un tercero | Expiración, un solo uso, tope de intentos y notificación: la fila en la bitácora más este webhook |
El cuadro completo de qué pasa con la credencial una vez entregada (cifrado, aislamiento, revocación) está en seguridad.
El caso plataforma
Para un producto que conecta a muchos clientes finales, el modelo de datos, el alta embebida y los topes que importan a escala.
Activar la emisión con un enlace desde tu sistema
Si integras Emisso en tu producto y tu cliente conectó el SII solo para leer, crea por API un enlace para que escriba la clave del certificado y su conexión pase a emitir. Con demo animada de la llamada y de la pantalla que ve tu cliente.