Saltar al contenido
Factuplan
Terminal de Node.js ejecutando un script que emite una factura electrónica autorizada por el SRI Ecuador con la API REST de Factuplan

Facturación electrónica Nodejs para Ecuador (paso a paso, 2026)

Integra facturación electrónica SRI en Node.js con el SDK oficial de Factuplan: webhooks, manejo de errores y repo facturación electrónica Ecuador en GitHub.

· 16 min de lectura · Equipo Factuplan
Compartir:

Tu app en Node.js necesita emitir facturas electrónicas autorizadas por el SRI de Ecuador. La buena noticia: con el SDK oficial de Factuplan lo puedes resolver en una tarde, sin tocar XMLs, sin firmar XAdES-BES manualmente y sin pelear con la API SOAP del SRI.

En este tutorial vas a ver cada paso: pre-requisitos, instalación, configuración, emisión de la primera factura, manejo de webhooks y troubleshooting. Todo con código real probado en producción.

Pre-requisitos

Antes de escribir una línea de código, necesitas:

1. Cuenta en Factuplan

Crea cuenta gratuita en app.factuplan.com.ec. El plan Free te da 25 facturas/mes sin costo, sin tarjeta de crédito. Suficiente para desarrollo y proyectos pequeños.

2. RUC activo

Tu negocio o el de tu cliente debe tener RUC activo en el SRI. Si todavía no tienes RUC, hay una guía completa para sacarlo.

3. Firma electrónica vigente

Para producción necesitas un certificado P12 emitido por una entidad acreditada en Ecuador (Banco Central, UANATACA, Security Data, ANF AC). Lo cargas una sola vez en tu workspace de Factuplan y ya. Para desarrollo en pruebas no se necesita firma real.

4. Node.js 18+

Ventana de terminal
node --version # debe ser v18.x o superior

Si usas una versión anterior, el SDK no funciona.

5. API key

Una vez dentro de Factuplan: Developer → Create API key.

  • ak_test_* para pruebas (comprobantes ficticios, se borran cada hora).
  • ak_live_* para producción (facturas reales firmadas y enviadas al SRI).

Guárdala en .env:

Ventana de terminal
FACTUPLAN_API_KEY=ak_test_xxxxxxxxxxxxxxxxxx
FACTUPLAN_RUC=0950194407001

Paso 1 — Crear el proyecto

Ventana de terminal
mkdir mi-app-facturacion
cd mi-app-facturacion
npm init -y
npm install factuplan dotenv express
npm install -D @types/node @types/express typescript tsx
npx tsc --init --target es2022 --module nodenext --moduleResolution nodenext --strict

Si prefieres CommonJS o JavaScript puro, salta el último comando y tsx. El SDK funciona en ambos.

Estructura mínima:

mi-app-facturacion/
├── .env
├── .gitignore
├── package.json
├── tsconfig.json
└── src/
├── factuplan.ts # cliente del SDK
├── emitir-factura.ts # ejemplo básico
└── webhooks.ts # endpoint webhooks

En .gitignore añade siempre:

.env
node_modules/
dist/

Paso 2 — Inicializar el cliente

src/factuplan.ts
import "dotenv/config"
import { Factuplan } from "factuplan"
if (!process.env.FACTUPLAN_API_KEY) {
throw new Error("FACTUPLAN_API_KEY no está definida en .env")
}
export const factuplan = new Factuplan(process.env.FACTUPLAN_API_KEY, {
ruc: process.env.FACTUPLAN_RUC!,
})

Tip: importa este archivo desde cualquier módulo. El SDK reutiliza la misma conexión HTTP, no se crea un nuevo cliente por request.

Paso 3 — Emitir tu primera factura

