Ir al contenido

Documentación para desarrolladores · v1

Emite comprobantes del SRI desde tu propio sistema

Una API REST con llaves por empresa para crear facturas, notas de crédito, retenciones y más, seguir su autorización y descargar el RIDE y el XML. Integra tu ERP, tienda en línea o punto de venta en una tarde.

Base URL
facturon.ec/api/v1/ext
Autenticación
Bearer fec_…
Emisión
asíncrona, segundos
Planes
Negocio y superiores

Introducción

Qué puedes hacer con la API

Todo lo que hace el panel de Facturón al emitir, expuesto como recursos JSON: empresas y puntos de emisión, clientes, productos, documentos electrónicos con su ciclo completo ante el SRI y los catálogos oficiales. Las respuestas siguen siempre el mismo envoltorio.

Emitir

Facturas, liquidaciones, notas de crédito y débito, guías de remisión y retenciones.

Consultar

Estado de autorización, mensajes del SRI, RIDE en PDF y XML autorizado.

Sincronizar

Clientes y productos en ambos sentidos, con búsqueda por identificación.

envoltorio de respuesta
{ "success": true, "message": "…", "data": { … } }          // éxito
{ "success": true, "data": [ … ], "meta": { "current_page": 1, "last_page": 3, "per_page": 15, "total": 42 } }  // listados
{ "success": false, "error": "insufficient_scope", "message": "…", "required_scope": "documents:write" }       // error

Autenticación

Llaves de API por empresa

Cada llave pertenece a una cuenta de Facturón, se muestra una sola vez al crearla y se guarda cifrada (hash). Envíala en la cabecera Authorization: Bearer o, si tu herramienta lo prefiere, en X-API-Key. Nunca en la URL.
primera petición
curl https://facturon.ec/api/v1/ext/me \
  -H "Authorization: Bearer fec_TU_LLAVE"
  • Rotación. Genera una credencial nueva sin borrar la configuración; la anterior deja de funcionar al instante.
  • Caducidad. Opcional: 30, 90 o 365 días. Una llave caducada responde 401 expired_api_key.
  • Hasta 10 llaves activas por cuenta: una por sistema, con el mínimo de alcances que necesite.
  • Solo HTTPS. Las llaves equivalen a las credenciales del propietario de la cuenta: guárdalas como secretos.

Alcances y límites

Mínimo privilegio y cuotas por plan

Al crear la llave eliges qué puede hacer. Sin el alcance necesario la API responde 403 insufficient_scope indicando cuál falta.
AlcancePermite
documents:readListar y ver documentos, estado ante el SRI, RIDE y XML.
documents:writeCrear y emitir documentos, reenviar al SRI, anular, reenviar correo.
customers:readListar, ver y buscar clientes.
customers:writeCrear y actualizar clientes.
products:readListar y ver productos y servicios.
products:writeCrear y actualizar productos y servicios.
catalogs:readCatálogos del SRI. Incluido en toda llave.
*Acceso total (equivale a todos los anteriores).
PlanLímite
Negocio60 peticiones / minuto
Profesional120 peticiones / minuto
Enterprise300 peticiones / minuto

Cada respuesta incluye X-RateLimit-Limit y X-RateLimit-Remaining. Al superarlo: 429 rate_limit_exceeded con Retry-After. Puedes fijar un límite menor por llave. El límite mensual de documentos es el del plan.

Flujo para emitir

De tu pedido a un comprobante autorizado en cinco pasos

  1. 1

    Crea una llave

    En el panel: Configuración → API e integraciones. Elige alcances y caducidad. La llave se muestra una sola vez.

  2. 2

    Descubre tus ids

    GET /companies devuelve company_id y emission_point_id; GET /customers/lookup encuentra al cliente por cédula o RUC (o créalo con POST /customers).

  3. 3

    Emite

    POST /documents con los importes calculados y la cabecera Idempotency-Key. Responde 201 con el documento en processing.

  4. 4

    Confirma la autorización

    GET /documents/{id}/status cada 5–10 s hasta authorized (o rejected con los mensajes del SRI).

  5. 5

    Entrega el comprobante

    GET /documents/{id}/ride (PDF) y /xml, o POST /documents/{id}/email para reenviarlo al cliente.

Ambiente de pruebas. Configura la empresa emisora en ambiente de pruebas del SRI para integrar sin emitir comprobantes reales; la API y la llave son las mismas. Al pasar a producción solo cambias el ambiente de la empresa.

Idempotencia

