Inicio rápido

Tu primera factura en 5 minutos

Vas a conseguir tu API key, comprobar que funciona y emitir una boleta en modo prueba (SUNAT beta, sin validez fiscal). No necesitas certificado digital ni clave SOL para esto, y el modo prueba no consume créditos (hasta 200 al día).

¿Integras con un agente de IA? Dale este enlace: https://factusmart.pe/api-facturacion-electronica/llms-full.txt

1Consigue tu API key

  1. Crea tu cuenta de integrador (gratis). Recibes 50 créditos de regalo, por única vez, para empezar a emitir en producción (al contratar tu primer plan se reemplazan por su cupo); las pruebas en RUCs en modo prueba no los gastan.
  2. En tu panel, entra a la pestaña Configuración y copia dos datos: tu API key y tu URL base. Para empezar te recomendamos pulsar "Generar llave de prueba" y usar esa llave (empieza con fs_test_): solo emite en RUCs en modo prueba, así tu código en desarrollo nunca manda un comprobante real por error.
  3. Ten a la mano el RUC con el que vas a emitir. Cada RUC nace en modo prueba.

La URL base no es la misma para todos

Cada cuenta vive en un servidor distinto (s1, s2…). En los ejemplos reemplaza TU_URL_BASE por la que ves en tu panel y TU_API_KEY por tu llave. Una API key solo funciona en su servidor.

Toda petición lleva la llave en el header X-API-Key. Si tu cuenta tiene un solo RUC, se usa solo; si tiene varios, indica cuál con el campo ruc.

2Prueba la conexión (ping)

GET /ping confirma que tu llave es válida y te dice cuántos créditos tienes. No consume crédito.

curl https://TU_URL_BASE/api/v1/issuer/ping \
  -H "X-API-Key: TU_API_KEY" \
  -H "Accept: application/json"

Respuesta:

{
  "success": true,
  "message": "Autenticado correctamente",
  "cuenta": "Mi Integración",
  "creditos": 4830,
  "tipo_llave": "prueba",
  "ruc_emisor": "20100070970",
  "razon_social": "MI EMPRESA"
}

tipo_llave te confirma qué llave usas (prueba o produccion). ¿Te sale 401? La llave está mal copiada o es de otro servidor: revisa la URL base.

3Emite una boleta

POST /documents con "codigo_tipo_documento": "03". Con "numero_documento": "#" FactuSmart pone el correlativo. Para no calcular el IGV a mano, primero pide items y totales a POST /calcular (gratis) y cópialos tal cual; los SDK hacen lo mismo con calcularComprobante(). En un RUC en modo prueba emitir es gratis (hasta 200 pruebas al día); en producción cuesta 1 crédito.

# 1) Calcula items y totales (gratis, no necesita RUC)
curl -X POST https://TU_URL_BASE/api/v1/issuer/calcular \
  -H "X-API-Key: TU_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
  "items": [
    {
      "codigo_interno": "PROD-002",
      "descripcion": "Producto de prueba",
      "cantidad": 1,
      "valor_unitario": 50,
      "afectacion": "10"
    }
  ]
}'

# La respuesta trae "items" y "totales": cópialos tal cual en el paso 2.