src/emitir-factura.ts
import { factuplan } from "./factuplan.js"
async function main() {
const factura = await factuplan.invoices.create({
customer: {
identificationType: "RUC",
identification: "0993378150001",
legalName: "Cliente Demo S.A.",
email: "facturas@cliente-demo.ec",
saveToContacts: true,
},
items: [
{
code: "SERV-001",
description: "Desarrollo web mensual",
quantity: 1,
unitPrice: 500,
taxType: "IVA_RATE",
tax: 15,
},
],
payments: [
{
method: "20", // Transferencia bancaria (catálogo SRI)
amount: 575, // 500 + IVA 15%
},
],
sendEmail: true,
})
console.log("✅ Factura emitida")
console.log("Clave de acceso:", factura.accessKey)
console.log("ID:", factura.id)
console.log("Estado:", factura.status) // DRAFT: la emisión sigue en segundo plano
// El PDF y el XML se piden aparte, cuando la factura ya está en COMPLETED
// (AUTHORIZED es un estado de paso: el SRI ya autorizó y el PDF puede no estar listo):
// const { status } = await factuplan.invoices.getStatus(factura.id)
// const { url: pdfUrl } = await factuplan.invoices.downloadPdf(factura.id)
// const { url: xmlUrl } = await factuplan.invoices.downloadXml(factura.id)
}
main().catch(console.error)

Ejecútalo:

Ventana de terminal
npx tsx src/emitir-factura.ts

Deberías ver algo como:

✅ Factura emitida
Clave de acceso: 1305202401099337815000110010010000056781234567811
ID: 0199c2d4-7b1e-7c3a-9f40-2d6a8e5b1c77
Estado: DRAFT

create() responde enseguida con la factura en DRAFT: la firma, el envío al SRI, el PDF y el correo siguen en segundo plano. En pruebas, la autorización del SRI es simulada. En producción depende del SRI y suele tardar unos segundos. El estado final es COMPLETED (AUTHORIZED es un estado de paso: el SRI ya autorizó y el PDF puede no estar listo); consúltalo con factuplan.invoices.getStatus(factura.id) o espera el webhook invoice.authorized.

Paso 4 — Manejo de errores

En producción siempre vas a encontrar errores. El SDK los lanza tipados:

import { FactuplanError, AuthenticationError, RateLimitError } from "factuplan"
import { factuplan } from "./factuplan.js"
async function emitirConManejo() {
try {
const factura = await factuplan.invoices.create({ /* ... */ })
return { ok: true, factura }
} catch (err) {
if (err instanceof AuthenticationError) {
// API key inválida, revocada o vencida (401)
return { ok: false, kind: "auth", message: "Revisa tu FACTUPLAN_API_KEY" }
}
if (err instanceof RateLimitError) {
// Todo 429 — superaste el límite de peticiones: espera y repite la misma petición.
// Si tu API key tiene un límite mensual propio y lo agotó, también llega aquí:
// el mensaje lo dice y esperar no lo resuelve.
return { ok: false, kind: "limite", message: err.message }
}
if (err instanceof FactuplanError) {
// Cualquier otro error de la API: 400 validación (GENERAL_0002), 403 plan o cupo,
// 409 devReference (API_10011 / API_10012), 5xx…
return { ok: false, kind: "api", status: err.statusCode, code: err.code, message: err.message, details: err.details }
}
// Error de red o timeout (el SDK corta a los 30 s y no reintenta).
// Un rechazo del SRI no llega aquí: aparece después como estado REJECTED / RETURNED
// o en el webhook invoice.rejected.
throw err
}
}

Errores más frecuentes en producción

ErrorCausa típicaSolución
AuthenticationError (401)API key faltante, revocada o vencidaRevisar .env y el prefijo de la key
FactuplanError 400 con GENERAL_0002Datos inválidos: por ejemplo un RUC que no tiene 13 dígitos terminados en 001, o un campo que la API no conoceCorregir el body; el detalle llega en err.details.validation
FactuplanError 403 con SUB_12002Se acabó el cupo de documentos de tu planSubir de plan o renovar tu suscripción
FactuplanError 409 con API_10011 / API_10012La devReference ya pertenece a otro documento (contenido distinto) o a uno anuladoUsar una referencia nueva; los datos del documento existente llegan en err.details
RateLimitError (429)Superaste el límite de peticionesEsperar y repetir la petición con la misma devReference
RateLimitError (429) cuyo mensaje habla del límite mensualLa API key tiene un límite mensual propio y lo agotóReintentar no lo resuelve
FactuplanError 5xx, o un error de red o timeout (estos dos no son FactuplanError)Caída temporalEl SDK no reintenta: repite tú la petición con la misma devReference
Estado REJECTED / RETURNED (no es una excepción)El SRI no aceptó el comprobante; lo ves con getStatus() o en el webhook invoice.rejectedLeer los mensajes del SRI, corregir y emitir de nuevo con otra devReference