Reintenta sin duplicar facturas

Las redes fallan. Envía en POST /documents la cabecera Idempotency-Key con un identificador único de tu operación (por ejemplo, el número de pedido). Durante 24 horas, cualquier repetición con el mismo cuerpo devuelve exactamente la misma respuesta.
201 + Idempotent-Replayed: true

Misma llave, mismo cuerpo: se devuelve la respuesta original, no se crea otro documento.

409 idempotency_key_reused

Misma llave con otro cuerpo: usa una llave nueva para cada operación distinta.

409 idempotency_in_progress

Dos peticiones simultáneas con la misma llave: espera unos segundos y reintenta.

Referencia

Cuenta y empresas

Verifica la llave y descubre los identificadores que necesitas para emitir.
GET/mecualquier llave

Identidad de la integración

Cuenta, plan, límites, uso del período y datos de la llave. Úsalo para probar credenciales.

respuesta
{
  "success": true,
  "data": {
    "tenant": { "id": 12, "name": "ACME S.A.", "status": "active" },
    "plan": { "slug": "negocio", "name": "Negocio" },
    "limits": { "documents_per_month": 50, "effective_document_limit": 50, "unlimited": false, "rate_limit_per_minute": 60 },
    "usage": { "documents_this_period": 17, "period_start": "2026-09-01" },
    "api_key": { "name": "Tienda en línea", "key_prefix": "fec_a1B2c3D4", "scopes": ["documents:write", "customers:write"], "effective_rate_limit": 60, "expires_at": null }
  }
}
GET/companiesdocuments:read

Empresas emisoras con establecimientos y puntos de emisión

Devuelve company_id y emission_point_id (con su serie 001-001) y el ambiente del SRI configurado en cada empresa.

respuesta
{
  "success": true,
  "data": {
    "companies": [
      {
        "id": 1, "ruc": "1790012345001", "business_name": "ACME S.A.", "sri_environment": "2", "sri_environment_label": "Producción",
        "branches": [
          { "id": 1, "code": "001", "name": "Matriz", "is_main": true,
            "emission_points": [ { "id": 1, "code": "001", "name": "Caja 1", "series": "001-001" } ] }
        ]
      }
    ]
  }
}

Referencia

Documentos

Facturas (01), liquidaciones de compra (03), notas de crédito (04) y débito (05), guías de remisión (06) y retenciones (07). El mismo payload que usa el panel de Facturón.
POST/documentsdocuments:write

Crear y emitir un documento

Crea el comprobante y, salvo send: false, lo valida contra las reglas del SRI y lo envía a firmar y autorizar. Responde 201 con el documento en processing; la autorización llega en segundos y se consulta en /status. Facturón no recalcula importes: envía subtotal, tax_base, tax_value y total ya calculados.

ParámetroEnTipoDescripción
Idempotency-Keyheaderstring ≤128Identificador único de la operación en tu sistema (ej. el id del pedido). Válido 24 h.
company_idobligatoriobodyintegerEmpresa emisora (ver /companies).
emission_point_idobligatoriobodyintegerPunto de emisión de la empresa (ver /companies).
customer_idobligatoriobodyintegerCliente (ver /customers y /customers/lookup).
document_typeobligatoriobody"01" | "03" | "04" | "05" | "06" | "07"Tipo de comprobante.
issue_datebodydateFecha de emisión (por defecto hoy).
subtotal_15 / subtotal_12 / subtotal_5 / subtotal_0 / subtotal_no_taxbodynumberSubtotales por tarifa de IVA.
total_taxbodynumberIVA total.
total_discountbodynumberDescuento total.
totalobligatoriobodynumberImporte total.
payment_methods[]body{ code, amount, term?, time_unit? }Formas de pago del SRI (ver catálogo).
items[]obligatoriobodyobjetomain_code, description, quantity, unit_price, discount, subtotal, tax_code, tax_percentage_code, tax_rate, tax_base, tax_value. Obligatorio salvo en retenciones.
additional_infobodyobjetoPares nombre → valor impresos en el RIDE (máx. 300 caracteres cada uno).
reference_document_id + modification_reasonbodyinteger + stringObligatorios en notas de crédito y débito.
withholding_details[]bodyobjetoObligatorio en retenciones (07): support_doc_*, tax_type (renta|iva), retention_code, tax_base, retention_rate, retained_value.
sendbodybooleantrue por defecto. Con false queda en borrador para enviarlo luego con /send.
cuerpo de la petición
{
  "company_id": 1,
  "emission_point_id": 1,
  "customer_id": 25,
  "document_type": "01",
  "issue_date": "2026-09-13",
  "subtotal_15": 100.00,
  "total_tax": 15.00,
  "total": 115.00,
  "payment_methods": [{ "code": "01", "amount": 115.00 }],
  "items": [
    {
      "main_code": "SERV-001",
      "description": "Servicio de consultoría",
      "quantity": 1,
      "unit_price": 100.00,
      "discount": 0,
      "subtotal": 100.00,
      "tax_code": "2",
      "tax_percentage_code": "4",
      "tax_rate": 15,
      "tax_base": 100.00,
      "tax_value": 15.00
    }
  ],
  "additional_info": { "Pedido": "WEB-1001" }
}
respuesta
{
  "success": true,
  "message": "Documento creado y enviado al SRI. Consulta su estado en GET /documents/{id}/status.",
  "data": {
    "document": {
      "id": 812,
      "document_type": "01",
      "document_number": "001-001-000000042",
      "access_key": "1309202601179001234500110010010000000421234567811",
      "status": "processing",
      "total": 115,
      "customer": { "id": 25, "identification_number": "1790012345001", "name": "ACME S.A." },
      "items": [ { "main_code": "SERV-001", "description": "Servicio de consultoría", "quantity": 1 } ]
    }
  }
}
GET/documentsdocuments:read

