Ir al contenido

SDKs

Los SDK oficiales envuelven la API de Flashpi con tipos generados del documento OpenAPI, reintentos seguros con Idempotency-Key, errores tipados (RFC 9457), paginación y verificación de firmas de webhooks. Hay siete: @flashpi/node para Node.js y TypeScript, flashpi para Python, flashpi/flashpi-php para PHP, ec.com.flashpi:flashpi-java para Java y Kotlin, Flashpi para C# y .NET, github.com/flashpi1/flashpi-go para Go y flashpi para Ruby. No son obligatorios: las guías usan HTTP simple, que funciona desde cualquier lenguaje, incluidos los sistemas de escritorio en Visual FoxPro y Delphi. En un lenguaje sin SDK, verifica los webhooks con cualquier librería de Standard Webhooks o a mano (consulta Webhooks).

Cada sección muestra los siete SDK en pestañas. Elige tu lenguaje en cualquiera de ellas y toda la página lo sigue.

@flashpi/node es el SDK oficial para Node.js y TypeScript. Su código está en GitHub, con licencia MIT.

  • Cubre todas las operaciones de la API: los seis comprobantes, la consulta de comprobantes (XML, RIDE y correo), los emisores (incluida su creación desde el .p12) con sus establecimientos, puntos de emisión y certificados, los endpoints de webhooks, los eventos y el estado de la API.
  • Funciona en Node.js 22 o superior, Bun, Deno y Cloudflare Workers, con import o require, y no tiene dependencias.
  • Corre solo en el servidor: tu API key es secreta, así que el SDK se niega a correr en un navegador.
Ventana de terminal
npm install @flashpi/node

También con pnpm add @flashpi/node, yarn add @flashpi/node o bun add @flashpi/node.

Crea en la consola una API key de prueba con alcance Toda la cuenta (account) y acceso de lectura y escritura, y guárdala en la variable de entorno FLASHPI_API_KEY (consulta Autenticación y API keys). Con el emisor demo emites en el ambiente de pruebas del SRI sin un certificado propio: copia su ID del Resumen de la consola (consulta Sandbox y emisor demo).

import { Flashpi } from '@flashpi/node'
// Reads FLASHPI_API_KEY. You can also pass the key: new Flashpi('fp_test_...')
const flashpi = new Flashpi()
const invoice = await flashpi.invoices.create({
issuerId: '<demo issuer id>',
establishment: '001',
emissionPoint: '001',
customer: {
idType: 'ruc',
id: '1790000000001',
name: 'Supermercados La Pradera S.A.',
},
items: [
{
code: 'SRV-001',
description: 'Monthly accounting services',
quantity: '1',
unitPrice: '450.00',
taxes: [{ type: 'vat', rate: '15' }],
},
],
payments: [{ method: 'other_financial_system', amount: '517.50' }],
options: { waitForAuthorization: true },
})
console.log(invoice.status, invoice.accessKey)

En Cloudflare Workers no hay variables de entorno globales: pasa la clave desde env, con new Flashpi(env.FLASHPI_API_KEY). En Deno, leer la variable necesita el permiso --allow-env=FLASHPI_API_KEY.

Los montos y las cantidades van como texto ('450.00'), nunca como números, para no perder decimales. Con options.waitForAuthorization, la solicitud espera la respuesta del SRI y devuelve authorized, rejected o failed; si el SRI tarda más, devuelve processing o pending_sri y el comprobante sigue su curso. Sin esa opción, la respuesta llega enseguida con el estado processing y la decisión del SRI llega por webhook (invoice.authorized o invoice.rejected). Un comprobante failed todavía no genera un evento: búscalo con flashpi.documents.list({ status: 'failed' }). Consulta Modo síncrono y asíncrono y Ciclo de vida del comprobante.

Los demás comprobantes siguen el mismo patrón, cada uno con su create(body): creditNotes, debitNotes, purchaseSettlements, waybills y withholdings.

