Emisso Connect

Sincronizar conexión SII

Sincroniza los alcances solicitados (rcv, boletas, guias, boletas_honorarios, documentos) para un período en una sola sesión (un login, un logout).

Tool IDsii.conexion.sincronizar
Nombre MCPsii__conexion__sincronizar
Conectorsii
Planoread
Alcancesrcv, boletas, guias, boletas_honorarios, documentos
Scope (permiso)sii:read
Authconnection_credentials
Versión6
Sensible
Deprecadono
ComportamientoreadOnly=false, destructive=false, idempotent=true, openWorld=true

Requiere conexión. Indica cuál en cada llamada: header X-Connect-Connection en REST, campo connectionId en el execute de MCP y en las opciones del SDK. No hay resolución implícita, ni siquiera con una sola conexión activa: la conexión es la empresa. El id sale de conexiones.estado.consultar.

Entrada

CampoTipoRequeridoDescripción
periodostring ^\d{4}-\d{2}$El mes que se va a sincronizar, en formato AAAA-MM y en calendario chileno (por ejemplo '2026-07'). Traer varios meses son varias llamadas, una por mes.
alcanceslista de "rcv" · "boletas" · "guias" · "boletas_honorarios" · "documentos"Qué módulos de datos traer en esta corrida, al menos uno. Todos se sincronizan sobre UNA sola sesión (un login, un logout), así que pedir varios en una llamada cuesta menos que llamar una vez por cada uno. Un alcance debe estar habilitado en la conexión; si no lo está, la llamada responde 'alcance_not_enabled'.
JSON Schema de entrada
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "periodo": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}$",
      "description": "El mes que se va a sincronizar, en formato AAAA-MM y en calendario chileno (por ejemplo '2026-07'). Traer varios meses son varias llamadas, una por mes."
    },
    "alcances": {
      "minItems": 1,
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "rcv",
          "boletas",
          "guias",
          "boletas_honorarios",
          "documentos"
        ]
      },
      "description": "Qué módulos de datos traer en esta corrida, al menos uno. Todos se sincronizan sobre UNA sola sesión (un login, un logout), así que pedir varios en una llamada cuesta menos que llamar una vez por cada uno. Un alcance debe estar habilitado en la conexión; si no lo está, la llamada responde 'alcance_not_enabled'."
    }
  },
  "required": [
    "periodo",
    "alcances"
  ]
}

Ejemplo

curl
curl -X POST https://connect.emisso.ai/api/v1/tools/sii.conexion.sincronizar/execute \
  -H "Authorization: Bearer connect_sk_…" \
  -H "X-Connect-Connection: conn_9tKfR2mQx4Vb" \
  -H "Content-Type: application/json" \
  -d '{"input":{"periodo":"2026-07","alcances":["rcv","boletas"]}}'
SDK TypeScript
const data = await connect.tools.sii.conexion.sincronizar({ periodo: "2026-07", alcances: ["rcv", "boletas"] }, { connectionId: "conn_9tKfR2mQx4Vb" });
MCP · meta-tool execute
{
  "tool": "sii.conexion.sincronizar",
  "params": {
    "periodo": "2026-07",
    "alcances": [
      "rcv",
      "boletas"
    ]
  },
  "connectionId": "conn_9tKfR2mQx4Vb"
}

Salida esperada (200):

{
  "data": {
    "periodo": "2026-07",
    "results": [
      {
        "alcance": "rcv",
        "status": "ok",
        "recordsSynced": 214,
        "incompletos": 0,
        "completo": true,
        "reconMismatches": 0,
        "dedupCollisions": 0,
        "filasDescartadas": 0
      },
      {
        "alcance": "boletas",
        "status": "ok",
        "recordsSynced": 27
      }
    ]
  },
  "meta": {
    "request_id": "req_…",
    "tool_id": "sii.conexion.sincronizar",
    "plane": "read",
    "latency_ms": 58240,
    "audit_status": "recorded"
  }
}

