Factuarea API
SDKs

Visión general

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.

Factuarea ofrece SDKs oficiales que envuelven toda la API REST v1 (234 operaciones repartidas en 17 recursos) con un runtime premium para que no tengas que escribir HTTP a mano: reintentos automáticos, idempotency keys automáticas, auto‑paginación por cursor transparente, una jerarquía de errores tipada, verificación de webhooks tipada y descargas binarias (PDF).

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/sdk

Requiere 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-php

Requiere 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 prefix

Configuració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 cliente y una factura, y luego descarga su PDF. Cada operación es accesible como <resource>.<method> (TypeScript) o ->{resource}->publicApiV1{Resource}{Action} (PHP) siguiendo el contrato de nomenclatura — los snippets por endpoint de la referencia de la API muestran la llamada exacta para cada operación.

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 client.
const { data: client } = await factuarea.clients.create({
  name: "Cliente Demo SL",
  tax_id: "B98765432",
});

// 2. Create an invoice (the API computes the totals).
const { data: invoice } = await factuarea.invoices.create({
  client_id: client.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 client.
$client = $factuarea->clients->publicApiV1ClientsCreate(
    new Components\CreateClientRequest(
        name: 'Cliente Demo SL',
        taxId: 'B98765432',
    ),
);

// 2. Create an invoice (the API computes the totals).
$invoice = $factuarea->invoices->publicApiV1InvoicesCreate(
    new Components\CreateInvoiceRequest(
        clientId: $client->object->data->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 (429 y 5xx, además de errores de red en TypeScript) se reintentan con backoff exponencial y jitter, respetando el header Retry-After. Los errores de cliente deterministas (p. ej. validación 422) nunca se reintentan.
  • Idempotencia automática — cada mutación recibe una Idempotency-Key generada 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_id y status. 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 muestra un snippet de TypeScript, PHP y cURL listo para copiar para esa operación exacta, generado a partir del spec para que nunca se desvíen de la superficie real.

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.

El spec vive en https://docs.factuarea.com/api/openapi. Se genera a partir del mismo backend que sirve la API, así que nunca se desvía de la superficie real.

npx openapi-typescript https://docs.factuarea.com/api/openapi \
  -o src/factuarea.d.ts
openapi-python-client generate \
  --url https://docs.factuarea.com/api/openapi
openapi-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.

En esta página