This is the full developer documentation for Firma Digital Partner APIs
# Documentación de Firma Digital
> Documentación para integrar Firma Digital como partner — generación de códigos de compra, canje de identidad, emisión de certificados, y el widget de onboarding embebible.
## Empieza aquí
[Sección titulada «Empieza aquí»](#empieza-aquí)
[API de PartnersEl flujo completo: generar un código de compra, canjearlo (con o sin Clave Única según tu configuración), y obtener el certificado emitido.](/guides/partner-api-guide/)[Referencia de la APICada endpoint de la API de Partners y de la API de Códigos de Compra, con schemas y ejemplos.](/api/partners/)[Widget de OnboardingIncorpora el flujo de emisión de Firma Digital en tu sitio como un Web Component embebible.](/guides/widget-guide/)
## Documentación lista para agentes de IA
[Sección titulada «Documentación lista para agentes de IA »](#documentación-lista-para-agentes-de-ia)
Todo el contenido se publica también como Markdown plano, `llms.txt` y OpenAPI, para que un LLM o un agente de desarrollo pueda leer la documentación completa sin ejecutar JavaScript.
[Cómo usar estos docs con IAQué formato conviene según tu herramienta, y cómo apuntar un agente a esta documentación.](/ai/)[llms.txtEl índice del sitio en el formato estándar de llmstxt.org.](/llms.txt)
# Página no encontrada
> La página que buscas no existe o cambió de dirección. Usa el buscador o vuelve al inicio. — The page you are looking for doesn't exist or has moved. Try the search or head back home.
# Documentación para agentes de IA
> Cómo consumir esta documentación desde un LLM, un agente de desarrollo o cualquier herramienta automatizada.
Esta documentación está pensada para que la lean tanto personas como agentes de IA. Todo el contenido se genera como HTML estático y Markdown plano.
## Qué formato conviene usar
[Sección titulada «Qué formato conviene usar»](#qué-formato-conviene-usar)
| Formato | Úsalo cuando… |
| ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Markdown por página** — p. ej. [`/guides/partner-api-guide.md`](/guides/partner-api-guide.md) | Quieres pasarle a un LLM una sola página, o copiarla al chat sin el ruido del HTML. |
| [**`/llms.txt`**](/llms.txt) | Quieres que el agente primero descubra qué contiene el sitio y después decida qué leer. Es el índice según el estándar [llmstxt.org](https://llmstxt.org/). |
| [**`/llms-full.txt`**](/llms-full.txt) | Quieres cargar todas las guías completas en el contexto de una sola vez. |
| [**`/llms-small.txt`**](/llms-small.txt) | Lo mismo, pero en versión reducida para modelos con ventana de contexto chica. |
| [**OpenAPI 3.0**](/openapi/partner-api-es.json) | Tu herramienta entiende OpenAPI: es la fuente de verdad de la referencia de API (endpoints, schemas y autenticación). Hay dos specs — [API de Partners](/openapi/partner-api-es.json) y [API de Códigos de Compra](/openapi/pcode-worker-es.json) — también disponibles [en inglés](/openapi/partner-api-en.json). |
Cómo se reparte el contenido
`llms-full.txt` contiene las **guías**. La **referencia de API** no se duplica ahí: para eso están las especificaciones OpenAPI, que ya son machine-readable y siempre están sincronizadas con la documentación publicada.
## Markdown de cada página
[Sección titulada «Markdown de cada página»](#markdown-de-cada-página)
Cada página de guía se publica también como Markdown plano: agrega `.md` a su ruta.
```plaintext
https://docs.firma.digital/guides/partner-api-guide.md
https://docs.firma.digital/en/guides/partner-api-guide.md
```
Además, arriba de cada guía hay botones para **copiar el Markdown** al portapapeles, **verlo** en crudo, o abrir esa página directamente en **ChatGPT**, **Claude** o **Gemini** con el contexto ya cargado.
## Cómo apuntar un agente a esta documentación
[Sección titulada «Cómo apuntar un agente a esta documentación»](#cómo-apuntar-un-agente-a-esta-documentación)
Para un asistente con acceso a internet, el punto de entrada recomendado es `llms.txt`:
```text
Lee https://docs.firma.digital/llms.txt y luego los documentos que necesites
de ahí para ayudarme a integrar la API de partners de Firma Digital.
```
Si va a generar código contra la API, conviene darle directamente la especificación OpenAPI:
```text
Usa https://docs.firma.digital/openapi/partner-api-es.json como referencia
de la API de Partners de Firma Digital y ayúdame a implementar el flujo de
canje.
```
## Autenticación
[Sección titulada «Autenticación»](#autenticación)
Cualquier código que genere un agente necesita autenticarse. Todas las peticiones a las APIs llevan la API Key en el header `x-gw`:
```http
x-gw: {TU_API_KEY}
Content-Type: application/json
```
El flujo completo está en la [Guía de Integración — API de Partners](/guides/partner-api-guide/).
# Guía de Integración — API de Partners
> Flujo completo para integrar Firma Digital como partner — emitir códigos de compra, canjear identidad, y obtener el certificado.
Esta guía cubre el ciclo de vida completo de un código de compra: emitirlo, canjearlo (validar la identidad del titular), y obtener el certificado ya emitido. Hay dos APIs separadas, en dos servidores distintos:
* **API de Códigos de Compra** (`partner-pcode`, Cloudflare Worker, `/api/partner/v1`) — genera y lista códigos de compra.
* **API de Partners** (`/api/partners/v1`) — canjea identidad y entrega certificados.
Autenticación
Ambas APIs se autentican igual: header `x-gw` con tu API Key.
```http
x-gw: {TU_API_KEY}
Content-Type: application/json
```
Ambientes
Los ejemplos de esta guía usan las URLs de **producción**. Para probar en desarrollo, reemplazá la URL base:
| API | Desarrollo | Producción |
| ------------------------ | ---------------------------------------------------------- | ------------------------------------------------------ |
| API de Partners | `https://dev-api.tsp.cl/firma_digital/dev/api/partners/v1` | `https://api.firma.digital/api/partners/v1` |
| API de Códigos de Compra | `https://partner-pcode-dev.tsp.workers.dev/api/partner/v1` | `https://partner-pcode.tsp.workers.dev/api/partner/v1` |
Ambas URLs también están listadas en el selector de servidor de la [Referencia de la API](/api/partners/).
## 1. Tu configuración determina el flujo, no el endpoint
[Sección titulada «1. Tu configuración determina el flujo, no el endpoint»](#1-tu-configuración-determina-el-flujo-no-el-endpoint)
A diferencia de versiones anteriores de esta API, **hay un solo endpoint de canje** (`certificate_request`). Su comportamiento se ajusta automáticamente según tu configuración de partner:
| Tu configuración | Qué pasa en `certificate_request` |
| ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `require_cedula_serie = 0` (flujo completo, default) | Debes enviar `names`/`fLastname`/`phone`. Se valida contra Clave Única además de Registro Civil. |
| `require_cedula_serie = 1` (flujo reducido) | **No** envíes `names`/`fLastname`/`phone` — se obtienen de Registro Civil. Debes enviar `serialNumber` (serie de la cédula). Sin Clave Única. |
| `mode = 1` (B2C, default) | El certificado se entrega recién cuando llames `certificate_claim`. |
| `mode = 2` (B2B) | El certificado se genera y se entrega automático (webhook/email) en la misma llamada a `certificate_request` — **no llames `certificate_claim`**, siempre te va a responder “ya emitido”. |
Estos dos ajustes son independientes entre sí — puedes tener flujo reducido + B2B, flujo completo + B2C, o cualquier otra combinación. Contacta a soporte para configurarlos.
## 2. Flujo B2C (el más común)
[Sección titulada «2. Flujo B2C (el más común)»](#2-flujo-b2c-el-más-común)
1. **Emitir un código de compra** — `POST /pcode` en la API de Códigos de Compra.
```bash
curl -X POST https://partner-pcode.tsp.workers.dev/api/partner/v1/pcode \
-H "x-gw: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"productCode": "FV01", "external_reference_id": "orden-12345"}'
```
Esta llamada puede fallar con `400` si tu partner no tiene ese `productCode` habilitado — cada partner puede tener restringido a qué productos (`FV00`-`FV03`) tiene acceso. Si no te queda claro qué productos tenés habilitados, contactá a soporte.
2. **Canjear el código de compra** — `POST /certificate_request`. Los campos varían según tu flujo (ver tabla arriba). Ejemplo con flujo reducido:
```bash
curl -X POST https://api.firma.digital/api/partners/v1/certificate_request \
-H "x-gw: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"pCode": "MIPARTNER-26-FV01-A1B2C3D4",
"referenceId": "orden-12345",
"dni": "18925910-7",
"serialNumber": "536463312",
"email": "usuario@ejemplo.com",
"pin": "1234"
}'
```
La respuesta trae `status: "VALIDATED"` — el certificado **todavía no existe**, solo se verificó la identidad.
3. **Obtener el certificado** — `POST /certificate_claim`, con el mismo `pin` usado en el paso anterior (funciona como contraseña del PFX).
```bash
curl -X POST https://api.firma.digital/api/partners/v1/certificate_claim \
-H "x-gw: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"p_code": "MIPARTNER-26-FV01-A1B2C3D4", "dni": "18925910-7", "pin": "1234"}'
```
Esta llamada es **de una sola vez**: si la repites, responde `201` con `ALREADY_ISSUED` en vez de regenerar el certificado. Si necesitas recuperarlo después de reclamado, contacta a soporte.
## 3. Flujo B2B
[Sección titulada «3. Flujo B2B»](#3-flujo-b2b)
Igual al paso 1 y 2 de arriba, pero el paso 2 ya es el último: si tu configuración tiene `mode = 2`, la respuesta de `certificate_request` viene con `status: "EMITTED"` y el certificado se entrega automáticamente por el webhook y/o email que tengas configurado — pueden ser ambos a la vez, no es uno u otro. No hay paso 3.
La entrega es asíncrona respecto a la respuesta
El certificado ya queda persistido antes de que te respondamos, pero la entrega efectiva (webhook/email) ocurre **después** de que recibiste la respuesta `200`. Si tu integración depende de recibir el certificado, no asumas que llegó solo porque la llamada a `certificate_request` fue exitosa — si el webhook falla, no hay forma de saberlo desde esa misma respuesta. Usá `GET /status` como respaldo para confirmar del lado del servidor que quedó `emitido`.
## 4. Consultar estado
[Sección titulada «4. Consultar estado»](#4-consultar-estado)
`GET /status?p_code=...` — útil sobre todo si integraste vía **widget** (el usuario completa el flujo en su navegador, no en una sola llamada tuya) y necesitas saber en qué va sin escuchar los eventos del widget en tiempo real.
```bash
curl "https://api.firma.digital/api/partners/v1/status?p_code=MIPARTNER-26-FV01-A1B2C3D4" \
-H "x-gw: $API_KEY"
```
Estados posibles, en orden de precedencia (el primero que aplica gana):
| Estado | Significa |
| --------------- | ----------------------------------------------------------------------------------------------------- |
| `CANCELLED` | Anulado (orden cancelada) — gana incluso sobre un certificado ya emitido. |
| `EXPIRED` | El certificado se emitió pero ya venció. |
| `EMITTED` | Certificado generado y entregado. |
| `LOCKED` | Bloqueado antes de llegar a emitirse — si ya se había emitido, no aparece: sigue mostrando `EMITTED`. |
| `IN_ONBOARDING` | El usuario está a mitad del flujo del widget. |
| `VALIDATED` | Identidad verificada (solo B2C), falta llamar `certificate_claim`. |
| `ACTIVE` | Existe, nadie lo canjeó todavía. |
| `NOT_FOUND` | El código de compra no existe. |
Nota
`VALIDATED` e `IN_ONBOARDING` describen pasos previos a que exista un certificado — todavía no forman parte del enum `status` del modelo de datos unificado hacia el que se está migrando (ver `purchase_codes.status` en `MODELO_BD.md`), que hoy solo cubre `ACTIVE, LOCKED, CANCELLED, DOWNLOADED, CENTRALIZED, EMITTED, EXPIRED, REVOKED, SUSPENDED`. Se usan igual acá porque describen algo real que un partner necesita distinguir.
## 5. Errores comunes
[Sección titulada «5. Errores comunes»](#5-errores-comunes)
| Código | Causa |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `401` | API Key inválida o ausente. |
| `404` | El código de compra no existe (o, en `certificate_claim`, existe pero nunca pasó por `certificate_request`). |
| `406` | Rechazo de negocio — el mensaje (`message`) indica cuál: serie requerida, RUT no coincide, email duplicado, cédula no coincide con Registro Civil, fecha de vencimiento no coincide, etc. |
| `423` | El código de compra está bloqueado de forma permanente (anulado). |
| `429` | Rate limit — 10 emisiones por minuto por partner, o intentos de validación de cédula agotados (bloqueo de seguridad temporal). |
Ver la [Referencia de la API de Partners](/api/partners/) y la [Referencia de la API de Códigos de Compra](/api/pcode/) para el detalle completo de cada endpoint.
# Guía de Integración — Widget de Onboarding
> Cómo embeber el flujo de emisión de Firma Digital como un Web Component en tu sitio.
El widget de onboarding es un [Web Component](https://developer.mozilla.org/es/docs/Web/API/Web_components) autocontenido (``) que corre todo el flujo de emisión — desde ingresar el código de compra hasta descargar el certificado — dentro de la página de tu sitio, sin iframes. La integración con partners es exclusivamente vía este Web Component.
## 1. Cargar el widget
[Sección titulada «1. Cargar el widget»](#1-cargar-el-widget)
1. Agregá el `
```
2. Agregá el elemento donde quieras que aparezca el formulario:
```html
```
Si no tenés un código de compra todavía para probar, generalo primero con la [API de Códigos de Compra](/guides/partner-api-guide/#2-flujo-b2c-el-m%C3%A1s-com%C3%BAn).
### Atributos
[Sección titulada «Atributos»](#atributos)
| Atributo | Requerido | Descripción |
| ----------- | --------- | ------------------------------------------------------------------------------- |
| `partner` | Sí | Tu nombre de partner (el mismo que usás como identidad de partner en las APIs). |
| `p_code` | Sí | El código de compra a canjear. |
| `returnurl` | No | A dónde redirigir cuando el usuario termina el flujo completo. |
Probalo antes de integrar
Podés cargar el widget contra un p\_code real de tu ambiente de desarrollo con la página de prueba en [`test-widget-harness`](https://test-widget-harness.tsp.workers.dev) — pega tu código de compra y partner ahí para ver el flujo completo y los eventos que emite, sin tocar tu propio sitio todavía.
## 2. Escuchar eventos
[Sección titulada «2. Escuchar eventos»](#2-escuchar-eventos)
El widget notifica su progreso vía [`CustomEvent`](https://developer.mozilla.org/es/docs/Web/API/CustomEvent) sobre el propio elemento — no hace falta un iframe ni `postMessage`, porque vive en el mismo documento que tu página.
```js
const widget = document.querySelector('firmadigital-onboarding');
widget.addEventListener('onboarding:ready', (e) => {
console.log('Widget listo', e.detail); // { height }
});
widget.addEventListener('onboarding:stepChange', (e) => {
console.log('Paso actual', e.detail); // { step, total }
});
widget.addEventListener('onboarding:complete', (e) => {
console.log('Flujo completado', e.detail);
});
widget.addEventListener('onboarding:error', (e) => {
console.error('Error en el widget', e.detail);
});
```
| Evento | Cuándo se dispara |
| ------------------------ | --------------------------------------------------------------------- |
| `onboarding:ready` | El widget terminó de cargar y renderizar. |
| `onboarding:stepChange` | El usuario avanzó de paso (identidad → datos personales → seguridad). |
| `onboarding:complete` | El usuario terminó el flujo completo. |
| `onboarding:error` | Ocurrió un error durante el flujo. |
| `onboarding:download` | El usuario descargó su certificado. |
| `onboarding:emailCopy` | El usuario pidió reenviar una copia por email. |
| `onboarding:centralized` | El usuario centralizó su firma en el SII. |
Si preferís no depender de eventos en tiempo real (por ejemplo, para un dashboard interno de soporte), podés consultar el estado de cualquier código de compra en cualquier momento con [`GET /status`](/api/partners/#operation/getStatus) de la API de Partners.
## 3. Modo widget vs. sitio standalone
[Sección titulada «3. Modo widget vs. sitio standalone»](#3-modo-widget-vs-sitio-standalone)
El widget ajusta su propia UI cuando detecta que corre embebido (sin el “confetti” de celebración, sin el panel de recomendaciones al final, con navegación que no le escribe hash a la URL de tu sitio) — no hace falta ninguna configuración extra de tu parte para esto, es automático.
## Siguiente paso
[Sección titulada «Siguiente paso»](#siguiente-paso)
Si tu integración es B2B (`mode = 2` en tu configuración de partner), probablemente no necesites el widget en absoluto — el certificado se emite y entrega automático vía la [API de Partners](/guides/partner-api-guide/#3-flujo-b2b) sin que el usuario final tenga que interactuar con nada.