Listar documentos

Paginado (máximo 100 por página), ordenado por fecha de emisión descendente.

ParámetroEnTipoDescripción
statusquerystringdraft, processing, authorized, rejected, failed, voided.
document_typequerystring01, 03, 04, 05, 06, 07.
company_id / customer_idqueryintegerFiltra por empresa o cliente.
date_from / date_toquerydateRango de fecha de emisión (YYYY-MM-DD).
access_keyquerystring (49)Clave de acceso exacta.
searchquerystringClave de acceso, número o cliente.
page / per_pagequeryintegerPaginación; per_page máximo 100.
respuesta
{
  "success": true,
  "data": [ { "id": 812, "document_number": "001-001-000000042", "status": "authorized", "total": 115, "customer": { "name": "ACME S.A." } } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 15, "total": 1 },
  "links": { "first": "…", "last": "…", "prev": null, "next": null }
}
GET/documents/{id}documents:read

Ver un documento

Detalle completo con ítems, cliente, empresa, mensajes del SRI y banderas has_ride / has_xml.

GET/documents/{id}/statusdocuments:read

Estado ante el SRI

Si el documento sigue en proceso, consulta al SRI en vivo antes de responder. Sondea cada 5–10 segundos tras emitir hasta ver authorized o rejected.

respuesta
{
  "success": true,
  "data": {
    "status": "authorized",
    "status_label": "Autorizado",
    "authorization_number": "1309202601179001234500110010010000000421234567811",
    "authorization_date": "2026-09-13T15:04:11.000000Z",
    "sri_messages": [],
    "contingency_active": false,
    "contingency_message": null
  }
}
POST/documents/{id}/senddocuments:write

Enviar al SRI

Para borradores (creados con send: false) y para reintentar documentos fallidos o rechazados tras corregir la causa.

POST/documents/{id}/voiddocuments:write

Marcar como anulado

Solo documentos autorizados. Registra el motivo en Facturón; la anulación fiscal se hace en SRI en línea o emitiendo una nota de crédito.

ParámetroEnTipoDescripción
reasonobligatoriobodystring ≤300Motivo de la anulación.
POST/documents/{id}/emaildocuments:write

Reenviar el comprobante por correo

ParámetroEnTipoDescripción
emailbodystringDestinatario. Si se omite, el correo del cliente.
GET/documents/{id}/ridedocuments:read

RIDE en PDF

Responde el PDF (application/pdf). Con ?url=1 responde JSON con una URL temporal de 30 minutos, útil para enlazar desde tu sistema.

GET/documents/{id}/xmldocuments:read

XML firmado / autorizado

Responde el XML (application/xml) o, con ?url=1, una URL temporal. Antes de la firma responde 404 xml_not_available.

Referencia

Clientes

Los comprobantes se emiten a un cliente registrado. Busca por identificación y crea solo si no existe.
GET/customers/lookupcustomers:read

Buscar por identificación exacta

ParámetroEnTipoDescripción
identificationobligatorioquerystringCédula, RUC o pasaporte.
respuesta
{ "success": true, "data": { "customer": { "id": 25, "identification_type": "04", "identification_number": "1790012345001", "name": "ACME S.A.", "email": "compras@acme.ec" } } }
POST/customerscustomers:write