Paso 5 — Webhooks

Para apps reales no basta con “fire and forget”. Configura webhooks para enterarte de:

  • invoice.authorized — el SRI autorizó.
  • invoice.rejected — el SRI rechazó (necesitas reaccionar).
  • credit_note.authorized — nota de crédito aprobada.
  • waybill.authorized — guía de remisión aprobada (las guías se emiten desde el panel: no existe /v1/developer/waybills).

Configurar el endpoint en Factuplan

  1. Dashboard → Developer → Webhooks.
  2. Agrega tu URL (https://tu-app.com/webhooks/factuplan).
  3. Copia el webhook secret (lo necesitas para verificar firmas).

Implementar el endpoint con Express

src/webhooks.ts
import "dotenv/config"
import express from "express"
import { verifyWebhookSignature } from "factuplan"
const app = express()
app.post(
"/webhooks/factuplan",
express.raw({ type: "application/json" }),
(req, res) => {
const valida = verifyWebhookSignature(
req.body, // Buffer crudo, gracias a express.raw()
req.headers["x-factuplan-signature"],
process.env.FACTUPLAN_WEBHOOK_SECRET!,
)
if (!valida) {
console.error("Firma de webhook inválida")
res.status(400).send("Invalid signature")
return
}
const event = JSON.parse(req.body.toString("utf-8"))
switch (event.event) {
case "invoice.authorized":
console.log("✅ Autorizada:", event.data.accessKey)
// Tu lógica: marcar pedido como facturado, notificar al cliente, etc.
// Si emitiste con devReference, event.data.devReference trae tu referencia
// (junto con event.data.environment: TESTING o PRODUCTION).
break
case "invoice.rejected":
console.error("❌ Rechazada por SRI:", event.data.reason)
// Tu lógica: avisar al ops team, corregir y emitir de nuevo, etc.
break
case "credit_note.authorized":
console.log("✅ NC autorizada:", event.data.accessKey)
break
}
res.json({ received: true })
},
)
const PORT = process.env.PORT || 3000
app.listen(PORT, () => console.log(`Webhook listener en :${PORT}`))

Importante: usa express.raw() para este endpoint (no express.json()). La verificación HMAC necesita el body sin parsear.

Probar webhooks localmente

Usa ngrok o cloudflared tunnel para exponer localhost:3000 a internet:

Ventana de terminal
ngrok http 3000
# Copia el URL https que te da y úsalo en el dashboard de Factuplan
Factuplan — activa tu cuenta y emite tu primera factura electrónica autorizada por el SRI.

Paso 6 — Patrón para apps web (Next.js)

Si estás en Next.js App Router, usa Server Actions:

app/actions/emitir-factura.ts
"use server"
import { factuplan } from "@/lib/factuplan"
import { revalidatePath } from "next/cache"
export async function emitirFacturaAction(formData: FormData) {
try {
const factura = await factuplan.invoices.create({
customer: {
identificationType: "RUC",
identification: formData.get("ruc") as string,
legalName: formData.get("legalName") as string,
email: formData.get("email") as string,
},
items: [
{
code: "SERV-001",
description: formData.get("descripcion") as string,
quantity: 1,
unitPrice: Number(formData.get("precio")),
taxType: "IVA_RATE",
tax: 15,
},
],
sendEmail: true,
})
revalidatePath("/facturas")
return { ok: true, id: factura.id, accessKey: factura.accessKey, status: factura.status }
} catch (err) {
return { ok: false, error: (err as Error).message }
}
}

Y en el componente cliente:

app/facturas/nueva/page.tsx
import { emitirFacturaAction } from "@/actions/emitir-factura"
export default function NuevaFactura() {
return (
<form action={emitirFacturaAction}>
<input name="ruc" required />
<input name="legalName" required />
<input name="email" type="email" required />
<input name="descripcion" required />
<input name="precio" type="number" step="0.01" required />
<button>Emitir</button>
</form>
)
}

Paso 7 — Patrón para apps backend (NestJS)

src/facturacion/facturacion.service.ts
import { Injectable } from "@nestjs/common"
import { Factuplan } from "factuplan"
@Injectable()
export class FacturacionService {
private readonly factuplan: Factuplan
constructor() {
this.factuplan = new Factuplan(process.env.FACTUPLAN_API_KEY!, {
ruc: process.env.FACTUPLAN_RUC!,
})
}
async emitirFactura(data: EmisionDTO) {
return this.factuplan.invoices.create({
customer: {
identificationType: data.identificationType,
identification: data.identification,
legalName: data.legalName,
email: data.email,
},
items: data.items.map((item) => ({
code: item.code,
description: item.description,
quantity: item.quantity,
unitPrice: item.unitPrice,
taxType: "IVA_RATE",
tax: 15,
})),
sendEmail: true,
})
}
}

Paso 8 — Testing

Para tests unitarios sin llamar al SRI real, usa mocks de Jest/Vitest:

__tests__/emitir.test.ts
import { describe, it, expect, vi } from "vitest"
vi.mock("factuplan", () => ({
Factuplan: vi.fn().mockImplementation(() => ({
invoices: {
create: vi.fn().mockResolvedValue({
id: "0199c2d4-7b1e-7c3a-9f40-2d6a8e5b1c77",
accessKey: "1305202401099337815000110010010000056781234567811",
sequential: "000005678",
status: "DRAFT",
total: "575",
}),
},
})),
}))
describe("emitirFactura", () => {
it("emite con datos válidos", async () => {
const { emitirFactura } = await import("../src/emitir.js")
const result = await emitirFactura({ /* ... */ })
expect(result.accessKey).toHaveLength(49)
})
})

Para tests end-to-end contra Factuplan, usa siempre la API key de pruebas (ak_test_*) y no la de producción.

Buenas prácticas en producción

1. Idempotencia

Si tu sistema reintenta una emisión por timeout, evita facturas duplicadas enviando tu propia referencia en el campo devReference del body (texto libre de 1 a 100 caracteres, por ejemplo tu número de pedido). No existe ningún header de idempotencia: ni Idempotency-Key ni X-Idempotency-Key tienen efecto.

const factura = await factuplan.invoices.create({
...payload, // customer, items, payments…
devReference: `pedido-${pedidoId}`, // la MISMA en cada reintento
})
if (factura.duplicate) {
// Ya existía: esta llamada no emitió nada nuevo.
// Mira factura.status para saber en qué quedó (en proceso, COMPLETED, REJECTED…).
}

La referencia es única por contribuyente, ambiente y tipo de documento. Si repites la petición con la misma referencia y el mismo contenido, la API responde 201 con la factura que ya existía y duplicate: true (revisa su status). Con la misma referencia y otro contenido responde 409 (API_10011), y si ese documento fue anulado, 409 (API_10012). En pruebas los comprobantes se borran cada hora y su referencia vuelve a quedar libre; en producción una referencia usada queda ocupada para siempre.

2. Reintentos cuando no llegó la respuesta

Si la red se cae después del POST pero antes de recibir la respuesta, no emitas otra factura con una referencia distinta. Repite la misma petición con la misma devReference: si la primera llegó, recibes esa factura con duplicate: true; si no llegó, se emite ahora. También puedes buscarla primero por tu referencia:

const { data } = await factuplan.invoices.list({ devReference: `pedido-${pedidoId}` })
const existente = data[0] // cero o un documento: undefined si todavía no existe

3. Backoff exponencial

El SDK no reintenta por su cuenta (hace una sola petición y la corta a los 30 segundos). Si quieres reintentar, hazlo tú con backoff y solo ante fallos temporales, y en las emisiones envía siempre la misma devReference para que un reintento nunca emita dos veces:

import { FactuplanError, RateLimitError } from "factuplan"
function esReintentable(err: unknown): boolean {
if (err instanceof RateLimitError) return true // 429: limita siempre el número de reintentos
if (err instanceof FactuplanError) {
// 5xx, o 408 si la API cortó la petición. Un 400, 401, 403 o 409
// responden lo mismo aunque repitas.
return err.statusCode >= 500 || err.statusCode === 408
}
return true // error de red o timeout: no llegó ninguna respuesta
}
async function withBackoff<T>(fn: () => Promise<T>, maxAttempts = 5): Promise<T> {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
return await fn()
} catch (err) {
if (attempt === maxAttempts - 1 || !esReintentable(err)) throw err
const delay = Math.min(1000 * Math.pow(2, attempt), 30000)
await new Promise((r) => setTimeout(r, delay))
}
}
throw new Error("unreachable")
}
// El mismo payload, con la misma devReference, en todos los intentos
const factura = await withBackoff(() =>
factuplan.invoices.create({ ...payload, devReference: `pedido-${pedidoId}` }),
)

