Factuarea API
Conceptes clau

Errors

Embolcall d'error normalitzat, catàleg de type i code amb àncores estables, i estratègia de reintents.

Tota resposta d'error de l'API pública usa un embolcall JSON consistent. L'estat HTTP indica la categoria general; el camp type desambigua i el camp code apunta a la causa específica.

Embolcall

{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_invalid",
    "message": "El campo client_id es obligatorio.",
    "param": "client_id",
    "request_id": "req_01HKQS5N8VR7QXJ9K3T6BWPMZA",
    "doc_url": "https://docs.factuarea.com/guides/errors#parameter_invalid"
  }
}

Camps:

  • type — categoria general de l'error. Estable i enumerada (llista a sota).
  • code — causa específica. Estable i enumerada.
  • subcode — opcional. Present en algunes respostes 409 conflict_error / resource_already_exists per assenyalar la clau duplicada exacta — p. ex. subcode: "tax_id_already_exists".
  • message — text per a persones en castellà. No es garanteix estable entre versions; útil per a logging i visualització.
  • param — opcional, present en errors de validació. Apunta al camp problemàtic.
  • doc_url — opcional. Enllaç a aquesta guia amb àncora al code específic (#{code}).
  • request_id — identificador únic de la petició (req_<ULID>). Inclou-lo sempre quan contactis amb suport. També es retorna al header de resposta X-Request-Id.

L'objecte error sempre porta type, code i message; la resta de camps són presents quan és rellevant.

Tipus d'error

typeHTTPDescripció
invalid_request_error400 o 422Payload malformat, paràmetres absents/invàlids o fallada de validació de negoci.
authentication_error401L'API key falta, és invàlida, està revocada, ha expirat o la IP no és a la llista d'accés.
authorization_error403La key és vàlida però el scope no cobreix l'endpoint.
permission_error403El pla/add-on no dona accés a la funcionalitat.
not_found_error404El recurs sol·licitat no existeix o no pertany a l'empresa de la key.
conflict_error409Conflicte de creació, lock d'idempotència o recurs duplicat (p. ex. un tax_id ja registrat).
idempotency_error409Reutilització d'Idempotency-Key amb un payload diferent.
rate_limit_error429Superada la quota per minut o mensual, o massa fallades d'autenticació.
api_error500Error inesperat del backend. Els reintents poden ajudar; reporta a suport amb el request_id.
service_unavailable_error503API pública deshabilitada via kill-switch, o caiguda d'una dependència (Stripe, mailer).

Les violacions de regles de negoci (transició d'estat invàlida, una acció no permesa en l'estat actual del document) responen 422 amb type: invalid_request_error i code: invalid_status_transitionno 409. 409 conflict_error es reserva per a creació duplicada, conflictes d'idempotència i locks de concurrència.

Catàleg de codes

L'àncora de cada encapçalament H3 coincideix exactament amb el valor del camp code de l'embolcall. El doc_url que retorna l'API resol a la secció específica. La llista de sota cobreix els codes que trobaràs a la pràctica; la referència OpenAPI en viu documenta els codes exactes per endpoint.

invalid_request_error

parameter_invalid

Un paràmetre de la petició falta o és invàlid. param apunta al camp problemàtic (p. ex. client_id, lines[0].quantity).

parameter_invalid_format

El format d'un valor és incorrecte per a la seva semàntica (regex, longitud, codificació, un UUID malformat, una data fora de format).

parameter_invalid_range

Un valor numèric o de data està fora del rang permès (p. ex. limit fora d'1..100).

parameter_invalid_cursor

El cursor starting_after / ending_before no és un id de recurs vàlid. Consulta Paginació.

parameter_unknown

El body conté un camp no documentat (en endpoints estrictes).

invalid_param_format

Va fallar una restricció de format en un camp tipat — p. ex. el header Idempotency-Key o el header Factuarea-Version està malformat.

invalid_param_value

El valor no compleix una restricció (enum, format, regla semàntica).

invalid_period

El període de report sol·licitat és invàlid (p. ex. un trimestre/any que no existeix).

invalid_status_transition

La transició sol·licitada està prohibida per la màquina d'estats del document (p. ex. enviar una factura que no està en un estat enviable). Les violacions de regles de negoci com aquesta són 422, no 409.

invoice_already_paid

mark-paid sobre una factura ja pagada.

quote_already_accepted

Acció que entra en conflicte amb un pressupost ja acceptat.

business_rule_violation

Una invariant de domini va bloquejar l'operació. El subcode identifica la regla i param el camp infractor. El fa servir el ledger de pagaments (Registrar pagaments):

  • payment_exceeds_pending_amount (param: "amount") — l'import del pagament és més gran que el saldo pendent de la factura. S'aplica tant a POST /v1/invoices/{id}/payments com a POST /v1/purchase_invoices/{id}/payments.
  • invalid_payment_date (param: "paid_on") — la data de pagament cau fora de la finestra permesa data_emissió … avui (factures de compra).
  • purchase_invoice_not_payable (param: "status") — la factura de compra està cancel·lada i ja no admet pagaments.
{
  "error": {
    "type": "invalid_request_error",
    "code": "business_rule_violation",
    "subcode": "payment_exceeds_pending_amount",
    "message": "El importe del pago (1.500,00 €) supera el importe pendiente de la factura (710,00 €).",
    "param": "amount",
    "doc_url": "https://docs.factuarea.com/guides/errors#business_rule_violation",
    "request_id": "req_..."
  }
}

unsupported_format

El format d'exportació/report sol·licitat no està suportat.

insufficient_data_for_report

No hi ha prou dades per generar el report d'impostos sol·licitat.

signature_payload_too_large

La imatge de signatura de l'albarà supera la mida màxima.

authentication_error

missing_api_key

No hi ha header d'autenticació present (Authorization: Bearer o X-API-Key).

invalid_api_key

La key no existeix o el secret no coincideix amb el hash emmagatzemat.

api_key_revoked

La key va ser revocada. Crea'n una de nova al dashboard.

too_many_auth_failures

S'han limitat fallades d'autenticació repetides des del teu client. Espera (back off) i verifica les teves credencials.

authorization_error

insufficient_scope

La key no té el scope que requereix l'endpoint. Consulta el catàleg a Autenticació › Scopes.

permission_error

feature_not_available_in_plan

El pla actual no inclou el mòdul requerit (p. ex. recurring_invoices).

addon_not_active

L'add-on developer_api està inactiu o fora del seu període de gràcia.

not_found_error

resource_not_found

El recurs no existeix o no pertany a la teva empresa.

tax_report_not_found

El report d'impostos sol·licitat no existeix.

conflict_error

resource_already_exists

Intent de crear un duplicat (p. ex. un tax_id ja registrat). El subcode (p. ex. tax_id_already_exists) assenyala la clau duplicada.

resource_conflict

L'operació entra en conflicte amb l'estat actual del recurs (p. ex. una modificació concurrent).

max_api_keys_exceeded

L'empresa ha assolit el seu nombre màxim d'API keys actives.

idempotency_error

idempotency_key_reused

Mateix Idempotency-Key, body de petició diferent. Usa una key nova. Consulta Idempotència.

rate_limit_error

rate_limit_exceeded

Vas superar la quota per minut o mensual del teu tier. El header Retry-After indica els segons a esperar. Consulta Límits de peticions.

api_error

internal_error

Error inesperat. Ja està capturat per la nostra banda, però comparteix el request_id amb suport.

service_unavailable_error

service_unavailable

L'API pública no està disponible temporalment — deshabilitada globalment via kill-switch, en una finestra de manteniment, o una dependència (base de dades, mailer, Stripe) no està sana. Reintenta després d'un back-off curt.

Errors tipats amb el SDK oficial

Els SDKs de TypeScript i PHP mapegen aquest embolcall a una jerarquia d'excepcions tipada, així ramifiques segons una classe (i llegeixes code, type, param, request_id) en lloc de parsejar JSON. La teva API key mai no s'inclou en cap excepció.

import {
  FactuareaError,
  ValidationError,
  RateLimitError,
} from "@factuarea/sdk";

try {
  await factuarea.invoices.create(body);
} catch (error) {
  if (error instanceof ValidationError) {
    console.error(error.fields);     // { client_id: ["obligatorio"], … }
  } else if (error instanceof RateLimitError) {
    console.error(error.retryAfter); // seconds to wait
  } else if (error instanceof FactuareaError) {
    console.error(error.code, error.type, error.requestId);
  }
}

La jerarquia també exporta AuthenticationError, NotFoundError, ConflictError, ServerError i ConnectionError.

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
}

Consulta SDKs › Gestió d'errors per veure la jerarquia completa. La política de reintents de sota l'apliquen automàticament ambdós SDKs.

request_id i suport

Tota resposta inclou un request_id. Adjunta'l a qualsevol tiquet o petició a support@factuarea.com:

Subject: 422 on POST /v1/invoices — request_id req_01JBVH7K9Y4N3CDQ2EHJB1AGSV

Amb el request_id correlacionem logs, mètriques i traces per investigar ràpid.

Estratègia de reintents

  • 4xx excepte 429no reintentis: l'error és a la petició. Corregeix-lo i reenvia.
  • 429 → respecta el header Retry-After. Implementa back-off exponencial amb jitter.
  • 5xx → back-off exponencial (2^n * 100ms) amb jitter, màxim 5 intents.

Stripe publica un patró canònic que també aplica aquí: stripe.com/docs/error-handling.

En aquesta pàgina