Cada error de la API se lanza como un APIError, con la subclase de su estado HTTP cuando la hay (por ejemplo UnprocessableEntityError para 422). Decide según code, que es estable y en inglés. El mensaje sigue el idioma que pidas: new Flashpi({ language: 'es' }) da los mensajes en español.

import { APIError, UnprocessableEntityError } from '@flashpi/node'
try {
await flashpi.invoices.create(body)
} catch (error) {
if (error instanceof UnprocessableEntityError) {
console.log(error.code) // 'validation_failed', 'total_mismatch', ...
for (const field of error.errors) console.log(field.field, field.message)
} else if (error instanceof APIError) {
console.log(error.status, error.code, error.requestId) // share requestId with support
}
throw error
}

Consulta los códigos y qué hacer con cada uno en Errores.

Cada SDK reintenta hasta dos veces, con una espera creciente, los errores de red, los tiempos agotados y las respuestas 408, 429 y 5xx, salvo el 501 y cuando la API pide esperar más de 60 segundos (como en los límites diarios). Tampoco reintenta el 503 demo_issuer_unavailable: un reintento segundos después no lo resuelve.

Cada emisión lleva una Idempotency-Key que se repite en sus reintentos, así que un reintento nunca emite dos veces: si el primer intento ya creó el comprobante, el SDK te devuelve ese comprobante.

Para usar tu propia clave, por ejemplo el ID de tu pedido, pásala en las opciones de la llamada:

await flashpi.invoices.create(body, { idempotencyKey: `order-${order.id}` })

Consulta Idempotencia.

Una lista devuelve una página.

Con for await recorres todas las páginas, que el SDK pide a medida que avanzas:

for await (const document of flashpi.documents.list({ status: 'authorized' })) {
console.log(document.accessKey)
}

Consulta Paginación.

unwrapWebhook verifica la firma con el cuerpo tal como llegó, sin interpretarlo, y el secreto whsec_ del endpoint, y te devuelve el evento con su tipo. No necesita API key. Funciona en Next.js, Hono, Cloudflare Workers y cualquier entorno con Request; con Express, lee el cuerpo con express.raw({ type: 'application/json' }).

import { unwrapWebhook, WebhookVerificationError } from '@flashpi/node'
export async function POST(request: Request): Promise<Response> {
let event
try {
event = await unwrapWebhook(
await request.text(),
request.headers,
process.env.FLASHPI_WEBHOOK_SECRET ?? '',
)
} catch (error) {
if (error instanceof WebhookVerificationError) return new Response(null, { status: 400 })
throw error
}
switch (event.type) {
case 'webhook_endpoint.verification':
// The endpoint's activation: answer the challenge.
return Response.json({ challenge: event.data.challenge })
case 'invoice.authorized':
console.log('Authorized', event.data.accessKey) // event.data is the document
break
}
return new Response(null, { status: 204 })
}

Guarda el event.id (el mismo valor del encabezado webhook-id) y, si se repite, responde 2xx sin volver a hacer el trabajo: un evento puede llegar más de una vez.

El ejemplo supone el modo full del endpoint, el predeterminado. En el modo thin los eventos, salvo la verificación, llegan sin data: usa unwrapWebhook<ThinWebhookEvent>(...) (el tipo también se importa de @flashpi/node) y lee el evento con flashpi.events.get(event.id). Consulta Webhooks y su Contenido.

El README del SDK documenta el resto: la consulta de comprobantes (XML, RIDE en PDF y reenvío por correo), la creación de emisores desde su .p12 y sus certificados, las opciones de cada llamada y cómo leer la respuesta HTTP completa.

  • Un paquete para Laravel, aparte del SDK de PHP. Mientras tanto, flashpi/flashpi-php funciona en Laravel tal como es: la pestaña PHP de esta página muestra cómo registrarlo en un service provider y cómo recibir los webhooks en un controlador.