4. Logs estructurados

Loguea siempre id, accessKey, status y tu devReference para poder debuggear:

import pino from "pino"
const log = pino()
try {
const factura = await factuplan.invoices.create(payload)
log.info(
{
id: factura.id,
accessKey: factura.accessKey,
status: factura.status,
devReference: factura.devReference,
duplicate: factura.duplicate,
},
"factura emitida",
)
} catch (err) {
log.error({ err, payload }, "error emitiendo factura")
}

5. Variables de entorno por ambiente

Usa keys distintas en development, staging y producción:

.env.development
FACTUPLAN_API_KEY=ak_test_dev_xxx
FACTUPLAN_WEBHOOK_SECRET=whsec_dev_xxx
# .env.production
FACTUPLAN_API_KEY=ak_live_prod_xxx
FACTUPLAN_WEBHOOK_SECRET=whsec_prod_xxx

Troubleshooting

”AuthenticationError” (401)

Causa: la key no existe, fue revocada o venció. Pruebas y producción usan el mismo host: el ambiente lo decide el prefijo de la key (ak_test_ o ak_live_).

Solución: regenerar en el dashboard de Factuplan y actualizar .env.

”RUC del cliente inválido”

El SDK no valida nada en local: el error llega de la API como FactuplanError 400 (GENERAL_0002), con el detalle en err.details.validation. La API comprueba el formato (13 dígitos terminados en 001 para RUC, 10 dígitos para cédula), no el dígito verificador.

