Skip to content

Authentication

Test keys and live keys, payments and data scopes, rotation, going live.

Every call to the 221 Pay API carries an API key of a project. The key identifies the project and its mode; 221 Pay creates the project's merchant account on the first authenticated call.

Test keys and live keys

Test keyLive key
Prefixsk_221_pay_test_sk_221_pay_live_
MoneyNo real money: simulated confirmation.Real money: funds collected and paid out.
CreationAs soon as the project exists.Once the project's live mode is activated.

Previously issued 221pay_test_, 221pay_live_ and sk_221_ keys remain valid until they expire or are revoked.

A key is the prefix, 43 base62 characters and a 6-character checksum (CRC32). A malformed key is refused before any lookup. Pattern to detect a key in a code repository or in logs:

Detection
\b(?:sk_221_pay_|221pay_)(test|live)_[0-9A-Za-z]{43}[0-9A-Za-z]{6}\b

Create a key

221 Pay dashboard, Developers > API keys (project administrator):

SettingValues
Name1 to 60 characters.
Modetest (default) or live.
LifetimeNo expiry, 30 days, 90 days or 1 year.
Scopespayments, data, or both (default).

A project has at most 5 active keys.

Shown only once

221 Pay keeps only the secret's hash and a visible prefix. The secret goes into the server's secret manager; if it is lost, revoke the key and create another.

Send the key

Header
Authorization: Bearer sk_221_pay_test_…
Terminal
curl "$API_URL/v1/balances" -H "Authorization: Bearer $API_KEY"

The key stays server side: never in a browser, never in a published mobile app.

Scopes

ScopeGrants access to
paymentsAll 221 Pay routes: payments, links, refunds, payouts, balances.
dataThe 221 API data routes (geography, public holidays, banks…).

A key without the payments scope receives 403 MISSING_SCOPE on 221 Pay routes. A key dedicated to 221 Pay, with only the payments scope, limits the impact of a leak. The project's webhook routes accept any key of the project, whatever its scope.

Daily quota

221 Pay routes have no daily quota: only the limit of 600 requests per minute per project applies (Errors). The daily quota covers data routes only (data scope).

Each key carries a daily_limit, the number of data calls it can make per day. It is set when the key is created through the API (POST /v1/projets/{id}/cles, integer of at least 1) and cannot exceed a key's default limit, which also applies when it is omitted. The account has its own limit, shared by all its keys and projects. Server defaults: 1,000 calls per key and per account; 5,000 per key and 10,000 per account when the identity is verified, and a key of a verified account counts as at least 5,000. The counter resets at midnight UTC.

Developers > Usage shows the values in force and today's consumption. Project owners receive an e-mail at 80% and then 100% of a key's quota.

Beyond that, the call receives 429 QUOTA_EXCEEDED with Retry-After (seconds until midnight UTC):

429
HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 5000
RateLimit-Remaining: 0
Retry-After: 21887

{"code": "QUOTA_EXCEEDED", "message": "Daily quota of the account or key reached.", "request_id": "2f6c9a0e-5b1d-4e7f-8c3a-9d0b1e2f3a4c", "limit": 5000, "reset_at": "2026-10-08T00:00:00.000Z"}

See also Authentication and keys.

Role of a key

A key acts with the administrator role on its project: it creates payments, links, refunds and payouts. The administrator who created it is accountable for its use. The roles of project members are described in Dashboard.

Project id

$PROJECT_ID is the project id in the /v1/projets/{id}/… routes. A key reads it itself, whatever its scope:

Terminal
curl "$API_URL/v1/moi/cle" -H "Authorization: Bearer $API_KEY"
200 · application/json
{ "project_id": "…", "mode": "test", "scopes": ["payments", "data"], "name": "Shop server" }

project_id is the value of $PROJECT_ID. This route requires a key: the dashboard session receives 401.

The dashboard also shows it, inside the merchant ID, in the form p221_<project id>: Home > Developers > Credentials, "Merchant ID" row (copy button). Remove the p221_ prefix. This block of the Home screen appears once an active API key exists.

Do not confuse it with the "Identifier" field of My account > Account, "Project" card: that is the project's short name (slug), which the API refuses (404) in place of the id. With the dashboard session, GET /v1/projets also returns each project's id.

Rotation

Rotation replaces a key with a new one, with the same name, mode, scopes and quota. The old key stays valid for the chosen grace period, while the new one is deployed: now (revoked at once), 1h, 24h or 7d.

Dashboard, Developers > API keys, or with the dashboard session:

Terminal
curl -X POST "$API_URL/v1/projets/$PROJECT_ID/cles/$KEY_ID/rotate" \
  -H "Cookie: $SESSION_COOKIE" \
  -H "Content-Type: application/json" \
  -d '{"grace": "24h"}'

The response holds the new secret, shown only once, and rotated_from, the id of the replaced key.

Go live

A project administrator activates live mode, with an explicit confirmation: live keys move real money.

Terminal
curl -X PUT "$API_URL/v1/projets/$PROJECT_ID/live" \
  -H "Cookie: $SESSION_COOKIE" \
  -H "Content-Type: application/json" \
  -d '{"live_enabled": true, "acknowledged": true}'

The change is logged. Live keys are then created in Developers > API keys. GET /v1/projets/{id}/live returns live_enabled.

Server mode: gateway_mode

Terminal
curl -s "$API_URL/v1/balances" -H "Authorization: Bearer $API_KEY" | jq -r .gateway_mode
curl -s "$API_URL/health" | jq -r .payments.gateway_mode
ValueMeaning
simulatedSimulator: no real money.
realReal operators.
not_wired (in /health)221 Pay not connected on this server: 221 Pay routes answer 503 PAYMENTS_UNAVAILABLE.

The test journey is described in Testing.

Authentication errors

StatuscodeCause
400PROJECT_REQUIREDDashboard session without a designated project (X-221-External-Ref).
401INVALID_API_KEYKey malformed, unknown or revoked.
401UNAUTHENTICATEDNeither key nor session, or key of another project.
403MISSING_SCOPEKey without the payments scope.
403FORBIDDENRole insufficient for the action (session of a read-only member, for example).

A key can be revoked at any time by a project administrator, or disabled by 221 in case of abuse.