# 2) Emite la boleta con esos items y totales
curl -X POST https://TU_URL_BASE/api/v1/issuer/documents \
  -H "X-API-Key: TU_API_KEY" \
  -H "Idempotency-Key: venta-000123" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
  "ruc": "20100070970",
  "numero_documento": "#",
  "fecha_de_emision": "2026-07-08",
  "hora_de_emision": "10:30:00",
  "codigo_tipo_operacion": "0101",
  "codigo_tipo_documento": "03",
  "codigo_tipo_moneda": "PEN",
  "datos_del_cliente_o_receptor": {
    "codigo_tipo_documento_identidad": "1",
    "numero_documento": "12345678"
  },
  "items": [
    {
      "codigo_interno": "PROD-002",
      "descripcion": "Producto de prueba",
      "unidad_de_medida": "NIU",
      "cantidad": 1,
      "valor_unitario": 50,
      "codigo_tipo_precio": "01",
      "precio_unitario": 59,
      "codigo_tipo_afectacion_igv": "10",
      "total_base_igv": 50,
      "porcentaje_igv": 18,
      "total_igv": 9,
      "total_impuestos": 9,
      "total_valor_item": 50,
      "total_item": 59
    }
  ],
  "totales": {
    "total_operaciones_gravadas": 50,
    "total_operaciones_exoneradas": 0,
    "total_operaciones_inafectas": 0,
    "total_exportacion": 0,
    "total_igv": 9,
    "total_impuestos": 9,
    "total_valor": 50,
    "total_venta": 59
  }
}'
  • En curl, cambia fecha_de_emision y hora_de_emision por las de hoy (hora de Perú). Los SDK las ponen solos si no las mandas, igual que numero_documento: "#", codigo_tipo_operacion: "0101" y codigo_tipo_moneda: "PEN".
  • Cliente con DNI o RUC: basta el número, el nombre se completa solo desde RENIEC/SUNAT.
  • Idempotency-Key es un valor único por venta (el id de tu venta). Si repites la petición con la misma llave, recibes el mismo comprobante, sin cobrarte de nuevo. Los SDK la generan solos si no la pasas.

4Revisa el resultado

La respuesta trae el resultado de SUNAT en el mismo momento:

{
  "success": true,
  "estado": "05",
  "estado_descripcion": "Aceptado",
  "serie_numero": "BA01-1",
  "external_id": "9822f52c-108e-47ff-9d2e-5f0c3c1a7b11",
  "sunat": { "codigo": "0", "descripcion": "La Boleta numero BA01-1, ha sido aceptada" },
  "creditos_restantes": 50,
  "aceptado_por_sunat": true,
  "entorno": "prueba",
  "tiene_validez_fiscal": false,
  "credito_cobrado": false,
  "modo_demo": true,
  "pruebas_restantes_hoy": 199
}
CampoQué te dice
aceptado_por_sunattrue solo si SUNAT lo aceptó (estado 05). Este es el campo que tienes que revisar.
entornoprueba (SUNAT beta, sin validez) o produccion (real, con validez fiscal). tiene_validez_fiscal dice lo mismo como booleano.
external_idGuárdalo: con él consultas, reenvías y descargas el PDF/XML/CDR.
credito_cobradotrue si esta emisión descontó 1 crédito. En modo prueba viene false, junto con modo_demo: true y pruebas_restantes_hoy (cuántas de las 200 de hoy te quedan). creditos_restantes es tu saldo real: en modo prueba no baja.
sunatCódigo y mensaje de SUNAT. Si algo falló, aquí está el motivo.

Regla de oro: HTTP 200 no significa “aceptado por SUNAT”

Un 200 quiere decir que generamos tu comprobante. Si SUNAT está caída, tarda o lo rechaza, igual recibes 200, pero con aceptado_por_sunat: false y estado 01 (registrado, no confirmado) o 09 (rechazado).

Eso no es un error del API y no lanza excepción en los SDK: es un resultado que tu sistema tiene que revisar. Guarda el external_id, lee sunat.descripcion y accion_requerida, y sigue la guía Si no sale "Aceptado".

# Con jq: te quedas solo con lo que importa
curl -s -X POST https://TU_URL_BASE/api/v1/issuer/documents ... | jq '{aceptado_por_sunat, entorno, estado, serie_numero, external_id, sunat}'

Mira el entorno antes de probar

Un comprobante emitido en produccion es real aunque sea de S/ 0.10 y aunque lo hayas hecho «para probar»: solo se quita anulándolo. Haz tus pruebas con el RUC en modo prueba.

5Siguientes pasos

¿Prefieres no armar las peticiones a mano? Mira los SDKs para PHP, Node.js/TypeScript, Python, Java y C# o descarga la colección de Postman.

¿Aún no tienes cuenta?

Créala gratis y recibe tu API key al instante, con 50 créditos de regalo para empezar a emitir en producción. El modo prueba es gratis y no los consume.

Crear cuenta gratis