Solución: valida el dígito verificador en tu sistema antes de enviar, por ejemplo con la herramienta de validación de RUC.

”La factura se queda en proceso”

create() no espera al SRI: responde enseguida con la factura en DRAFT y la autorización sigue en segundo plano. En horas pico el SRI puede tardar más de lo normal.

Solución: no bloquees tu petición esperando. Espera el webhook invoice.authorized o consulta factuplan.invoices.getStatus(id) hasta COMPLETED. El SDK corta cada petición a los 30 segundos y no reintenta.

”EAI_AGAIN” o “ECONNRESET”

Errores de red transitorios.

Solución: el SDK no reintenta; repite tú la petición (con la misma devReference si era una emisión). Si persiste, revisa la conectividad de tu servidor con api-rest.factuplan.com.ec.

Repositorio de ejemplo

El repo de referencia con todos estos snippets se publicará en GitHub pronto. Por ahora puedes clonar el quickstart desde el hub de developers (próximamente en factuplan.com.ec/desarrolladores).

Resumen práctico

  1. Instala factuplan y dotenv en tu proyecto Node.js 18+.
  2. Crea API key de pruebas en app.factuplan.com.ec.
  3. Inicializa el cliente con API key + RUC.
  4. Emite tu primera factura en 10 líneas con factuplan.invoices.create({ ... }).
  5. Configura webhooks para reaccionar a estados de autorización del SRI.
  6. Maneja errores tipados (FactuplanError, AuthenticationError, RateLimitError).
  7. Usa devReference para la idempotencia, backoff, logs estructurados y variables de entorno por ambiente.

