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

# API keys and scopes

> Three key kinds, type-homogeneity, and how the prefix routes the request

mintfax has three kinds of API key. The prefix is a structural promise: every request is routed based on the prefix the key carries. You pick a key, the routing follows.

## The three key kinds

| Prefix      | Kind    | Scope                                         | Can send faxes | Can manage account |
| ----------- | ------- | --------------------------------------------- | -------------- | ------------------ |
| `mfx_test_` | Sandbox | One sandbox environment                       | Yes (sandbox)  | No                 |
| `mfx_live_` | Live    | One live environment                          | Yes (live)     | No                 |
| `mfx_acct_` | Account | The whole account (no environment operations) | No             | Yes                |

### `mfx_test_...` - sandbox environment key

Operational key scoped to a single sandbox environment. Sends sandbox faxes (no carrier dispatch). Reads that environment's sandbox fax history, events, webhooks, and credit balance. Cannot touch live data and cannot call `/account/*`.

### `mfx_live_...` - live environment key

Operational key scoped to a single live environment. Sends real faxes through the carrier. Reads that environment's live data. Requires the account to be [activated](/docs/activation) - until the first live credit purchase succeeds, a live key returns `account_not_activated` on operational routes.

### `mfx_acct_...` - account management key

Account-scoped admin key. Reads and manages account-level resources: balances across all pools, the pool-wide transaction ledger, and the list of API keys. Cannot send faxes and cannot call `/environment/*`. Think of it as the keys-and-money key, not the send-a-fax key.

## The prefix is the sandbox/live wall

mintfax follows Stripe's `sk_test_` / `sk_live_` pattern, with a third `acct` kind for the account namespace. Because the gateway routes on prefix, the wall between sandbox and live is structural, not configurational:

<Note>
  A key never spans sandbox and live. Each environment is one type for its life. To send live, use a live key against a live environment. To send sandbox, use a sandbox key against a sandbox environment. There is no environment toggle in the API.
</Note>

This is the **type-homogeneity rule**. If you accidentally point a sandbox key at production code, you do not silently send real faxes - the worst case is that nothing happens, because sandbox keys cannot reach live resources by construction.

## Registration provisions two keys

`POST /account/register/verify` returns both a `mfx_test_...` key and a `mfx_acct_...` key in the same response. Store both. They have different jobs:

* Use the **sandbox key** for your first sandbox fax in dev. It is scoped to the sandbox environment created at registration.
* Use the **acct key** when you need to programmatically manage environments, balances, or other keys. For example: listing all your API keys, reading the live and sandbox balances side by side, or creating a new live environment key after you activate.

```json theme={null}
{
  "account":         { "id": "acct_4HGhJ7K2pNm9XqL3VtR8Wz", "name": "Acme Corp" },
  "user":            { "id": 42, "email": "dev@acme.com" },
  "environment":     { "id": "env_2BcD3eF4gH5iJ6kL7mN8oP", "name": "Sandbox", "type": "sandbox" },
  "api_key":         "mfx_test_abc123def456...",
  "api_key_account": "mfx_acct_qpr456stv789..."
}
```

Both plain-text keys are shown once only. Save them to a secrets manager or `.env` file before navigating away.

## Creating more keys

### Environment keys (test or live)

`POST /account/keys` with `scope_kind=test` or `scope_kind=live` creates an environment-scoped key. Use an `mfx_acct_...` key to authenticate the call:

```bash theme={null}
curl -X POST https://api.mintfax.com/v1/account/keys \
  -H "Authorization: Bearer mfx_acct_qpr456stv789..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CI pipeline key",
    "scope_kind": "test",
    "environment_id": "env_2BcD3eF4gH5iJ6kL7mN8oP"
  }'
```

The response includes the plain-text key once. Store it immediately.

### Account keys

