This is the abridged 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). | ## 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. ## 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. | ## 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. | ## 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.