Crear cliente

ParámetroEnTipoDescripción
identification_typeobligatoriobody"04" RUC | "05" cédula | "06" pasaporte | "07" consumidor final | "08" exteriorTipo de identificación del SRI.
identification_numberobligatoriobodystring ≤20Única por cuenta.
nameobligatoriobodystring ≤300Razón social o nombre.
email / additional_emails[] / phone / addressbodystringDatos de contacto opcionales.
cuerpo de la petición
{
  "identification_type": "04",
  "identification_number": "1790012345001",
  "name": "ACME S.A.",
  "email": "compras@acme.ec",
  "address": "Av. Amazonas N21-147, Quito"
}
GET/customerscustomers:read

Listar clientes

ParámetroEnTipoDescripción
searchquerystringNombre, identificación o correo.
GET/customers/{id}customers:read

Ver cliente

PATCH/customers/{id}customers:write

Actualizar cliente

Envía el registro completo (mismos campos que al crear).

Referencia

Productos y servicios

Opcional: los ítems de un documento pueden referenciar un product_id o describirse en línea.
GET/productsproducts:read

Listar productos y servicios

ParámetroEnTipoDescripción
searchquerystringCódigo o nombre.
POST/productsproducts:write

Crear producto o servicio

ParámetroEnTipoDescripción
codeobligatoriobodystring ≤50Código principal, único por cuenta.
skubodystring ≤50Código auxiliar.
nameobligatoriobodystring ≤300Nombre.
typeobligatoriobody"product" | "service"Bien o servicio.
unit_priceobligatoriobodynumberPrecio unitario sin IVA.
tax_percentage_code / tax_ratebodystring / numberTarifa de IVA (ej. "4" / 15).
track_inventory / stock / min_stockbodyboolean / integerControl de inventario (planes con inventario).
cuerpo de la petición
{ "code": "CAM-001", "sku": "SKU-CAM-001", "name": "Camiseta", "type": "product", "unit_price": 12.50, "tax_percentage_code": "4", "tax_rate": 15 }
GET/products/{id}products:read

Ver producto

PATCH/products/{id}products:write

Actualizar producto

Envía el registro completo (code, name, type y unit_price son obligatorios).

Referencia

Catálogos del SRI

Códigos oficiales que necesitas al construir documentos. Disponibles con cualquier llave.
GET/catalogs/identification-typescualquier llave

Tipos de identificación

GET/catalogs/document-typescualquier llave

Tipos de comprobante

GET/catalogs/payment-methodscualquier llave

Formas de pago

GET/catalogs/tax-ratescualquier llave

Tarifas de IVA

GET/catalogs/retention-codescualquier llave

Códigos de retención (IVA y renta)

Errores

Códigos estables para tu manejo de errores

Además del código HTTP, cada error trae un campo error en snake_case que no cambia entre versiones, y un message legible en español.
HTTPerrorCuándo
401missing_api_keyNo enviaste la cabecera Authorization ni X-API-Key.
401invalid_api_keyLa llave no existe o fue desactivada.
401expired_api_keyLa llave caducó. Genera una nueva en el panel.
403tenant_inactiveLa cuenta está suspendida o inactiva.
403subscription_requiredLa cuenta no tiene una suscripción vigente (incluye upgrade_url).
403api_access_not_allowedEl plan no incluye API (incluye upgrade_url).
403insufficient_scopeLa llave no tiene el alcance necesario (incluye required_scope).
403plan_limit_reachedSe alcanzó el límite mensual de documentos del plan.
404not_foundEl recurso no existe o pertenece a otra cuenta.
404xml_not_availableEl XML aún no se generó (documento sin firmar/autorizar).
409idempotency_key_reusedMismo Idempotency-Key con un cuerpo distinto.
409idempotency_in_progressOtra petición con el mismo Idempotency-Key está en curso.
409send_failedEl documento se creó pero la empresa no está lista para emitir (firma, establecimientos).
422validation_errorCampos inválidos (errors por campo) o reglas del SRI (errors.sri).
429rate_limit_exceededSe superó el límite por minuto (incluye retry_after y Retry-After).

Ejemplos de código

Del cero a la primera factura

Los tres ejemplos hacen lo mismo: verificar la llave, emitir con idempotencia, esperar la autorización y descargar el RIDE.
curl
# 1) Verifica la llave
curl https://facturon.ec/api/v1/ext/me \
  -H "Authorization: Bearer fec_TU_LLAVE"

