Skip to content

Errors ​

Every /api/v1/* endpoint returns the same error envelope. error.code is stable, so your application can branch on it without depending on message wording.

The OAuth2 /oauth/token and /oauth/revoke endpoints use protocol errors (for example, {"error":"invalid_grant"} for an invalid code or refresh token), rather than this public API envelope. See Authentication and scopes.

Envelope ​

json
{
  "error": {
    "type": "validation_error",
    "code": "invoice.nif_receptor_invalid",
    "message": "The recipient tax ID has an invalid format",
    "param": "partner.id_num"
  }
}
FieldDescription
typeGeneral error category.
codeStable machine-readable code. Branch on this field.
messageHuman-readable debugging guidance. Do not parse it.
detailsOptional structured error-specific data.
paramAffected field, when applicable.

Categories ​

typeHTTPMeaning
validation_error400Invalid body or parameters.
authentication_error401Missing, invalid, or expired credential.
permission_error403Missing scope or forbidden operation.
not_found_error404The resource does not exist in the tenant.
conflict_error409 / 422Conflict with current state or idempotency rules.
billing_error402The plan reached a usage limit.
verifactu_error422The AEAT would reject the operation.
internal_error500Unexpected service error.

Common codes ​

Authentication and permissions ​

codeWhen
api_key.missingThe Authorization header is missing.
api_key.invalidThe key does not exist or has been revoked.
api_key.no_scopesThe key has no scopes.
oauth.invalid_tokenThe OAuth access token is invalid, expired, or revoked.
api_key.insufficient_scopesThe endpoint's required scope is missing from the key.
oauth.insufficient_scopesThe OAuth token lacks the required scope.
mutability.invoice_lockedAn invoice outside draft state is being edited.
plan_permission_requiredThe tenant plan does not include the feature.

Plan limit (402) ​

plan_limit_reached includes metric, plan_code, limit, used, and, for monthly metrics, reset_at in details. Do not repeat the same operation until usage is released, a new month starts, or the plan changes.

Validation (400) ​

codeWhen
invalid_bodyJSON does not match the endpoint schema.
param.invalid_uuidA path UUID is malformed.
pagination.invalid_cursorThe supplied cursor is invalid.
invoices.partner_requiredThe invoice type requires partner_id.
idempotency.key_too_longIdempotency-Key exceeds 255 characters.

Not found (404) ​

Codes include invoice.not_found, invoice_line.not_found, partner.not_found, product.not_found, serie.not_found, tax.not_found, economic_activity.not_found, verifactu_record.not_found, and external_invoice.not_found.

Conflict (409) ​

codeWhen
partner.external_id_taken / product.external_id_takenThe external ID is already in use.
partner.id_num_taken / product.name_takenThe identifier or name already exists.
serie.code_takenA series already uses that code.
serie.in_useThe series has documents and cannot be deleted.
serie.numbering_startedThe series has numbered a document; only name and is_active may change.
serie.type_immutableA series type cannot be changed.
serie.last_of_typeThe last series of a type cannot be deleted.
economic_activity.in_useInvoices reference the activity.
economic_activity.last_activityThe tenant's last activity cannot be deleted.
idempotency.request_in_progressA request with the same key is still running.
issuance_authorization_requiredInvoice issuance has not been enabled.
external_invoices_not_enabledVerifactu Direct API has not been enabled.

Reusing an Idempotency-Key with a different body returns 422 and idempotency.key_reused_with_different_body. Use a new key per operation.

VeriFactu / unprocessable (422) ​

With type: verifactu_error, the request shape is valid but the AEAT would reject its data: inconsistent breakdown, a simplified invoice above its legal limit, or an unidentified recipient tax ID. message describes the cause.

  • Branch on error.code, never on message.
  • For 401 or 403, inspect the key and scopes; do not retry unchanged.
  • For 409, read the current server state and reconcile it.
  • For 422 during issuance, the invoice remains a draft: fix and retry.
  • Retry idempotency.request_in_progress after a few seconds; use a new key for idempotency.key_reused_with_different_body.

Bilteo · Documentation