Visió general
SDKs oficials de TypeScript i PHP per a l'API de Factuarea — instal·la @factuarea/sdk o factuarea/factuarea-php i obtén reintents, idempotència, paginació per cursor, errors tipats i verificació de webhooks de sèrie.
Factuarea ofereix SDKs oficials que envolten tota l'API REST v1 (234 operacions repartides en 17 recursos) amb un runtime premium perquè no hagis d'escriure HTTP a mà: reintents automàtics, idempotency keys automàtiques, auto‑paginació per cursor transparent, una jerarquia d'errors tipada, verificació de webhooks tipada i descàrregues binàries (PDF).
TypeScript / Node.js
@factuarea/sdk a npm. ESM + CommonJS dual, declaracions de tipus completes.
Codi font: github.com/factuarea/factuarea-node.
PHP
factuarea/factuarea-php a Packagist. PSR‑4, basat en Guzzle, PHP 8.2+.
Codi font: github.com/factuarea/factuarea-php.
Pre‑GA (0.x). Tots dos SDKs estan a 0.x. La superfície pública de
mètodes és estable i segueix el
contracte de nomenclatura de mètodes del SDK,
protegit per SemVer — però mentre estigui a 0.x, les versions minor poden
incloure canvis incompatibles fins a 1.0.0, que coincideix amb la GA de
l'API. Cada release fixa una
Factuarea-Version i l'envia a cada request, de manera
que el comportament de l'API es manté estable fins que actualitzes el SDK.
Només al servidor. La teva API key és un secret. No incloguis mai un SDK amb una clau live en un navegador, app mòbil o qualsevol client públic — fes servir el SDK des del teu backend.
Instal·lació
npm install @factuarea/sdkRequereix Node 20 o superior. El SDK està construït sobre l'estàndard
Web fetch, així que també funciona a Deno, Bun i Cloudflare Workers.
composer require factuarea/factuarea-phpRequereix PHP 8.2 o superior amb les extensions json i mbstring
(totes dues incloses a les builds estàndard de PHP).
Autenticació i entorns
Passa la teva API key. El prefix de la clau selecciona l'entorn — no hi
ha cap flag a part: una clau fact_test_… sempre s'executa contra el
sandbox aïllat, i una clau fact_live_… contra
producció.
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ó 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() és el punt d'entrada recomanat: connecta
l'autenticació Bearer i registra per tu el comportament automàtic de
Idempotency-Key. Per a configuració avançada (client Guzzle
personalitzat, política de reintents personalitzada, base URL de staging)
el builder generat continua 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();Inici ràpid
Crea un client i una factura, i després descarrega'n el PDF. Cada operació és
accessible com a <resource>.<method> (TypeScript) o
->{resource}->publicApiV1{Resource}{Action} (PHP) seguint el contracte de
nomenclatura — els snippets per endpoint de la
referència de l'API mostren la crida exacta per a cada
operació.
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 ?? '');Executa-ho tot primer amb una clau fact_test_ — els efectes del
sandbox (VeriFactu → AEAT, FACe, email, webhooks) estan desactivats. Quan el teu
flux funcioni d'extrem a extrem, canvia el prefix a fact_live_. La
superfície de l'API és idèntica en tots dos. Consulta Test mode &
sandbox.
Funcions en temps d'execució
Tots dos SDKs comparteixen el mateix runtime escrit a mà sobre la superfície tipada generada:
- Reintents automàtics — les fallades transitòries (
429i5xx, a més d'errors de xarxa a TypeScript) es reintenten amb backoff exponencial i jitter, respectant el headerRetry-After. Els errors de client deterministes (p. ex. validació422) mai es reintenten. - Idempotència automàtica — cada mutació rep una
Idempotency-Keygenerada perquè un request reintentat mai creï un recurs per duplicat. Sobreescriu-la per crida quan vulguis deduplicació a nivell d'app. Consulta Idempotency. - Auto‑paginació per cursor — els mètodes de llistat retornen un iterable
que recorre totes les pàgines per tu, gestionant
next_cursor/has_more. Consulta Paginar amb el SDK. - Errors tipats — l'embolcall d'error de l'API es mapeja
a una jerarquia d'excepcions tipada que exposa
code,type,request_idistatus. La teva API key mai s'inclou en cap missatge d'error. Consulta Gestionar errors. - Verificació de webhooks — un verificador HMAC‑SHA256 de temps constant que respecta la finestra de gràcia de rotació de secret. Consulta Verificar webhooks.
- Descàrregues binàries — els endpoints de PDF i de fitxers retornen una resposta binària que converteixes en un Buffer / stream, no JSON.
Paginació amb el SDK
Els mètodes de llistat retornen un Page, que és en si mateix 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 transmet cada element a través de totes les
pàgines sense gestió 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 per conèixer la semàntica de cursor subjacent.
Gestió d'errors
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 segons el code estable, mai segons el message en castellà
orientat a persones. El catàleg complet és a Errors.
Verificació de webhooks
Passa el cos cru del request (no un objecte re‑serialitzat), el header
Factuarea-Signature i el secret de l'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ó fa servir HMAC‑SHA256 amb una comparació de temps constant i una tolerància de timestamp configurable (5 minuts per defecte) per rebutjar replays, i accepta totes dues firmes durant una finestra de gràcia de rotació de secret. Consulta Webhooks.
Snippets per endpoint
Cada pàgina de la referència de l'API mostra un snippet de TypeScript, PHP i cURL llest per copiar per a aquesta operació exacta, generat a partir del spec perquè mai es desviïn de la superfície real.
Genera el teu propi client
Si el teu llenguatge encara no està cobert, o prefereixes un client que tu controlis i desis al teu repo, el contracte canònic llegible per màquina és el spec OpenAPI 3.1 — apunta-hi qualsevol generador.
El spec viu a
https://docs.factuarea.com/api/openapi. Es genera a partir
del mateix backend que serveix l'API, així que mai es desvia de la
superfície real.
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> pot ser qualsevol
generador suportat —
Go, Java, C#, Ruby, Rust i més.
Un client generat no inclourà el runtime del SDK oficial (reintents, idempotència, paginació, verificació de webhooks) — això ho connectes tu mateix seguint les guies de conceptes clau.
Construeixes amb un assistent d'IA?
Si vols que un agent d'IA operi Factuarea directament en lloc de generar codi
de client, connecta'l al servidor MCP — l'API pública exposada com a
tools, amb autenticació OAuth i per API key. Per a Claude Code, el
plugin oficial factuarea-mcp ho configura en dues
comandes.
Mode de prova i sandbox
Crea la teva integració de forma segura amb claus fact_test_ — dades de sandbox aïllades i AEAT, email i webhooks desactivats.
TypeScript
Instal·la @factuarea/sdk per a Node.js, autentica't i crea la teva primera factura. ESM + CommonJS dual, declaracions de tipus completes, Node 20+.