# 2) Emite una factura (idempotente por pedido)
curl -X POST https://facturon.ec/api/v1/ext/documents \
  -H "Authorization: Bearer fec_TU_LLAVE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido-WEB-1001" \
  -d @factura.json

# 3) Consulta el estado hasta que sea authorized
curl https://facturon.ec/api/v1/ext/documents/812/status \
  -H "Authorization: Bearer fec_TU_LLAVE"

# 4) Descarga el RIDE
curl -o factura.pdf https://facturon.ec/api/v1/ext/documents/812/ride \
  -H "Authorization: Bearer fec_TU_LLAVE"
JavaScript (Node 18+)
const BASE = "https://facturon.ec/api/v1/ext";
const headers = {
  Authorization: `Bearer ${process.env.FACTURON_API_KEY}`,
  "Content-Type": "application/json",
};

async function emitirFactura(pedido) {
  const res = await fetch(`${BASE}/documents`, {
    method: "POST",
    headers: { ...headers, "Idempotency-Key": `pedido-${pedido.id}` },
    body: JSON.stringify(pedido.factura),
  });
  const json = await res.json();
  if (!res.ok) throw new Error(`${json.error}: ${json.message}`);
  return json.data.document; // status: "processing"
}

async function esperarAutorizacion(id, intentos = 12) {
  for (let i = 0; i < intentos; i++) {
    const res = await fetch(`${BASE}/documents/${id}/status`, { headers });
    const { data } = await res.json();
    if (data.status === "authorized" || data.status === "rejected") return data;
    await new Promise((r) => setTimeout(r, 5000));
  }
  throw new Error("El SRI aún no responde; reintenta más tarde");
}
PHP (Guzzle)
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://facturon.ec/api/v1/ext/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('FACTURON_API_KEY')],
]);

// Cliente: buscar o crear
try {
    $cliente = json_decode($client->get('customers/lookup', ['query' => ['identification' => '1790012345001']])->getBody(), true)['data']['customer'];
} catch (\GuzzleHttp\Exception\ClientException $e) {
    if ($e->getResponse()->getStatusCode() !== 404) throw $e;
    $cliente = json_decode($client->post('customers', ['json' => [
        'identification_type' => '04', 'identification_number' => '1790012345001', 'name' => 'ACME S.A.',
    ]])->getBody(), true)['data']['customer'];
}

// Emitir
$factura = json_decode($client->post('documents', [
    'headers' => ['Idempotency-Key' => 'pedido-WEB-1001'],
    'json' => $payload + ['customer_id' => $cliente['id']],
])->getBody(), true)['data']['document'];

// Estado
$estado = json_decode($client->get("documents/{$factura['id']}/status")->getBody(), true)['data'];

Preguntas frecuentes

Lo que preguntan los integradores

¿Cómo pruebo sin emitir comprobantes reales?

Configura la empresa emisora en ambiente de pruebas del SRI (Configuración → Datos del emisor). Los documentos se firman y autorizan contra el ambiente de pruebas del SRI con la misma API; cuando pases a producción, cambia el ambiente de la empresa y usa la misma llave.

¿Cuánto tarda la autorización?

Normalmente entre 2 y 15 segundos. La API responde de inmediato con el documento en processing; sondea /status. Si el SRI está caído, el documento entra en contingencia y Facturón reintenta automáticamente; el estado lo refleja con contingency_active.

¿Qué pasa si mi sistema reintenta una petición?

Envía siempre Idempotency-Key en POST /documents. Una repetición con el mismo cuerpo devuelve la misma respuesta (cabecera Idempotent-Replayed: true) y no crea otra factura.

¿La API calcula el IVA?

No. Tu sistema envía subtotales, impuestos y total ya calculados (como lo hace el panel). Antes de enviar al SRI, Facturón valida reglas como el tope de $50 a Consumidor Final o la validez de la identificación.

¿Puedo recibir avisos cuando un documento se autoriza?

Los webhooks están en desarrollo. Mientras tanto, sondea GET /documents/{id}/status o consulta GET /documents?status=authorized&date_from=… de forma periódica.

¿Qué planes incluyen la API?

Negocio, Profesional y Enterprise. Cada plan define el límite de peticiones por minuto; el límite mensual de documentos es el mismo del plan.

¿Listo para integrar?

Crea tu cuenta, elige un plan con API y genera tu primera llave en minutos.