Tu primera factura al SRI por API: el recorrido completo, de la cuenta al RIDE
Tienes un checkout que ya cobra y quieres que, al confirmarse el pago, salga la factura electrónica autorizada por el SRI sin que nadie abra un panel. Desde el 1 de enero de 2026, con la Resolución NAC-DGERCGC25-00000017, esa factura viaja al SRI en el momento de emitirla: ya no hay lote nocturno donde esconder un error de integración.
Este artículo es el recorrido entero, en el orden real en que hay que hacerlo:
crear la cuenta, generar la API key, registrar el emisor con su establecimiento
y su punto de emisión, subir el certificado .p12, emitir la factura, esperar
la autorización y descargar el RIDE. Todo contra el ambiente de Pruebas del
SRI, que no consume el cupo de tu plan.
Ojo: para emitir en Pruebas necesitas un RUC real y un certificado
.p12real. No hay un certificado de pruebas compartido: el ambiente de Pruebas es el del propio SRI y firma con tu certificado, igual que Producción. Lo único que cambia es que los comprobantes no tienen validez tributaria.
Pruebas y Producción son el mismo código con un campo distinto
Cada cuenta emite contra un ambiente y se cambia con un PATCH. Lo que
certificas en Pruebas es exactamente lo que emitirás en Producción.
Pruebas (ambienteActivo: 1) |
Producción (ambienteActivo: 2) |
|
|---|---|---|
| Validez tributaria | No | Sí |
| Cupo de tu plan | No lo consume (tope propio de 500/mes) | Lo consume |
| Firma | Tu .p12 |
Tu .p12 |
Con el plan gratuito emites 10 comprobantes de Producción al mes, sin tarjeta. Los 500 de Pruebas van aparte, así que puedes integrar sin gastar nada.
Paso 1: la cuenta se crea con un POST público
POST /tenants/register es de los pocos endpoints que no piden token. Crea la
cuenta y su usuario owner en plan free, y devuelve el par de tokens JWT.
API=https://contadeo.com/api
curl -X POST $API/tenants/register -H 'content-type: application/json' \
-d '{"nombre":"Mi Empresa","email":"yo@empresa.ec","password":"secreta123",
"ruc":"0912345675001","declaraTitularidadRuc":true,
"aceptaPrivacidad":true,"aceptaTerminos":true}'
Los cuatro campos que la gente olvida: ruc (con dígito verificador válido) y
declaraTitularidadRuc, más aceptaPrivacidad y aceptaTerminos, que son el
consentimiento LOPDP del aviso de privacidad. Sin cualquiera de
ellos la respuesta es 400. El slug no se envía: lo genera el sistema. El
registro está limitado a 5 altas por IP cada 10 minutos; al pasarte recibes 429.
Paso 2: la API key se genera en el panel, no por API
Aquí es donde muchas integraciones se atascan buscando un endpoint que no existe: no hay una ruta pública para crear API keys. Se generan en el panel, en Configuración → API, con rol owner o admin, y la key se muestra una sola vez.
Lo que sí conviene saber antes de crearla:
- Se envía como
Authorization: Bearer cdo_...y no expira ni necesita refresh: es la credencial de tu servidor. - Sus permisos son acotados por diseño. Puede llevar los roles
emisor,contador,lectorywebhooks(por defecto,emisor), pero nunca owner ni admin: una key filtrada no puede tocar usuarios, otras keys ni la configuración de la cuenta. - Hasta 5 keys activas por cuenta, y la revocación desde el panel es inmediata (quien la use recibe 401 al instante).
Para el resto del recorrido, TOKEN es esa key.
Paso 3: emisor, establecimiento y punto de emisión
El emisor es el RUC que factura. Debajo cuelgan el establecimiento y el punto de
emisión, que son los dos primeros bloques del número de comprobante
(001-001-000000001).
curl -X POST $API/emisores -H "authorization: Bearer $TOKEN" \
-H 'content-type: application/json' \
-d '{"ruc":"0912345675001","razonSocial":"MI EMPRESA S.A.",
"dirMatriz":"Av. Principal 123, Guayaquil",
"obligadoContabilidad":false,"regimen":"GENERAL"}'
# regimen: GENERAL | RIMPE_EMPRENDEDOR | RIMPE_NEGOCIO_POPULAR
# El dígito verificador del RUC se valida aquí → 400 si es inválido.
curl -X POST $API/emisores/$EMISOR_ID/establecimientos \
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"codigo":"001","direccion":"Matriz centro","nombre":"Matriz"}'
El codigo es de exactamente 3 dígitos, igual para el punto de emisión
(POST /establecimientos/:estabId/puntos-emision).
Consejo: si ese RUC ya facturaba con otro sistema, sincroniza el secuencial antes de emitir con
PATCH /emisores/:emisorId/secuenciales(ultimoNumero= el último número ya usado). Si no lo haces, Contadeo se autorecupera reemitiendo, pero verás el error 45 del SRI («secuencial registrado») hasta alcanzar el número bueno.
Paso 4: el .p12 sube como JSON en base64
El certificado de firma no va como multipart: va como un campo más del JSON,
en base64, junto con su contraseña.
curl -X POST $API/certificados -H "authorization: Bearer $TOKEN" \
-H 'content-type: application/json' \
-d "{\"emisorId\":\"$EMISOR_ID\",
\"p12Base64\":\"$(base64 -w0 certificado.p12)\",
\"passphrase\":\"<contraseña del .p12>\",\"alias\":\"firma 2026\",
\"declaraTitularidadFirma\":true}"
# → { "id": "<certificadoId>", "subject": "...", "notAfter": "2029-..." }
El archivo y su contraseña se cifran con envelope AES-256-GCM y solo se
descifran en memoria en el momento de firmar. El GET /certificados nunca
devuelve material secreto.
Paso 5: la factura responde 202, no 200
La emisión es asíncrona. El POST valida el cuadre, reserva el secuencial de
forma atómica, genera la clave de acceso de 49 dígitos y encola la firma y la
transmisión. Por eso responde 202 con el comprobante en BORRADOR.
Manda siempre Idempotency-Key con un identificador tuyo —el id del pedido, por
ejemplo—: si el request se corta y reintentas, recibes el mismo comprobante en
vez de duplicarlo y quemar otro secuencial.
curl -s -X POST $API/comprobantes/factura \
-H "authorization: Bearer $TOKEN" \
-H "Idempotency-Key: pedido-8841" \
-H 'content-type: application/json' -d '{
"emisorId":"'$EMISOR_ID'","certificadoId":"'$CERT_ID'",
"establecimiento":"001","puntoEmision":"001",
"infoFactura":{
"tipoIdentificacionComprador":"05",
"razonSocialComprador":"JUAN PEREZ","identificacionComprador":"1745678902",
"obligadoContabilidad":"NO",
"totalSinImpuestos":10,"totalDescuento":0,
"totalConImpuestos":[{"codigo":"2","codigoPorcentaje":"4",
"baseImponible":10,"tarifa":15,"valor":1.5}],
"importeTotal":11.5,"pagos":[{"formaPago":"01","total":11.5}]},
"detalles":[{"descripcion":"Producto","cantidad":1,"precioUnitario":10,
"descuento":0,"precioTotalSinImpuesto":10,
"impuestos":[{"codigo":"2","codigoPorcentaje":"4","tarifa":15,
"baseImponible":10,"valor":1.5}]}]
}'
# → { "comprobanteId": "uuid", "claveAcceso": "49 dígitos", "estado": "BORRADOR" }
Ese cuerpo son $10.00 + 15 % de IVA = $11.50. El IVA general del 15 % es
codigo: "2" con codigoPorcentaje: "4". La fechaEmision no se envía: la fija
el servidor en hora de Ecuador.
Si los totales no cuadran, la respuesta es 400 con la lista de problemas[]
antes de tocar al SRI. Es la diferencia entre enterarte en el mismo request y
enterarte tres minutos después por un rechazo.
Paso 6: consulta hasta AUTORIZADO y descarga el RIDE
El comprobante recorre BORRADOR → FIRMADO → ENVIADO → AUTORIZADO. Haz polling
de GET /comprobantes/:id cada ~3 segundos hasta un estado terminal
(AUTORIZADO, RECHAZADO o DEVUELTA); el SRI suele resolver en 5 a 30
segundos.
curl -s $API/comprobantes/$ID -H "authorization: Bearer $TOKEN"
# → { "estado": "AUTORIZADO", "claveAcceso": "...", "numeroAutorizacion": "..." }
curl -s $API/comprobantes/$ID/ride -H "authorization: Bearer $TOKEN" # {"url": ...}
curl -s $API/comprobantes/$ID/xml -H "authorization: Bearer $TOKEN" # {"url": ...}
El RIDE (PDF) y el XML autorizado vuelven como URLs prefirmadas que expiran en 1
hora. Si el comprobante termina en DEVUELTA o RECHAZADO, la respuesta incluye
mensajesSri con los mensajes literales del SRI, para mostrar la razón sin
adivinar.
Cuando la integración pase de prototipo a producto, cambia el polling por
webhooks firmados: un POST a tu servidor cuando el
comprobante llega a estado final.
Preguntas frecuentes
¿Necesito RUC y firma electrónica para probar la API?
Sí, los dos, incluso en Pruebas. El ambiente de Pruebas es el del SRI y firma
con tu certificado .p12; no hay uno compartido para desarrolladores. Lo que no
necesitas es tarjeta: el plan gratuito y los 500 comprobantes de Pruebas al mes
cubren la integración.
¿Puedo crear la API key por API? No. Se genera en el panel, en Configuración → API, con rol owner o admin, y se muestra una sola vez. Es deliberado: la credencial de máquina no se emite desde la máquina.
¿Qué pasa si reintento el mismo POST de factura?
Con la misma Idempotency-Key recibes el mismo comprobante marcado
reutilizado: true, sin duplicar ni quemar secuencial. La clave no caduca, y si
llega con un cuerpo distinto la respuesta es 422 en vez de un comprobante que no
corresponde.
¿Cómo paso a Producción?
PATCH /tenants/current con {"ambienteActivo": 2}, o un clic en el panel,
cuando tu RUC ya certificó en Pruebas los tipos de comprobante que vas a emitir.
Desde ese momento son documentos tributarios reales.
Cómo empezar
Crea tu cuenta gratis —10 comprobantes al mes, sin tarjeta— y haz el recorrido completo en el ambiente de Pruebas. La documentación para integradores trae los seis tipos de comprobante con sus cuerpos, y la referencia OpenAPI tiene cada endpoint con sus esquemas y errores. Si prefieres generar el cliente, el spec descargable y el SDK oficial para TypeScript te ahorran el trabajo.
Contadeo — Facturación electrónica del SRI (Ecuador) por API, panel o IA. Documentación de la API · Matriz de capacidades · Crea tu cuenta