Todos los alcances pedidos comparten una sola sesión contra el SII: un login al empezar y un logout al final. Los contadores adicionales varían por alcance; 'boletas' solo reporta 'recordsSynced'.

Salida

CampoTipoRequeridoDescripción
periodostringEco del período que se pidió, para poder correlacionar la respuesta sin guardarlo tú.
resultslista de objetoEl resultado de cada alcance pedido, una fila por alcance. Los alcances son independientes: uno puede fallar mientras los otros de la misma corrida terminan bien, así que revisa la lista entera.
results[].alcancestringCuál de los alcances pedidos describe esta fila. Hay una fila por alcance solicitado, en el orden canónico del conector, no en el orden en que los pediste.
results[].status"ok" · "partial" · "failed"'ok' = el alcance terminó bien; que 'recordsSynced' sea 0 no lo vuelve un fallo. 'partial' = trajo datos pero alguna casilla quedó incompleta, y 'incompletos' dice cuántas: lo sincronizado sirve, y reintentar el mismo período más tarde puede completarlo. 'failed' = no terminó bien, y la causa va en 'error'; mira igual 'recordsSynced', porque un 'failed' no garantiza que no se haya escrito nada. Y revisa fila por fila: un alcance puede fallar mientras los otros de la misma corrida terminan bien.
results[].recordsSyncedenteroCuántos registros de este alcance escribió ESTA corrida. Es el trabajo de esta llamada, no el total acumulado que tienes guardado: para saber cuánto hay, consulta. Un 0 no significa por sí solo «no hay datos»; cuando el cero tiene una explicación, viene en 'detalle'.
results[].incompletosenteronoCuántas casillas de este alcance quedaron sin traer. Es lo que vuelve 'partial' al status: lo sincronizado sirve, y reintentar el mismo período más tarde puede completarlo. Una casilla legítimamente vacía no cuenta.
results[].completobooleanono'true' sólo si ninguna casilla de este alcance falló. No alcanza por sí solo para dar el período por cerrado: revísalo junto con 'reconMismatches' y 'filasDescartadas', porque un documento puede faltar por esas dos vías sin que 'completo' se entere.
results[].reconMismatchesenteronoVeces que las filas del detalle no coincidieron con el total que el resumen del SII declaraba. Es observabilidad y no detiene el sync, pero un valor distinto de 0 dice que el período puede estar incompleto.
results[].dedupCollisionsenteronoCuántas filas llegaron repetidas dentro de esta misma corrida (misma clave natural) y se colapsaron en una. No se cuentan dos veces en 'recordsSynced'.
results[].filasDescartadasenteronoFilas que llegaron con una forma inesperada (sin tipo ni folio resoluble) y no se pudieron guardar. Un valor distinto de 0 significa que el alcance corrió entero pero se perdieron filas, aunque 'completo' diga 'true'.
results[].fueraDeVentanaenteronoSólo en 'guias': cuántas direcciones cayeron fuera de la ventana de 6 meses que el SII conserva. No es una falla y el status igual sale 'ok', pero es lo único que distingue 'no había guías' de 'no pudimos verlas'. Reintentar no lo arregla.
results[].perspectivasFallidaslista de objetonoSólo en 'boletas_honorarios': qué direcciones fallaron enteras, con su código de error. Ese alcance la emite siempre, aunque quede vacía; ningún otro la emite.
results[].perspectivasFallidas[].perspectiva"emitidas" · "recibidas"Qué lado falló: 'emitidas' son las que emitió esta empresa y 'recibidas' las que le emitieron.
results[].perspectivasFallidas[].codestringEl código del catálogo de errores que explica por qué falló ese lado. Decide por el código, nunca por el texto.
results[].totalenteronoSólo en 'documentos': cuántos DTE anunció el índice del SII para el período. Es lo ESPERADO, no lo descargado.
results[].ventanasenteronoSólo en 'documentos': cuántas ventanas de descarga (hasta 20 folios cada una) hicieron falta para bajar el período.
results[].documentosenteronoSólo en 'documentos': cuántos DTE se descargaron de verdad. Compáralo con 'total': la diferencia es 'faltantes'.
results[].faltantesenteronoSólo en 'documentos': cuántos DTE prometió el índice y la descarga no trajo. Es lo que distingue un hueco del SII de un hueco nuestro; lo que sí bajó se guarda igual.
results[].sinIndiceenteronoSólo en 'documentos': cuántos DTE se descargaron sin que su clave apareciera en el índice del listado. Significa que el índice quedó corto, distinto de que la fila no trajera estado (eso llega como 'estado' en null).
results[].hashMismatchesenteronoSólo en 'documentos': cuántos documentos repetidos traían un XML distinto. Un DTE firmado es inmutable, así que un valor distinto de 0 es una anomalía para reportar, nunca un documento que cambió.
results[].errorstringnoPor qué este alcance no terminó bien. Presente solo cuando 'status' es 'failed'. Normalmente es un código del catálogo de errores; cuando el sistema externo truncó el listado es una etiqueta de resultado ('movimientos_truncated', 'cartolas_truncated') que no está en ese catálogo y que significa «se escribió lo que alcanzó a venir». Decide por el valor, nunca por el texto libre.
JSON Schema de salida
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "periodo": {
      "type": "string",
      "description": "Eco del período que se pidió, para poder correlacionar la respuesta sin guardarlo tú."
    },
    "results": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "alcance": {
            "type": "string",
            "description": "Cuál de los alcances pedidos describe esta fila. Hay una fila por alcance solicitado, en el orden canónico del conector, no en el orden en que los pediste."
          },
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "partial",
              "failed"
            ],
            "description": "'ok' = el alcance terminó bien; que 'recordsSynced' sea 0 no lo vuelve un fallo. 'partial' = trajo datos pero alguna casilla quedó incompleta, y 'incompletos' dice cuántas: lo sincronizado sirve, y reintentar el mismo período más tarde puede completarlo. 'failed' = no terminó bien, y la causa va en 'error'; mira igual 'recordsSynced', porque un 'failed' no garantiza que no se haya escrito nada. Y revisa fila por fila: un alcance puede fallar mientras los otros de la misma corrida terminan bien."
          },
          "recordsSynced": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Cuántos registros de este alcance escribió ESTA corrida. Es el trabajo de esta llamada, no el total acumulado que tienes guardado: para saber cuánto hay, consulta. Un 0 no significa por sí solo «no hay datos»; cuando el cero tiene una explicación, viene en 'detalle'."
          },
          "incompletos": {
            "description": "Cuántas casillas de este alcance quedaron sin traer. Es lo que vuelve 'partial' al status: lo sincronizado sirve, y reintentar el mismo período más tarde puede completarlo. Una casilla legítimamente vacía no cuenta.",
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "completo": {
            "description": "'true' sólo si ninguna casilla de este alcance falló. No alcanza por sí solo para dar el período por cerrado: revísalo junto con 'reconMismatches' y 'filasDescartadas', porque un documento puede faltar por esas dos vías sin que 'completo' se entere.",
            "type": "boolean"
          },
          "reconMismatches": {
            "description": "Veces que las filas del detalle no coincidieron con el total que el resumen del SII declaraba. Es observabilidad y no detiene el sync, pero un valor distinto de 0 dice que el período puede estar incompleto.",
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "dedupCollisions": {
            "description": "Cuántas filas llegaron repetidas dentro de esta misma corrida (misma clave natural) y se colapsaron en una. No se cuentan dos veces en 'recordsSynced'.",
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "filasDescartadas": {
            "description": "Filas que llegaron con una forma inesperada (sin tipo ni folio resoluble) y no se pudieron guardar. Un valor distinto de 0 significa que el alcance corrió entero pero se perdieron filas, aunque 'completo' diga 'true'.",
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "fueraDeVentana": {
            "description": "Sólo en 'guias': cuántas direcciones cayeron fuera de la ventana de 6 meses que el SII conserva. No es una falla y el status igual sale 'ok', pero es lo único que distingue 'no había guías' de 'no pudimos verlas'. Reintentar no lo arregla.",
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "perspectivasFallidas": {
            "description": "Sólo en 'boletas_honorarios': qué direcciones fallaron enteras, con su código de error. Ese alcance la emite siempre, aunque quede vacía; ningún otro la emite.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "perspectiva": {
                  "type": "string",
                  "enum": [
                    "emitidas",
                    "recibidas"
                  ],
                  "description": "Qué lado falló: 'emitidas' son las que emitió esta empresa y 'recibidas' las que le emitieron."
                },
                "code": {
                  "type": "string",
                  "description": "El código del catálogo de errores que explica por qué falló ese lado. Decide por el código, nunca por el texto."
                }
              },
              "required": [
                "perspectiva",
                "code"
              ],
              "additionalProperties": false
            }
          },
          "total": {
            "description": "Sólo en 'documentos': cuántos DTE anunció el índice del SII para el período. Es lo ESPERADO, no lo descargado.",
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "ventanas": {
            "description": "Sólo en 'documentos': cuántas ventanas de descarga (hasta 20 folios cada una) hicieron falta para bajar el período.",
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "documentos": {
            "description": "Sólo en 'documentos': cuántos DTE se descargaron de verdad. Compáralo con 'total': la diferencia es 'faltantes'.",
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "faltantes": {
            "description": "Sólo en 'documentos': cuántos DTE prometió el índice y la descarga no trajo. Es lo que distingue un hueco del SII de un hueco nuestro; lo que sí bajó se guarda igual.",
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "sinIndice": {
            "description": "Sólo en 'documentos': cuántos DTE se descargaron sin que su clave apareciera en el índice del listado. Significa que el índice quedó corto, distinto de que la fila no trajera estado (eso llega como 'estado' en null).",
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "hashMismatches": {
            "description": "Sólo en 'documentos': cuántos documentos repetidos traían un XML distinto. Un DTE firmado es inmutable, así que un valor distinto de 0 es una anomalía para reportar, nunca un documento que cambió.",
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "error": {
            "description": "Por qué este alcance no terminó bien. Presente solo cuando 'status' es 'failed'. Normalmente es un código del catálogo de errores; cuando el sistema externo truncó el listado es una etiqueta de resultado ('movimientos_truncated', 'cartolas_truncated') que no está en ese catálogo y que significa «se escribió lo que alcanzó a venir». Decide por el valor, nunca por el texto libre.",
            "type": "string"
          }
        },
        "required": [
          "alcance",
          "status",
          "recordsSynced"
        ],
        "additionalProperties": false
      },
      "description": "El resultado de cada alcance pedido, una fila por alcance. Los alcances son independientes: uno puede fallar mientras los otros de la misma corrida terminan bien, así que revisa la lista entera."
    }
  },
  "required": [
    "periodo",
    "results"
  ],
  "additionalProperties": false
}

Errores de esta tool

CódigoHTTPReintentableQué hacer
connection_disabled403noReactívala en /connections o usa otra conexión del mismo sistema.
connection_credential_required428noCrea un enlace con conexiones.enlace.crear (modo reconectar si la conexión ya existe) y pide a la persona que entregue la credencial de nuevo. No reintentes con la credencial anterior.
connection_busy409Espera unos segundos y reintenta. El candado es por conexión y se suelta solo.
upstream_error502Reintenta más tarde. Si persiste, el problema está en el sistema externo, no en tu integración.
timeout504Reintenta. Para sincronizaciones largas usa la vía asíncrona y consulta el estado del trabajo.
connection_sync_in_progress409Espera a que termine y reintenta, o consulta directamente: puede que ya haya datos.
too_many_pending429Deja terminar los trabajos en curso antes de encolar más.

Toda llamada puede devolver además los códigos transversales (validation_error, unauthorized, scope_not_granted, rate_limited, entre otros): el detalle vive en el catálogo de errores.

Próximos pasos

On this page