Crea tu API key gratis → y empieza con el plan freemium (25 facturas/mes sin tarjeta).


Referencia completa de la API: factuplan.com.ec/docs/api Referencia del SDK: factuplan.com.ec/docs/sdk Colección Postman: descarga desde tu dashboard de Factuplan.

Preguntas frecuentes

¿Puedo emitir facturas electrónicas en Node.js sin pasar por un servicio como Factuplan?

Técnicamente sí, pero implica resolver por tu cuenta: 1) Generación de XMLs según la ficha técnica del SRI v2.32 con todos los campos obligatorios y reglas de cascada IVA/ICE; 2) Firma electrónica XAdES-BES con tu certificado P12 (cargar el P12, extraer la cadena de certificados, firmar el XML con el algoritmo correcto); 3) Comunicación con los webservices SOAP del SRI (recepción y autorización) en lugar de REST; 4) Manejo de la clave de acceso de 49 dígitos con dígito verificador módulo 11; 5) Generación del RIDE PDF con QR. Es viable en proyectos donde tienes recursos para mantener todo eso, pero la mayoría de empresas usan un servicio como Factuplan para evitarse meses de desarrollo y mantenimiento continuo cada vez que el SRI publica una nueva ficha técnica.

¿Cómo manejo timeouts cuando el SRI tarda en autorizar?

El esquema offline del SRI puede tardar desde unos segundos en horarios normales hasta varios minutos en cierres de mes o picos de declaración. La API no te hace esperar al SRI: create() responde enseguida con la factura en estado DRAFT y la emisión sigue en segundo plano, así que no necesitas un timeout HTTP amplio. Hay dos patrones en Node.js: 1) Webhooks: devuelves a tu cliente la clave de acceso con la factura en proceso y actualizas el estado cuando llegue invoice.authorized (o invoice.rejected / invoice.error); 2) Polling: consultas factuplan.invoices.getStatus(id) cada N segundos hasta COMPLETED (AUTHORIZED es un estado de paso: el SRI ya autorizó y el PDF puede no estar listo) o hasta REJECTED, RETURNED o ERROR. La opción 1 (webhooks) es la más limpia para producción porque desacopla la UX del tiempo del SRI y no bloquea tu servidor con peticiones largas.

¿Cuál es el RUC para usar en pruebas con el SDK?

Para pruebas debes usar el RUC asociado a tu workspace de Factuplan al crearlo. Las API keys de prueba (prefijo ak_test_) generan comprobantes ficticios que NO se envían al SRI real (se mantienen en el sandbox interno de Factuplan y se borran cada hora). Puedes usar cualquier RUC válido sintácticamente para el cliente receptor en tus pruebas, por ejemplo el RUC de prueba estándar 0993378150001. En producción debes usar el RUC real de tu negocio, con la firma electrónica P12 vigente cargada en tu workspace, y los comprobantes se envían al SRI real con autorización efectiva.

¿Qué pasa si el SRI rechaza una factura? ¿Cómo lo manejo en Node.js?

El rechazo del SRI no llega como una excepción de create(): la emisión es asíncrona, create() responde con la factura en DRAFT y el rechazo aparece después como estado REJECTED o RETURNED. Te enteras de dos formas: por el webhook invoice.rejected, cuyo data.reason trae los mensajes del SRI, o consultando el estado con factuplan.invoices.getStatus(id). Patrón recomendado: loguea el id, la accessKey y los mensajes del SRI para tener trazabilidad y decide según el motivo. Si fue un problema temporal, factuplan.invoices.retry(id) vuelve a procesar el mismo comprobante (tras un rechazo lo regenera con una clave de acceso nueva y los mismos datos). Si el rechazo fue por datos inválidos, el reintento volverá a fallar: corrige los datos y emite una factura nueva con otra devReference.