Subsequent `mfx_acct_...` keys cannot be created via the API. `POST /account/keys` with `scope_kind=account` returns HTTP 403 with [`acct_key_creation_dashboard_only`](/docs/errors#acct-key-creation-dashboard-only):

```json theme={null}
{
  "error": "acct_key_creation_dashboard_only",
  "message": "Account-scoped keys can only be created via the dashboard.",
  "action": "use_dashboard",
  "docs": "https://mintfax.com/docs/errors/acct-key-creation-dashboard-only"
}
```

Rationale: account keys are admin-equivalent for the account. Restricting their lifecycle to the dashboard adds a human-loop attestation step, so an API-only chain of compromise cannot escalate from a stolen environment key to full account control.

## Revocation

| Key kind              | Dashboard | API (`DELETE /account/keys/{id}` with acct key) |
| --------------------- | --------- | ----------------------------------------------- |
| `mfx_test_` (sandbox) | Yes       | Yes                                             |
| `mfx_live_` (live)    | Yes       | Yes                                             |
| `mfx_acct_` (account) | Yes       | Dashboard only (API returns 403)                |

Deleting an environment key via the API:

```bash theme={null}
curl -X DELETE https://api.mintfax.com/v1/account/keys/key_8aZqRm4yT3vK7pNxJ2bH9c \
  -H "Authorization: Bearer mfx_acct_qpr456stv789..."
```

Revocation is effective on the next request - there is no caching layer to wait on. A revoked key returns `api_key_invalid`.

## Which key for which endpoint

The API splits cleanly into two scopes:

* **Operational** (`/faxes`, `/environment/*`, `/webhooks`, `/events`) - environment keys only.
* **Account** (`/account/*`) - account keys only.

| Endpoint                    | `mfx_test_` | `mfx_live_` | `mfx_acct_` |
| --------------------------- | ----------- | ----------- | ----------- |
| `POST /faxes`               | yes         | yes         | no          |
| `GET /faxes/{id}`           | yes         | yes         | no          |
| `GET /environment/balance`  | yes         | yes         | no          |
| `GET /environment/*`        | yes         | yes         | no          |
| `GET /account`              | no          | no          | yes         |
| `GET /account/balance`      | no          | no          | yes         |
| `GET /account/transactions` | no          | no          | yes         |
| `GET /account/keys`         | no          | no          | yes         |
| `POST /account/keys`        | no          | no          | yes         |

When a key hits a route it is not scoped for, the API returns HTTP 403 with a specific code:

* Environment key on an account route: [`key_not_scoped_for_account`](/docs/errors#key-not-scoped-for-account).
* Account key on an operational route: [`key_not_scoped_for_operations`](/docs/errors#key-not-scoped-for-operations).

These codes are stable. Match on them programmatically if you need to fall back to a different key in your client.

## Worked example: agent registration flow

A coding agent registers, stores both keys, sends a sandbox fax, then later switches to live.

```bash theme={null}
# 1. Start registration. Verification code goes to the email.
curl -X POST https://api.mintfax.com/v1/account/register \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Corp", "email": "dev@acme.com"}'

# 2. Verify with the 6-digit code. Returns BOTH keys.
curl -X POST https://api.mintfax.com/v1/account/register/verify \
  -H "Content-Type: application/json" \
  -d '{"email": "dev@acme.com", "code": "482901"}'
# Response includes:
#   "api_key":         "mfx_test_abc123def456..."   <- sandbox environment
#   "api_key_account": "mfx_acct_qpr456stv789..."   <- account admin

# 3. Store both. The agent persists them to its secrets store.
echo "MINTFAX_TEST_KEY=mfx_test_abc123def456..." >> .env
echo "MINTFAX_ACCT_KEY=mfx_acct_qpr456stv789..." >> .env

# 4. Send a first sandbox fax with the sandbox key.
#    Sandbox accepts only the +1 (500) 555-XXXX magic numbers - see /sandbox.
curl -X POST https://api.mintfax.com/v1/faxes \
  -H "Authorization: Bearer mfx_test_abc123def456..." \
  -F "to=+15005550001" \
  -F "file=@invoice.pdf"

# 5. Later, after activating live in the dashboard, mint a live environment key
#    using the account key.
curl -X POST https://api.mintfax.com/v1/account/keys \
  -H "Authorization: Bearer mfx_acct_qpr456stv789..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "production",
    "scope_kind": "live",
    "environment_id": "env_LiVe9AbC8DeF7GhI6JkL5M"
  }'

# 6. Swap the sandbox key for the new live key in production code.
curl -X POST https://api.mintfax.com/v1/faxes \
  -H "Authorization: Bearer mfx_live_xyz789wvu654..." \
  -F "to=+15125550100" \
  -F "file=@invoice.pdf"
```

The acct key never sends faxes. The environment keys never read account-level data. The prefix tells the gateway everything it needs to know.

## Related pages

* [Environments](/docs/environments) - sandbox vs live environments
* [Credits](/docs/credits) - account-pool credit model and balances
* [Activation](/docs/activation) - what enables live operations
* [Errors](/docs/errors) - full error code catalog
