---
title: "Rotate an API key secret"
method: POST
path: "/accounts/{account}/api-keys/{api_key}/rotate-secret"
tags: ["Account"]
---

# Rotate an API key secret

`POST /accounts/{account}/api-keys/{api_key}/rotate-secret`

## Request

- Base URL: `https://api.factuarea.com/v1`
- URL: `https://api.factuarea.com/v1/accounts/{account}/api-keys/{api_key}/rotate-secret`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

Rotate the secret of an API key: a fresh `prefix` + `secret` is returned in plaintext exactly once. Irreversible.
- The previous secret keeps working for a 24-hour grace window; rotating again in that window replaces it at once.
- A key with scopes the calling key does not cover returns 403 `insufficient_scope` and nothing is rotated.

## Path parameters

- `account` string, uuid, required
- `api_key` string, uuid, required

## Headers

- `Idempotency-Key` string, required
- `Factuarea-Version` string, date

## Response `200`

- object
  - `data` ApiKeyWithSecret, required: An API key returned once at creation or after secret rotation. Includes the plaintext `secret` — store it now, it cannot be retrieved later.
    - `id` string, uuid, required: Opaque identifier (UUID v7) of the API key.
    - `object` 'api_key', required: Always `api_key`.
    - `name` string, required: Human-friendly label assigned at creation time.
    - `prefix` string, required: First chars of the key (e.g. `fact_live_1N0Fnyhh`) — safe to log. Does NOT authenticate.
    - `scopes` string[], required: Authorized scopes. `*` means super scope (full access).
    - `tier` string, required: Rate-limit tier (`free`, `starter`, `pro`, `scale`). Derived from the company plan (or preserved by historical grandfathering), never set from the request body.
    - `environment` 'live' | 'test', required: Key environment: `live` (`fact_live_`, real side effects) or `test` (`fact_test_`, sandbox company, no real-world effects).
    - `created_at` string, date-time, required
    - `last_used_at` string, date-time, nullable, required: Timestamp of the last authenticated request with this key, or `null` if never used.
    - `expires_at` string, date-time, nullable, required: Expiry instant (ISO 8601), or `null` if the key does not expire.
    - `revoked_at` string, date-time, nullable, required: Revocation instant (ISO 8601), or `null` if the key is not revoked.
    - `is_active` boolean, required: `true` when the key is usable (not revoked and not expired).
    - `is_revoked` boolean, required: `true` once the key has been revoked.
    - `ip_allowlist` string[], nullable, required: IP addresses or CIDR ranges the key is restricted to, or `null` when it has no IP restriction.
    - `allowed_origins` string[], nullable, required: Browser origins allowed to use a browser-published key, or `null` (or empty) when the key is server-side only.
    - `last_used_ip` string, nullable, required: IP address of the last authenticated request with this key, or `null` if never used.
    - `nif_scope` ApiKeyNifScopeItem[], required: Tax IDs the key reaches, each with its opaque identifier, its fiscal identifier and the access level stored for the key on it.
      - `id` string, uuid, required: Opaque identifier of the company (UUID v7) — the one the company axis expects in the path.
      - `tax_id` string, required: Spanish fiscal identifier (NIF, CIF, NIE). Structural format: NIF `^\d{8}[A-Z]$`, NIE `^[XYZ]\d{7}[A-Z]$`, CIF `^[A-Z]\d{7}[A-Z0-9]$`. AEAT control-digit (checksum) validation is enforced when the request opts in via the `Factuarea-Version` header on or after the activation version; without that opt-in the legacy permissive behaviour is preserved.
      - `name` string, required
      - `access_level` 'view' | 'operate': Access level the key has on that tax ID: `view` is read-only, `operate` can also write. Present on the scope of an API key.
    - `created_by` object, nullable, required: The person who created the key. `null` when that person no longer belongs to the account, or for keys created before this field existed.
      - `id` string, uuid, required: Opaque identifier (UUID v7) of the person.
      - `name` string, required: Full name of the person.
    - `revoked_by` object, nullable, required: The person who revoked the key. `null` when the key is not revoked, when that person no longer belongs to the account, or for keys revoked before this field existed.
      - `id` string, uuid, required: Opaque identifier (UUID v7) of the person.
      - `name` string, required: Full name of the person.
    - `revoke_reason` string, nullable, required: Reason stored when the key was revoked, or `null`.
    - `secret_rotated_at` string, date-time, nullable, required: Instant of the last secret rotation, or `null` if the secret was never rotated.
    - `secret_rotated_by` object, nullable, required: The person who last rotated the secret. Always `null` when the rotation was made with an API credential or the MCP server instead of a person.
      - `id` string, uuid, required: Opaque identifier (UUID v7) of the person.
      - `name` string, required: Full name of the person.
    - `previous_secret_valid_until` string, date-time, nullable, required: End of the 24-hour grace window in which the previous secret still authenticates after a rotation, or `null` outside that window.
    - `secret` string, nullable, required: Plaintext secret, returned only at creation or after rotation — never again. `null` only in an idempotent replay of that creation or rotation, because the secret is never stored.

## Other responses

- `400`: `parameter_unknown` with `subcode` `retired_active_profile_header`: the retired `X-Active-Profile` header was sent; the company goes in the path. `parameter_invalid_format` on `Factuarea-Version`: the header is not a `YYYY-MM-DD` date. `unsupported_api_version`: the `Factuarea-Version` date is not a supported version.
- `401`: Missing or invalid API key.
- `403`: The request is authenticated but not allowed: the API key lacks the required scope (`insufficient_scope`), the plan does not include the public API or this feature (`addon_not_active`, `feature_not_available_in_plan`), or the module is not available with a test key (`module_not_available_in_sandbox`).
- `404`: The requested resource does not exist or belongs to another company.
- `422`: Validation failed — e.g. the API key plan limit was reached, or an invoice language outside the allowed catalog (`es`, `en`, `ca`). The `error.param` field identifies which input is invalid, if any.
- `429`: Rate limit exceeded. Retry after the duration in `Retry-After`.
- `500`: Unexpected server error.

---

[API](https://skmtc.dev/factuarea/apis/factuarea-public-api.md) · [All operations](https://skmtc.dev/factuarea/apis/factuarea-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/factuarea/apis/factuarea-public-api/revisions/718e77934422?raw)
