Resumen de los SDKs
SDKs oficiales de TypeScript y PHP para la API de Factuarea — instala @factuarea/sdk o factuarea/factuarea-php y obtén reintentos, idempotencia, paginación por cursor, errores tipados y verificación de webhooks de serie.
Los SDK oficiales de Factuarea ofrecen reintentos automáticos, idempotencia, paginación por cursor, errores tipados, verificación de webhooks y descargas binarias para su catálogo de métodos publicado. REST expone actualmente 469 operaciones en 41 recursos; consulta la cobertura de versiones al final.
TypeScript / Node.js
@factuarea/sdk en npm. ESM + CommonJS dual, declaraciones de tipos completas.
Código fuente: github.com/factuarea/factuarea-node.
PHP
factuarea/factuarea-php en Packagist. PSR‑4, basado en Guzzle, PHP 8.2+.
Código fuente: github.com/factuarea/factuarea-php.
Pre‑GA (0.x). Ambos SDKs están en 0.x. La superficie pública de
métodos es estable y sigue el
contrato de nomenclatura de métodos del SDK,
protegido por SemVer — pero mientras esté en 0.x, las versiones minor
pueden incluir cambios incompatibles hasta 1.0.0, que coincide con la GA
de la API. Cada release fija una
Factuarea-Version y la envía en cada request, de
modo que el comportamiento de la API se mantiene estable hasta que
actualizas el SDK.
Solo en el servidor. Tu API key es un secreto. Nunca incluyas un SDK con una clave live en un navegador, app móvil o cualquier cliente público — usa el SDK desde tu backend.
Instalación
npm install @factuarea/sdkRequiere Node 20 o superior. El SDK está construido sobre el estándar
Web fetch, así que también funciona en Deno, Bun y Cloudflare Workers.
composer require factuarea/factuarea-phpRequiere PHP 8.2 o superior con las extensiones json y mbstring
(ambas incluidas en las builds estándar de PHP).
Autenticación y entornos
Pasa tu API key. El prefijo de la clave selecciona el entorno — no hay
un flag aparte: una clave fact_test_… siempre se ejecuta contra el
sandbox aislado, y una clave fact_live_… contra
producción.
import { Factuarea } from "@factuarea/sdk";
const factuarea = new Factuarea({ apiKey: process.env.FACTUAREA_API_KEY! });
factuarea.environment; // "test" or "live", derived from the key prefixConfiguración opcional:
new Factuarea({
apiKey: "fact_live_…", // required
baseUrl: "https://api.factuarea.com/v1", // override for staging
timeout: 60_000, // per-request ms (default 60s)
maxRetries: 2, // attempts after the first try
factuareaVersion: "2026-06-04", // pinned API version header
defaultHeaders: {}, // extra headers on every request
});<?php
require 'vendor/autoload.php';
use Factuarea\Sdk\Custom\FactuareaClient;
// The key prefix selects the environment:
// fact_test_… → sandbox fact_live_… → production
$factuarea = FactuareaClient::create(getenv('FACTUAREA_API_KEY'));FactuareaClient::create() es el punto de entrada recomendado: conecta la
autenticación Bearer y registra por ti el comportamiento automático de
Idempotency-Key. Para configuración avanzada (cliente Guzzle
personalizado, política de reintentos personalizada, base URL de staging)
el builder generado sigue disponible:
use Factuarea\Sdk\Factuarea;
use Factuarea\Sdk\Models\Components\Security;
$factuarea = Factuarea::builder()
->setSecurity(new Security(bearerAuth: getenv('FACTUAREA_API_KEY')))
->setServerURL('https://api.factuarea.com/v1')
->build();Inicio rápido
Crea un contacto con rol de cliente y una factura, y descarga su PDF con los métodos publicados del SDK que aparecen a continuación. Para otras operaciones, comprueba tu SDK instalado o usa el ejemplo HTTP de la referencia de la API.
La creación del contacto en PHP usa HTTP con Guzzle, que el SDK PHP ya requiere. Así funciona sin asumir que tu versión PHP instalada tiene métodos de contactos generados. El SDK de facturas conserva clientId: pasa el id del contacto con rol customer activo.
import { Factuarea } from "@factuarea/sdk";
const factuarea = new Factuarea({ apiKey: process.env.FACTUAREA_API_KEY! });
// Responses are the API's `{ data: … }` envelope — read the resource off `.data`.
// 1. Create a customer contact.
const { data: contact } = await factuarea.contacts.create({
name: "Cliente Demo SL",
kind: "company",
roles: ["customer"],
tax_id: "B12345674",
});
// 2. Create an invoice (the API computes the totals).
const { data: invoice } = await factuarea.invoices.create({
client_id: contact.id,
series_id: "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0e",
issued_on: "2026-06-05",
due_on: "2026-07-05",
lines: [
{
description: "Consultoría — junio 2026",
quantity: 10,
unit_price: 100,
tax_rate_id: "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0f",
},
],
});
// 3. Download the PDF (a BinaryResponse, not JSON).
const pdf = await factuarea.invoices.pdf(invoice.id);
await import("node:fs/promises").then((fs) =>
fs.writeFile("invoice.pdf", pdf.toBuffer()),
);<?php
require 'vendor/autoload.php';
use Factuarea\Sdk\Custom\FactuareaClient;
use Factuarea\Sdk\Models\Components;
use Brick\DateTime\LocalDate;
$factuarea = FactuareaClient::create(getenv('FACTUAREA_API_KEY'));
// 1. Create a customer contact.
$http = new \GuzzleHttp\Client();
$response = $http->post('https://api.factuarea.com/v1/contacts', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('FACTUAREA_API_KEY'),
'Idempotency-Key' => bin2hex(random_bytes(16)),
],
'json' => [
'name' => 'Cliente Demo SL',
'kind' => 'company',
'roles' => ['customer'],
'tax_id' => 'B12345674',
],
]);
$contact = json_decode((string) $response->getBody(), true, 512, JSON_THROW_ON_ERROR)['data'];
// 2. Create an invoice (the API computes the totals).
$invoice = $factuarea->invoices->publicApiV1InvoicesCreate(
new Components\CreateInvoiceRequest(
clientId: $contact['id'],
seriesId: '01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0e',
issuedOn: LocalDate::parse('2026-06-05'),
dueOn: LocalDate::parse('2026-07-05'),
lines: [
new Components\CreateInvoiceRequestLine(
description: 'Consultoría — junio 2026',
quantity: 10,
unitPrice: 100,
taxRateId: '01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0f',
),
],
),
);
// 3. Download the PDF.
$pdf = $factuarea->invoices->publicApiV1InvoicesPdf($invoice->object->data->id);
file_put_contents('invoice.pdf', $pdf->bytes ?? '');Ejecuta todo primero con una clave fact_test_ — los efectos del
sandbox (VeriFactu → AEAT, FACe, email, webhooks) están desactivados. Cuando tu
flujo funcione de extremo a extremo, cambia el prefijo a fact_live_. La
superficie de la API es idéntica en ambos. Consulta Test mode &
sandbox.
Funciones en tiempo de ejecución
Ambos SDKs comparten el mismo runtime escrito a mano sobre la superficie tipada generada:
- Reintentos automáticos — los fallos transitorios (
429y5xx, además de errores de red en TypeScript) se reintentan con backoff exponencial y jitter, respetando el headerRetry-After. Los errores de cliente deterministas (p. ej. validación422) nunca se reintentan. - Idempotencia automática — cada mutación recibe una
Idempotency-Keygenerada para que un request reintentado nunca cree un recurso por duplicado. Anúlala por llamada cuando quieras deduplicación a nivel de app. Consulta Idempotency. - Auto‑paginación por cursor — los métodos de listado devuelven un
iterable que recorre todas las páginas por ti, gestionando
next_cursor/has_more. Consulta Paginar con el SDK. - Errores tipados — el envoltorio de error de la API se
mapea a una jerarquía de excepciones tipada que expone
code,type,request_idystatus. Tu API key nunca se incluye en ningún mensaje de error. Consulta Gestionar errores. - Verificación de webhooks — un verificador HMAC‑SHA256 de tiempo constante que respeta la ventana de gracia de rotación de secreto. Consulta Verificar webhooks.
- Descargas binarias — los endpoints de PDF y de ficheros devuelven una respuesta binaria que conviertes en un Buffer / stream, no JSON.
Paginación con el SDK
Los métodos de listado devuelven un Page, que es en sí mismo un async
iterable:
const page = await factuarea.invoices.list({ status: "paid", limit: 50 });
// (a) iterate every item across every page
for await (const invoice of page) {
console.log(invoice.id);
}
// (b) page by page
page.data; // items on this page
page.hasMore; // boolean
page.nextCursor; // opaque cursor or null
const next = await page.getNextPage(); // Page | null
// (c) collect everything into an array
const all = await page.toArray();El helper PageIterator transmite cada elemento a través de todas las
páginas sin gestión manual del cursor:
use Factuarea\Sdk\Custom\Pagination\PageIterator;
use Factuarea\Sdk\Models\Operations\PublicApiV1InvoicesListRequest;
$pages = new PageIterator(
fn (?string $cursor) => $factuarea->invoices->publicApiV1InvoicesList(
new PublicApiV1InvoicesListRequest(startingAfter: $cursor),
)->rawResponse,
);
// items() yields each item as a decoded associative array.
foreach ($pages->items() as $invoice) {
echo $invoice['id'], PHP_EOL;
}Consulta Pagination para conocer la semántica de cursor subyacente.
Gestión de errores
import {
FactuareaError,
ValidationError,
RateLimitError,
} from "@factuarea/sdk";
try {
await factuarea.invoices.create(body);
} catch (error) {
if (error instanceof ValidationError) {
console.error(error.fields); // { tax_id: ["NIF inválido"], … }
} else if (error instanceof RateLimitError) {
console.error(error.retryAfter); // seconds to wait
} else if (error instanceof FactuareaError) {
console.error(error.code, error.requestId);
}
}use Factuarea\Sdk\Models\Errors\ErrorThrowable;
try {
$factuarea->invoices->publicApiV1InvoicesCreate($body);
} catch (ErrorThrowable $e) {
$error = $e->container->error;
echo $error->type->value; // e.g. "invalid_request_error"
echo $error->code; // e.g. "parameter_invalid"
echo $error->param; // e.g. "client_id"
echo $error->requestId; // quote this to support
}Ramifica según el code estable, nunca según el message en español
orientado a personas. El catálogo completo está en Errors.
Verificación de webhooks
Pasa el cuerpo crudo del request (no un objeto re‑serializado), el header
Factuarea-Signature y el secreto del endpoint:
import { Factuarea, WebhookSignatureError, SIGNATURE_HEADER } from "@factuarea/sdk";
const factuarea = new Factuarea({ apiKey: process.env.FACTUAREA_API_KEY! });
// Express, with express.raw({ type: "application/json" }) on the route:
app.post("/webhooks/factuarea", (req, res) => {
try {
const event = factuarea.webhooks.verify(
req.body.toString("utf8"),
req.headers[SIGNATURE_HEADER.toLowerCase()] as string,
process.env.FACTUAREA_WEBHOOK_SECRET!,
);
if (event.type === "invoice.paid") { /* … */ }
res.sendStatus(200);
} catch (e) {
if (e instanceof WebhookSignatureError) return res.sendStatus(400);
throw e;
}
});use Factuarea\Sdk\Custom\Webhooks\WebhookVerifier;
use Factuarea\Sdk\Custom\Webhooks\WebhookSignatureException;
$verifier = new WebhookVerifier();
$rawBody = file_get_contents('php://input');
$signature = $_SERVER['HTTP_FACTUAREA_SIGNATURE'] ?? '';
try {
$event = $verifier->verify($rawBody, $signature, getenv('FACTUAREA_WEBHOOK_SECRET'));
// $event is the decoded, authenticated payload
} catch (WebhookSignatureException $e) {
http_response_code(400);
}La verificación usa HMAC‑SHA256 con una comparación de tiempo constante y una tolerancia de timestamp configurable (5 minutos por defecto) para rechazar replays, y acepta ambas firmas durante una ventana de gracia de rotación de secreto. Consulta Webhooks.
Snippets por endpoint
Cada página de la referencia de la API ofrece ejemplos HTTP en TypeScript, PHP y cURL generados desde el contrato OpenAPI documentado. Cubren la petición, sus cabeceras necesarias y el formato de respuesta sin depender de la cobertura de una versión del SDK.
Genera tu propio cliente
Si tu lenguaje todavía no está cubierto, o prefieres un cliente que tú controles y guardes en tu repo, el contrato canónico legible por máquina es el spec OpenAPI 3.1 — apunta cualquier generador a él.
Consulta el contrato OpenAPI documentado, exportado del backend y versionado con este portal.
npx openapi-typescript https://docs.factuarea.com/api/openapi \
-o src/factuarea.d.tsopenapi-python-client generate \
--url https://docs.factuarea.com/api/openapiopenapi-generator-cli generate \
-i https://docs.factuarea.com/api/openapi \
-g <language> -o ./factuarea-client<language> puede ser cualquier
generador soportado —
Go, Java, C#, Ruby, Rust y más.
Un cliente generado no incluirá el runtime del SDK oficial (reintentos, idempotencia, paginación, verificación de webhooks) — eso lo conectas tú mismo siguiendo las guías de conceptos clave.
¿Construyes con un asistente de IA?
Si quieres que un agente de IA opere Factuarea directamente en lugar de
generar código de cliente, conéctalo al servidor MCP — la API pública
expuesta como tools, con autenticación OAuth y por API key. Para Claude Code,
el plugin oficial factuarea-mcp lo configura en
dos comandos.
Cobertura de las versiones
La referencia de septiembre de 2026 es 0.2.0 para ambos SDK. Los specs de sus ramas principales contienen 413 entradas y todavía les faltan 39 endpoints REST. Es necesario actualizar el paquete para disponer de nuevos métodos generados. La referencia de la API ofrece ejemplos HTTP completos con fetch de TypeScript, cURL de PHP y terminal para el contrato documentado; estos ejemplos no presuponen que exista un método del SDK.