¿Cómo configuro webhooks de Factuplan en una app Node.js detrás de un proxy o load balancer?

El webhook se verifica con el header x-factuplan-signature, que tiene la forma t=<timestamp>,v1=<firma>: la firma es el HMAC-SHA256, con tu webhook secret, de la cadena <timestamp>.<body crudo>. La función verifyWebhookSignature del SDK hace ese cálculo por ti y rechaza entregas con más de 5 minutos. Si tu app está detrás de NGINX, AWS ALB o Cloudflare, debes asegurar que: 1) El body llegue sin modificación al handler (no usar middleware que reparse JSON antes del verificador); 2) En Express, usar express.raw({ type: 'application/json' }) específicamente en la ruta del webhook, ANTES que cualquier express.json() global; 3) El path del webhook esté expuesto en el ALB/proxy sin reescritura del body; 4) Si tu handler recibe un Request estándar (por ejemplo un Route Handler de Next.js), lee el body crudo con await request.text() y pásalo tal cual a verifyWebhookSignature, en lugar de usar await request.json(). Si la verificación falla con cuerpo válido, casi siempre es porque algún middleware reparseó el body.

¿Puedo emitir facturas con consumidor final desde Node.js?

Sí. En la propiedad customer del SDK, usa identificationType FINAL_CONSUMER en lugar de RUC o CEDULA, e identification con valor '9999999999999' (trece nueves; es el único valor que la API acepta para ese tipo). legalName puede ser 'CONSUMIDOR FINAL'. El campo email es obligatorio también para consumidor final: si falta, la API responde 400. El SRI permite consumidor final hasta el monto máximo establecido en la normativa vigente (verifica el monto actualizado en la guía de monto a consumidor final). Para montos superiores debes solicitar al cliente RUC o cédula. Algunos comercios (restaurantes, farmacias, comercio masivo) emiten todo a consumidor final por velocidad, lo cual es legal mientras no excedan el monto tope por transacción.

¿Es seguro guardar la API key de Factuplan en variables de entorno del servidor?

Sí, siempre que el servidor esté correctamente configurado. Buenas prácticas: 1) Usar un gestor de secretos (AWS Secrets Manager, Vercel Environment Variables, Doppler, 1Password Secrets Automation) en lugar de archivos .env en producción; 2) Rotar la API key periódicamente (cada 3-6 meses); 3) Usar keys distintas por ambiente (dev, staging, prod) con permisos granulares cuando estén disponibles; 4) Auditar los logs de uso de la API key en el dashboard de Factuplan para detectar acceso anómalo; 5) Tener un procedimiento documentado de revocación rápida (botón en el dashboard) si sospechas filtración; 6) Nunca commitear .env al repositorio (siempre en .gitignore). Lo que NO debes hacer es exponer la key en NEXT_PUBLIC_, VITE_PUBLIC_ ni en código JavaScript del lado del cliente.

Tags: #api
Compartir:

¿Te sirvió este artículo? Marca a Factuplan como fuente preferida y aparecerá más en tus resultados de Google.

Añadir a fuentes preferidas
FirmaOK

¿Aún no tienes firma electrónica?

Sin ella no puedes emitir comprobantes ante el SRI. Consíguela 100% en línea.

Compra tu firma electrónica
Facturación electrónica
Pantalla de inicio de factuplan.com.ec, el sistema de facturación electrónica

Adquiere tu plan de facturación

Emite facturas, notas de crédito y guías de remisión autorizadas por el SRI desde cualquier dispositivo. Activa tu cuenta en minutos.

  • Autorización del SRI en segundos
  • Empieza gratis con 25 facturas al mes
  • Soporte en español, sin contratos
Adquiere tu plan