Inicio
El API HTTP REST de Factuplan te permite integrar facturación electrónica autorizada por el SRI del Ecuador desde cualquier lenguaje o plataforma: PHP, Python, Go, .NET, Ruby, Bash + cURL, etc.
- Base URL:
https://api.factuplan.com.ec - Versionado por path: todos los endpoints viven bajo
/v1/developer/*. - Respuestas siempre JSON con sobre
{ data, meta }. - Dos entornos: pruebas (
ak_test_*) y producción (ak_live_*). - Compatible con Postman: descarga la colección oficial.
Importante: los comprobantes creados con una API key de pruebas se eliminan automáticamente cada hora. Usa pruebas solo para desarrollo.
Instalación
No hay nada que instalar — el API se consume con cualquier cliente HTTP.
Crear una API key
- Inicia sesión en app.factuplan.com.ec.
- Anda a Developer → Create API key.
- Copia la clave generada — solo se muestra una vez.
- Guárdala en una variable de entorno (
FACTUPLAN_API_KEY), nunca la subas al repositorio.
Las API keys son por workspace. El prefijo indica el entorno:
| Prefijo | Entorno | Comportamiento |
|---|---|---|
ak_test_* | Pruebas | Comprobantes ficticios, eliminados cada hora |
ak_live_* | Producción | Comprobantes reales firmados y enviados al SRI |
Prueba rápida con cURL
curl https://api.factuplan.com.ec/v1/developer/usage \
-H "X-API-Key: $FACTUPLAN_API_KEY" \
-H "Accept: application/json"Autenticación
Todas las peticiones requieren dos cabeceras:
| Cabecera | Valor | Notas |
|---|---|---|
X-API-Key | Tu API key (ak_test_* o ak_live_*) | Identifica el workspace y el plan. |
x-taxpayer-ruc | RUC del contribuyente emisor (13 dígitos) | Requerida cuando la operación emite o consulta comprobantes. |
curl https://api.factuplan.com.ec/v1/developer/invoices \
-H "X-API-Key: $FACTUPLAN_API_KEY" \
-H "x-taxpayer-ruc: 0950194407001" \
-H "Content-Type: application/json" \
-d @factura.jsonSeguridad: nunca expongas tu API key en el frontend. Úsala solo desde tu servidor.
Convenciones
Sobre de respuesta
Todas las respuestas exitosas siguen la misma forma:
{
"data": { /* recurso o lista */ },
"meta": {
"requestId": "req_1a2b3c",
"timestamp": "2026-05-13T12:34:56.789Z"
}
}Las listas paginadas añaden meta.pagination:
{
"data": [ /* ... */ ],
"meta": {
"requestId": "req_1a2b3c",
"timestamp": "2026-05-13T12:34:56.789Z",
"pagination": {
"total": 120,
"page": 1,
"limit": 20,
"totalPages": 6
}
}
}Sobre de error
Los errores devuelven el mismo formato en todos los endpoints:
{
"statusCode": 422,
"message": "Customer identification is invalid",
"code": "INVOICE_4002",
"details": [
"identification must be a 13-digit RUC"
]
}| Código HTTP | Significado |
|---|---|
200 / 201 | Operación correcta. |
400 | Error de validación o body mal formado. |
401 | API key faltante, inválida o expirada. |
403 | Permisos insuficientes o plan incompatible. |
404 | Recurso no encontrado. |
422 | Datos válidos sintácticamente pero rechazados por reglas del negocio o del SRI. |
429 | Rate limit o cuota mensual excedidos. |
500 | Error interno — reintenta con backoff. |
Postman
Descarga la colección oficial e impórtala en Postman para probar el API en segundos. La colección incluye todos los endpoints con ejemplos de request y response.
1) Descarga: /factuplan-developer.postman_collection.json
2) Abre Postman → Import → arrastra el archivo.
3) Edita las variables:
baseUrl = https://api.factuplan.com.ec
apiKey = tu_api_key
taxpayerRuc = tu_rucComprobantes
Emisión completa de facturas electrónicas. La API soporta tres modos:
- Modo A — Factuplan crea el XML, lo firma, lo autoriza ante el SRI, genera el PDF (RIDE) y manda el correo. Es el camino recomendado.
- Modo B — Tú generas el XML sin firmar; Factuplan lo firma, autoriza y notifica.
- Modo C — Factuplan solo firma el XML; tú te encargas del envío al SRI.
Emitir comprobante (Modo A)
POST /v1/developer/invoicesFlujo completo: crea el XML, lo firma con tu certificado P12, lo autoriza ante el SRI, genera el PDF (RIDE) y envía el correo al cliente automáticamente.
Request body
{
"customer": {
"customerId": "cust_id (opcional)",
"identificationType": "RUC",
"identification": "0993378150001",
"legalName": "Empresa Demo S.A.",
"email": "facturas@empresademo.ec",
"address": "Guayaquil, Ecuador",
"phone": "+593985691039",
"saveToContacts": true
},
"items": [
{
"quantity": 1,
"productId": "prod_id (opcional)",
"code": "SERV-001",
"auxiliaryCode": "AUX-001 (opcional)",
"description": "Servicio de consultoría",
"unitPrice": 150.0,
"discount": 0,
"taxType": "IVA_RATE",
"tax": 15,
"saveToProducts": false
}
],
"emissionPointId": "ep_id (opcional)",
"establishment": "001 (opcional)",
"emissionPoint": "001 (opcional)",
"additionalInfo": { "Vendedor": "Juan Pérez" },
"sendEmail": true,
"payments": [
{
"method": "20",
"amount": 172.5,
"term": 30,
"timeUnit": "dias"
}
]
}Campos del customer
| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
customerId | string | No | Si se envía, ignora los demás campos y usa el cliente del directorio. |
identificationType | enum | Sí | RUC, CEDULA, PASSPORT, FINAL_CONSUMER |
identification | string | Sí | RUC = 13 dígitos · CEDULA = 10 dígitos. |
legalName | string | Sí | Razón social o nombre completo. |
email | string | No | Necesario para envío automático del RIDE. |
address | string | No | Aparece en el RIDE. |
phone | string | No | Formato libre. |
saveToContacts | boolean | No | Si true, lo guarda en tu directorio. |
Campos de cada item
| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
quantity | number | Sí | Cantidad facturada. |
productId | string | No | Si se envía, los demás campos pueden omitirse. |
code | string | Sí | Identificador del ítem. |
auxiliaryCode | string | No | Código secundario (SKU, código de barras…). |
description | string | Sí | Aparece en el RIDE. |
unitPrice | number | Sí | Hasta 4 decimales de precisión. |
discount | number | No | Descuento por línea. |
taxType | enum | Sí | IVA_0, IVA_RATE, NOT_TAXABLE, EXEMPT. |
tax | number | Sí cuando taxType=IVA_RATE | Tarifa: 0, 5, 8, 12, 14, 15 (default 15). |
saveToProducts | boolean | No | Si true, lo guarda en tu catálogo. |
Punto de emisión
Tres formas de resolverlo, en orden de prioridad:
- Por UUID — envía
emissionPointId. - Por códigos SRI — envía
establishment+emissionPoint. - Auto-detección — omite todo; si solo tienes un punto activo, lo usa.
Tarifas de IVA (tax)
Aplica cuando taxType es IVA_RATE. Default: 15.
tax | Código SRI | Descripción |
|---|---|---|
0 | 0 | IVA 0% |
5 | 5 | IVA 5% |
8 | 8 | IVA 8% |
12 | 2 | IVA 12% |
14 | 3 | IVA 14% |
15 | 4 | IVA 15% (default) |
Formas de pago (payments)
Cada entrada lleva el código SRI en method, el amount y, opcionalmente, term + timeUnit. Si omites payments, se aplica "01" (Sin utilización del sistema financiero).
La suma de los
amountdebe ser exactamente igual al total con impuestos. Si no, el SRI rechaza la factura con400.
| Código | Descripción |
|---|---|
01 | Sin utilización del sistema financiero |
15 | Compensación de deudas |
16 | Tarjeta de débito |
17 | Dinero electrónico |
18 | Tarjeta prepago |
19 | Tarjeta de crédito |
20 | Otros con utilización del sistema financiero |
21 | Endoso de títulos |
timeUnit | Descripción |
|---|---|
dias | Días |
meses | Meses |
anios | Años |
Respuesta 201 Created
{
"data": {
"id": "rcpt_01HABCDEF",
"accessKey": "0104202601099337815000110010010000000011234567890",
"sequential": "000000001",
"status": "PROCESSING",
"total": 172.5,
"source": "API",
"apiKeyId": "ak_01H..."
},
"meta": {
"requestId": "req_1a2b3c",
"timestamp": "2026-05-13T12:34:56.789Z"
}
}status empieza en PROCESSING y evoluciona a AUTHORIZED → COMPLETED, o a ERROR / REJECTED. Consulta el progreso con GET /v1/developer/receipts/{id}/status.
Ejemplo con cURL
curl https://api.factuplan.com.ec/v1/developer/invoices \
-X POST \
-H "X-API-Key: $FACTUPLAN_API_KEY" \
-H "x-taxpayer-ruc: 0950194407001" \
-H "Content-Type: application/json" \
-d '{
"customer": {
"identificationType": "RUC",
"identification": "0993378150001",
"legalName": "Empresa Demo S.A.",
"email": "facturas@empresademo.ec"
},
"items": [
{
"code": "SERV-001",
"description": "Servicio de consultoría",
"quantity": 1,
"unitPrice": 150.0,
"taxType": "IVA_RATE",
"tax": 15
}
],
"payments": [
{ "method": "20", "amount": 172.5 }
]
}'Importar comprobante por clave de acceso
POST /v1/developer/invoices/importImporta una factura ya autorizada por el SRI usando su clave de 49 dígitos. Útil para sincronizar comprobantes emitidos fuera de Factuplan.
Solo
ak_live_*. No disponible con claves de pruebas.
Request body
{
"accessKey": "0104202601099337815000110010010000000011234567890"
}Respuesta 201 Created
{
"data": {
"id": "rcpt_01HXYZ",
"accessKey": "0104202601099337815000110010010000000011234567890",
"sequential": "000000007",
"status": "AUTHORIZED",
"total": 230.0,
"source": "IMPORT",
"apiKeyId": "ak_01H..."
},
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}Firmar XML
Endpoints para integradores que ya generan su propio XML SRI.
Firmar y autorizar (Modo B)
POST /v1/developer/sign-and-authorizeRecibe un XML sin firmar, lo firma con tu certificado P12 y lo envía al SRI para autorización. Factuplan también genera el PDF y envía el correo.
Request body
{
"xml": "<factura ...>...</factura>"
}Respuesta 200 OK
{
"data": {
"authorized": true,
"authorizationNumber": "0104202601...",
"authorizationDate": "2026-05-13T12:35:01.000Z",
"authorizedXml": "<autorizacion>...</autorizacion>"
},
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}Firmar XML (Modo C)
POST /v1/developer/signFirma el XML con tu certificado P12 de forma síncrona sin enviarlo al SRI. Útil cuando quieres controlar el envío al SRI por tu cuenta.
Request body
{ "xml": "<factura ...>...</factura>" }Respuesta 200 OK
{
"data": { "signedXml": "<factura ...><ds:Signature>...</ds:Signature></factura>" },
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}Validar estructura de XML
POST /v1/developer/validate-xmlValida que el XML tenga la estructura correcta según el esquema del SRI sin procesarlo ni enviarlo. Devuelve los errores encontrados.
Request body
{ "xml": "<factura ...>...</factura>" }Respuesta 200 OK
{
"data": {
"valid": false,
"errors": [
"infoTributaria.razonSocial is required",
"detalles[0].precioUnitario must be a number"
]
},
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}Verificar autorización en el SRI
GET /v1/developer/verify/{accessKey}Consulta en tiempo real el estado de autorización de un comprobante directamente ante el SRI usando su clave de acceso de 49 dígitos.
Parámetros de ruta
| Parámetro | Tipo | Notas |
|---|---|---|
accessKey | string | Clave de acceso SRI (49 dígitos). |
Respuesta 200 OK
{
"data": {
"found": true,
"source": "local",
"accessKey": "0104202601099337815000110010010000000011234567890",
"receiptId": "rcpt_01HABC",
"status": "AUTHORIZED",
"authorizationNumber": "0104202601...",
"authorizationDate": "2026-05-13T12:35:01.000Z",
"messages": [],
"type": "01",
"authorized": true,
"message": "Comprobante autorizado"
},
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}Consultar comprobantes
Consultar comprobante externo por clave de acceso
POST /v1/developer/receipts/queryConsulta cualquier comprobante autorizado por el SRI (Facturas 01, Notas de Crédito 04, Guías de Remisión 06), sin importar qué sistema lo emitió. Si el contribuyente emisor no existe en tu workspace, se crea automáticamente con firma vacía.
Solo
ak_live_*. No disponible con claves de pruebas.
Cómo se descuenta el contador: el crédito se descuenta cuando el comprobante está autorizado, sin importar el valor de
save. Si no está autorizado, no se descuenta ningún crédito.
Request body
| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
accessKey | string | Sí | Clave de acceso SRI (49 dígitos). |
save | boolean | No (default true) | Si false, solo verifica sin guardar en BD ni generar PDF. |
{
"accessKey": "0104202601019999999900110010010000000011234567813",
"save": true
}Obtener detalle del comprobante
GET /v1/developer/receipts/{id}Devuelve todos los datos del comprobante: estado, clave de acceso, secuencial, totales y fechas.
Respuesta 200 OK
{
"data": {
"id": "rcpt_01HABC",
"accessKey": "0104202601099337815000110010010000000011234567890",
"sequential": "000000001",
"status": "COMPLETED",
"total": 172.5,
"source": "API",
"apiKeyId": "ak_01H..."
},
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}Consultar estado del comprobante
GET /v1/developer/receipts/{id}/statusDevuelve el estado actual: PROCESSING, AUTHORIZED, COMPLETED, ERROR o REJECTED.
Respuesta 200 OK
{
"data": {
"status": "AUTHORIZED",
"authorizationNumber": "0104202601...",
"messages": []
},
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}Descargar XML autorizado
GET /v1/developer/receipts/{id}/xmlDevuelve una URL pre-firmada del XML autorizado por el SRI (expira en 5 minutos) y una URL permanente de visualización (previewUrl) que no expira.
Respuesta 200 OK
{
"data": {
"url": "https://files.factuplan.com.ec/...?sig=...",
"previewUrl": "https://files.factuplan.com.ec/preview/rcpt_01HABC.xml"
},
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}Descargar PDF (RIDE)
GET /v1/developer/receipts/{id}/pdfDevuelve una URL pre-firmada del PDF (RIDE) del comprobante (expira en 5 minutos) y una URL permanente de visualización (previewUrl).
Respuesta 200 OK
{
"data": {
"url": "https://files.factuplan.com.ec/...?sig=...",
"previewUrl": "https://files.factuplan.com.ec/preview/rcpt_01HABC.pdf"
},
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}Clientes
CRUD del directorio de clientes (receptores) que aparecerán en tus comprobantes.
Crear cliente
POST /v1/developer/customersRequest body
{
"identificationType": "RUC",
"identification": "0993378150001",
"legalName": "Empresa Demo S.A.",
"email": "facturas@empresademo.ec",
"address": "Guayaquil, Ecuador",
"phone": "+593985691039",
"additionalEmail": "contabilidad@empresademo.ec"
}| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
identificationType | enum | Sí | RUC, CEDULA, PASSPORT, FINAL_CONSUMER. |
identification | string | Sí | Validamos longitud y dígito verificador. |
legalName | string | Sí | Razón social o nombre completo. |
email | string | No | Para envío automático del RIDE. |
address | string | No | Aparece en el RIDE. |
phone | string | No | Formato libre. |
additionalEmail | string | No | Copia opcional para el envío del RIDE. |
Respuesta 201 Created
{
"data": {
"id": "cust_01HABC",
"taxpayerId": "tax_01H...",
"identificationType": "RUC",
"identification": "0993378150001",
"legalName": "Empresa Demo S.A.",
"email": "facturas@empresademo.ec",
"isActive": true,
"createdAt": "2026-05-13T12:34:56.789Z",
"updatedAt": "2026-05-13T12:34:56.789Z"
},
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}Listar clientes
GET /v1/developer/customersQuery parameters
| Parámetro | Tipo | Default | Notas |
|---|---|---|---|
page | number | 1 | Página solicitada. |
limit | number | 20 | Elementos por página. |
search | string | — | Busca por nombre, identificación o email. |
identificationType | enum | — | RUC, CEDULA, PASSPORT, FINAL_CONSUMER. |
isActive | boolean | — | Filtra por estado activo. |
Respuesta 200 OK
{
"data": [
{
"id": "cust_01HABC",
"taxpayerId": "tax_01H...",
"identificationType": "RUC",
"identification": "0993378150001",
"legalName": "Empresa Demo S.A.",
"email": "facturas@empresademo.ec",
"isActive": true,
"createdAt": "2026-05-13T12:34:56.789Z",
"updatedAt": "2026-05-13T12:34:56.789Z"
}
],
"meta": {
"requestId": "req_1a2b3c",
"timestamp": "2026-05-13T12:34:56.789Z",
"pagination": { "total": 120, "page": 1, "limit": 20, "totalPages": 6 }
}
}Obtener cliente
GET /v1/developer/customers/{id}Devuelve el detalle completo de un cliente específico por su ID.
Actualizar cliente
PATCH /v1/developer/customers/{id}Actualiza uno o más campos. Solo se modifican los enviados en el body.
{
"email": "nuevo@empresademo.ec",
"phone": "+593987654321",
"isActive": true
}Eliminar cliente
DELETE /v1/developer/customers/{id}Elimina un cliente del directorio. No afecta los comprobantes ya emitidos a ese cliente.
Respuesta 200 OK
{
"data": { "message": "Customer deleted successfully" },
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}Productos
CRUD del catálogo de ítems facturables. Funciona igual para productos tangibles y servicios.
Crear producto o servicio
POST /v1/developer/productsRequest body
{
"code": "SERV-001",
"type": "SERVICE",
"name": "Servicio de consultoría",
"unitPrice": 150.0,
"taxType": "IVA_RATE",
"auxiliaryCode": "AUX-001",
"description": "Hora de consultoría técnica",
"iceCode": "",
"iceRate": 0,
"irbpnr": false,
"unitOfMeasure": "hora"
}| Campo | Tipo | Requerido | Notas |
|---|---|---|---|
code | string | Sí | Identificador único en tu workspace. |
type | enum | Sí | PRODUCT, SERVICE. |
name | string | Sí | Aparece en el RIDE. |
unitPrice | number | Sí | Hasta 4 decimales de precisión. |
taxType | enum | Sí | IVA_0, IVA_RATE, NOT_TAXABLE, EXEMPT. |
auxiliaryCode | string | No | Código secundario (SKU, código de barras…). |
description | string | No | Descripción larga. |
iceCode | string | No | Código ICE del SRI. |
iceRate | number | No | Tarifa ICE aplicable. |
irbpnr | boolean | No | true si el ítem aplica IRBPNR. |
unitOfMeasure | string | No | Ej. unidad, kg, hora. |
Listar productos
GET /v1/developer/productsQuery parameters
| Parámetro | Tipo | Default | Notas |
|---|---|---|---|
page | number | 1 | Página solicitada. |
limit | number | 20 | Elementos por página. |
search | string | — | Busca por nombre, código o descripción. |
type | enum | — | PRODUCT, SERVICE. |
taxType | enum | — | IVA_0, IVA_RATE, NOT_TAXABLE, EXEMPT. |
isActive | boolean | — | Filtra por estado activo. |
Obtener, actualizar y eliminar
GET /v1/developer/products/{id}
PATCH /v1/developer/products/{id}
DELETE /v1/developer/products/{id}PATCH acepta cualquier subconjunto de los campos de creación más isActive: boolean. DELETE no afecta comprobantes históricos que ya referencien el ítem.
Uso & Cuota
GET /v1/developer/usageDevuelve el consumo de documentos del mes actual, el límite de tu plan y el costo estimado.
Respuesta 200 OK
{
"data": {
"currentMonth": "2026-05",
"plan": "growth",
"monthlyQuota": 1000,
"monthlyUsed": 273
},
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}| Campo | Tipo | Descripción |
|---|---|---|
currentMonth | string | Período actual (YYYY-MM). |
plan | string | Plan vigente del workspace. |
monthlyQuota | number | Límite mensual del plan. |
monthlyUsed | number | Documentos consumidos en el período. |
Certificado digital
GET /v1/developer/certificate/statusIndica si el certificado P12 configurado en tu cuenta está vigente, su fecha de vencimiento y el RUC del titular. Si no está vigente, los comprobantes no podrán firmarse.
Respuesta 200 OK
{
"data": {
"hasCertificate": true,
"isExpired": false,
"daysUntilExpiry": 87,
"ruc": "0950194407001",
"legalName": "Mi Empresa S.A.",
"issuedAt": "2025-05-13T00:00:00.000Z",
"expiresAt": "2026-08-08T00:00:00.000Z",
"issuer": "Banco Central del Ecuador"
},
"meta": { "requestId": "req_1a2b3c", "timestamp": "2026-05-13T12:34:56.789Z" }
}| Campo | Tipo | Descripción |
|---|---|---|
hasCertificate | boolean | Si hay un certificado cargado. |
isExpired | boolean | true si el certificado expiró. |
daysUntilExpiry | number | Días restantes hasta el vencimiento. |
ruc | string | RUC del titular del certificado. |
legalName | string | Nombre registrado en el certificado. |
issuedAt | string | Fecha de emisión (ISO 8601). |
expiresAt | string | Fecha de vencimiento (ISO 8601). |
issuer | string | Entidad certificadora emisora. |
Si
isExpiredestrue, renueva el certificado en Configuración → Certificado desde tu cuenta antes de seguir emitiendo.
Errores
Todos los endpoints devuelven el mismo formato de error:
{
"statusCode": 422,
"message": "Customer identification is invalid",
"code": "INVOICE_4002",
"details": [
"identification must be a 13-digit RUC"
]
}Códigos frecuentes
| Código | HTTP | Descripción |
|---|---|---|
AUTH_ERROR | 401 | API key inválida o expirada. |
RATE_LIMIT | 429 | Límite de solicitudes excedido. |
API_10001 | 403 | Plan no compatible con la operación. |
API_10002 | 429 | Cuota mensual excedida. |
INVOICE_4002 | 422 | Datos del cliente inválidos. |
INVOICE_4003 | 422 | Detalle de factura vacío. |
CERT_3008 | 422 | Certificado expirado. |
CUSTOMER_7004 | 409 | Cliente duplicado. |
PRODUCT_6002 | 409 | Código de producto duplicado. |
GENERAL_0003 | 429 | Rate limit por velocidad. |
Rate limit
Cada API key tiene dos límites:
- Velocidad:
100peticiones por segundo por API key. - Cuota mensual: depende del plan contratado (consulta /precios).
Si superas cualquiera de los dos, recibes HTTP 429.
Respuesta al superar el límite de velocidad
{
"statusCode": 429,
"code": "GENERAL_0003",
"message": "Has superado el límite de peticiones. Intenta de nuevo en unos segundos."
}Respuesta al superar la cuota mensual
{
"statusCode": 429,
"code": "API_10002",
"message": "Has alcanzado el límite mensual de 500 documentos.",
"details": { "used": 500, "quota": 500 }
}Manejo recomendado con reintentos
Implementa espera exponencial (500ms → 1s → 2s → 4s…) y un máximo de reintentos por petición. Ejemplo en Python con requests:
import os, time, requests
API = "https://api.factuplan.com.ec/v1/developer"
HEADERS = {
"X-API-Key": os.environ["FACTUPLAN_API_KEY"],
"x-taxpayer-ruc": "0950194407001",
"Content-Type": "application/json",
}
def emit_invoice(body, intentos=3):
for i in range(intentos):
r = requests.post(f"{API}/invoices", json=body, headers=HEADERS, timeout=30)
if r.status_code != 429:
r.raise_for_status()
return r.json()
time.sleep(0.5 * (2 ** i))
r.raise_for_status()Webhooks
Antes de procesar un evento webhook, verifica que el comprobante exista y consulta su estado actual con GET /v1/developer/receipts/{id}. Esto evita que actualices tu base de datos con eventos manipulados o duplicados.
curl https://api.factuplan.com.ec/v1/developer/receipts/$RECEIPT_ID \
-H "X-API-Key: $FACTUPLAN_API_KEY" \
-H "x-taxpayer-ruc: 0950194407001"Tip: llama a este endpoint apenas recibes un evento webhook. Confirma que el comprobante existe antes de actualizar tu BD o disparar notificaciones a tus usuarios.
¿Necesitas ayuda integrando el API? Escríbenos a soporte@factuplan.com.ec o desde el Centro de ayuda. Si prefieres Node.js o TypeScript, te ahorra trabajo el SDK oficial.
