Factuarea API

API keys (self-service)

List, create, rotate and revoke your API keys over the v1 API — the secret is shown once, environments are live/test, and the tier comes from your plan.

Beyond the developer dashboard, Factuarea exposes the full lifecycle of your API keys over the public v1 API, so you can provision and rotate credentials programmatically. Five endpoints under /v1/account/api-keys cover listing, creating, retrieving, rotating the secret and revoking — all scoped to the authenticated company.

OperationEndpointScope
List keysGET /v1/account/api-keysaccount:read
Create a keyPOST /v1/account/api-keysaccount:write
Retrieve a keyGET /v1/account/api-keys/{api_key}account:read
Rotate the secretPOST /v1/account/api-keys/{api_key}/rotate_secretaccount:write
Revoke a keyPOST /v1/account/api-keys/{api_key}/revokeaccount:write

{api_key} is the key's id — an opaque UUID v7, not its prefix or secret. See the full schemas in the API Reference.

List your keys

GET /v1/account/api-keys returns your keys with cursor pagination. Each key exposes its prefix, scopes, tier, environment and lifecycle timestamps — never the secret.

curl https://api.factuarea.com/v1/account/api-keys \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z"
{
  "data": [
    {
      "object": "api_key",
      "id": "0190f2b1-1c4e-7a3d-9f10-0a1b2c3d4e5f",
      "name": "Production sync",
      "prefix": "fact_live_8KqW3pXn",
      "scopes": ["invoices:read", "invoices:write"],
      "tier": "scale",
      "environment": "live",
      "active": true,
      "revoked": false,
      "last_used_at": "2026-06-23T18:04:11Z",
      "expires_at": null,
      "revoked_at": null
    }
  ],
  "has_more": false,
  "next_cursor": null
}

prefix is the first chars of the key — safe to log, it does not authenticate. Use it to recognize a key in your own dashboards without ever storing the secret.

Create a key

POST /v1/account/api-keys mints a new key and returns its plaintext secret exactly once. Store it the moment you receive it — there is no endpoint to read it back later.

curl -X POST https://api.factuarea.com/v1/account/api-keys \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name": "Reporting export",
    "scopes": ["invoices:read", "pdfs:read"],
    "environment": "test"
  }'

Response (201):

{
  "data": {
    "object": "api_key",
    "id": "0190f2c0-77aa-7b21-8c33-1d2e3f405162",
    "name": "Reporting export",
    "prefix": "fact_test_1N0Fnyhh",
    "secret": "fact_test_1N0FnyhhR2VbY7TcA9eFmN5z",
    "scopes": ["invoices:read", "pdfs:read"],
    "tier": "scale",
    "environment": "test"
  }
}

The secret field appears only in this 201 response (and after a rotation). It is never returned by the list, retrieve or any other endpoint. If you lose it you must rotate the key. Persist it to a secret manager immediately — never to a log or a repository.

Request body

FieldRequiredNotes
nameyesHuman-readable label (1–120 chars).
scopesyesOne or more scopes from the closed catalog. At least one.
environmentnolive (default) or test. See below.
expires_atnoFuture ISO 8601 instant after which the key stops authenticating.
allowed_ipsnoOptional list of allowed IPs / CIDR ranges (IPv4, IPv6, /N).

The tier is derived from your company plan (or from an active capacity boost when higher) — it is not settable from the body. If you send a tier, it is ignored. Requesting a scope outside the closed catalog, or a scope above your plan, returns 422 with per-field errors.

The environment field

Every key belongs to one of two environments, fixed at creation and visible on the key object:

environmentPrefixOperates on
livefact_live_Your real company, with real side effects (VeriFactu → AEAT, emails, webhooks).
testfact_test_An isolated sandbox company with external effects switched off.

Pass environment: test when creating a key to mint a sandbox credential; omit it for a live key. The prefix mirrors the environment, so you can tell them apart without decoding the key. See Test mode & sandbox for what is switched off in test.

Rotate the secret

POST /v1/account/api-keys/{api_key}/rotate_secret generates a fresh prefix + secret and returns the new secret in plaintext exactly once. The previous secret keeps working for a 24-hour grace window so you can roll out the new one with zero downtime.

curl -X POST \
  https://api.factuarea.com/v1/account/api-keys/0190f2b1-1c4e-7a3d-9f10-0a1b2c3d4e5f/rotate_secret \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z"
{
  "data": {
    "object": "api_key",
    "id": "0190f2b1-1c4e-7a3d-9f10-0a1b2c3d4e5f",
    "prefix": "fact_live_Zq7mP4xV",
    "secret": "fact_live_Zq7mP4xVnR2VbY7TcA9eFmN5z",
    "scopes": ["invoices:read", "invoices:write"],
    "environment": "live"
  }
}

During the 24-hour grace window both the new and the previous secret authenticate; a request still using the previous one receives a 199 Warning header counting down the hours left. Once the window expires the previous secret is rejected and purged. Roll the new secret out within those 24 hours. Rotation is irreversible.

Revoke a key

POST /v1/account/api-keys/{api_key}/revoke invalidates a key permanently. Subsequent requests authenticated with it fail with 401. An optional reason (max 500 chars) is recorded in the audit log.

curl -X POST \
  https://api.factuarea.com/v1/account/api-keys/0190f2b1-1c4e-7a3d-9f10-0a1b2c3d4e5f/revoke \
  -H "Authorization: Bearer fact_live_8KqW3pXnR2VbY7TcA9eFmN5z" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Rotated out of the deploy pipeline"}'

Revocation is irreversible and is not restricted to other keys: you may revoke the key you are authenticating the request with, cutting off your own access. Make sure another valid key is in place first if you still need API access.

After revocation, requests with that key return 401 with the generic invalid_api_key code — not a distinct "revoked" code:

{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "La API key proporcionada no es válida.",
    "request_id": "req_01JBVH7K9Y4N3CDQ2EHJB1AGSV"
  }
}

This is deliberate anti-enumeration: the API never reveals whether a key was revoked, expired or never existed — every unusable key looks the same to an attacker. Branch your own logic on the 200/401 outcome, not on a revoked-specific code.

Scopes and isolation

The five endpoints are gated by the account scopes:

  • account:read — list and retrieve keys.
  • account:write — create, rotate and revoke keys.

All operations are scoped to the authenticated company. A key id belonging to another company returns 404 api_key_not_found (again, anti-enumeration — it never reveals the key exists), never 403.

Managing keys still requires an existing key with the right scopes. Create your first key in the developer dashboard (app.factuarea.com/settings/developers/api-keys), then use these endpoints to provision the rest programmatically. See Authentication for the key format and headers.

On this page