> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aropay.aro.media/llms.txt
> Use this file to discover all available pages before exploring further.

# API keys

> Create, use, rotate, and revoke aro_sk_ keys: limits, expiry, and how keys are stored.

API keys are the credential for programmatic access. They authenticate every
protected endpoint except the deliberately
[session-only ones](/security/authentication#session-only-endpoints).

```bash theme={null}
curl -s "$BASE/wallets" -H "Authorization: Bearer aro_sk_…"
```

## Properties

|                     |                                                                                           |
| ------------------- | ----------------------------------------------------------------------------------------- |
| **Format**          | `aro_sk_` prefix + 256 bits of entropy                                                    |
| **Shown**           | Exactly once, in the `POST /keys` response (`plaintext`)                                  |
| **Stored**          | SHA-256 hash only; the platform cannot recover a lost key                                 |
| **Displayed later** | Prefix + metadata (`keyPrefix`, `lastUsedAt`, `expiresAt`, …)                             |
| **Limit**           | 10 active keys per account                                                                |
| **Expiry**          | Optional, 1–365 days (`expiresInDays`)                                                    |
| **Management**      | Session-only: keys are created and revoked from a browser session, never with another key |

## Create a key

In the dashboard: **Settings → API keys → Create**. Or from a
session-authenticated request:

```bash theme={null}
curl -s "$BASE/keys" -b cookies.txt \
  -H "content-type: application/json" \
  -d '{"name":"CI integration","expiresInDays":90}'
```

```json theme={null}
{
  "ok": true,
  "data": {
    "key": {
      "id": "ckkey0001…",
      "name": "CI integration",
      "keyPrefix": "aro_sk_3f9",
      "lastUsedAt": null,
      "expiresAt": "2026-11-11T09:00:00.000Z",
      "revokedAt": null,
      "createdAt": "2026-08-13T09:00:00.000Z"
    },
    "plaintext": "aro_sk_…full key, shown only now…"
  }
}
```

<Warning>
  Copy `plaintext` into your secret manager immediately; it is never shown
  again. If it's lost, revoke the key and create a new one.
</Warning>

Hitting the cap returns `400 key_limit_reached`; revoke unused keys first.

## List and audit

`GET /keys` (works with either credential) returns metadata only. `lastUsedAt`
tells you whether a key is actually in use, useful before revoking during
rotation.

## Revoke

```bash theme={null}
curl -s -X DELETE "$BASE/keys/$KEY_ID" -b cookies.txt
```

Revocation is **immediate and idempotent**; repeat calls return the same
success. Expired keys stop authenticating the moment `expiresAt` passes.

## Rotation playbook

<Steps>
  <Step title="Create the replacement key">
    Give it a name that identifies the consumer (`payments-service-2026Q3`).
  </Step>

  <Step title="Deploy the new key">
    Update the secret in your deployment; confirm traffic via `lastUsedAt`.
  </Step>

  <Step title="Revoke the old key">
    `DELETE /keys/{id}` takes effect instantly. Anything still using it starts
    receiving `401 invalid_api_key`, which is how you find stragglers.
  </Step>
</Steps>

## If a key leaks

Revoke it from the dashboard immediately. Scope damage is bounded by design:
a key can move sandbox funds, but it **cannot** create keys, change the
password, manage 2FA or passkeys, or export wallet keys; those are
[session-only](/security/authentication#session-only-endpoints). Account
deactivation (an admin action) kills all keys and sessions at once.
