API Keys
API keys are how every server-to-server Liqfy request authenticates. This page is for dashboard/admin users managing keys for their account — if you just need to use a key, see Getting Started.
#Key format
lq_live_<24-byte-base64url> ← production
lq_test_<24-byte-base64url> ← sandbox / test- The cleartext is shown exactly once, at issuance time.
- Server-side we keep only the SHA-256 fingerprint and a 12-character prefix (e.g.
lq_live_xyz) for display in the dashboard. - Lost a key? You can't recover it — rotate to issue a new one.
The exact prefix is brand-specific (here lq_live_ / lq_test_); what is universal is the shape <prefix>_live_… / <prefix>_test_…. Never hardcode a prefix in code that classifies a key — the official SDKs accept any brand's prefix and expose isTestKey helpers that read the _test_ segment instead.
#Using a key on the API
Server-to-server calls to /v1/* carry the key in the canonical Authorization: Bearer header:
Authorization: Bearer lq_live_...The legacy apikey: lq_live_... header is still accepted for compatibility (the gateway rewrites Bearer to the internal apikey form). New integrations should send Bearer and nothing else. If a request carries both headers, the key in Authorization: Bearer is the one used. Missing or invalid keys return 401.
The gateway decides on every request whether the key is a test or a live key, by checking whether it starts with the brand's test prefix (lq_test_). Any key that does not start with the test prefix is treated as live. A client cannot force sandbox routing by sending its own mode header — the gateway always overwrites it from the key.
The same key also unlocks the OpenAPI portals at /docs/payments and /docs/webhooks; without a key they return 401 like any other protected route.
Rate limiting on key-authenticated routes is counted per account (the gateway consumer behind the key), not per IP, so all keys of the same account share one budget. Responses expose X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset and Retry-After so you can back off.
Never log a key. Not in app logs, not in CI output, not in an error report — the cleartext is the credential, and fingerprints exist so you can talk about a key without quoting it.
#IP allowlist
An account can restrict API-key traffic to a list of CIDR ranges. On the routes the guard covers, a request from an address outside the list is refused with 403 before the route runs — same permission_error envelope as Errors, and the key itself is not at fault.
Scope: the allowlist is enforced on the core account routes — wallets, withdrawals, transactions, MED cases, api-keys and neighbours. The money-movement routes /v1/charges, /v1/pix/charges, /v1/payments and /v1/webhooks are not covered by the per-account allowlist (the gateway's ip-restriction protects only /v1/admin).
Include every egress address your integrations use: production servers, CI runners, failover hosts, and the NAT addresses of your cloud regions. A wrong entry here fails closed — the request never reaches the key check, so a "valid key, 403 anyway" report is usually the allowlist.
Ask support (suporte@liqfy.com.br) to add, change or remove a range; the list is maintained per account.
#Auth — these endpoints use JWT, not an API key
All /v1/api-keys/* endpoints are JWT-authenticated (the same dashboard login token returned by POST /v1/auth/login). They are not gated by Kong's apikey plugin — that would be a chicken-and-egg.
Authorization: Bearer <dashboard JWT>The JWT's account claim scopes every operation — you can only manage your own account's keys.
Who can: any active member of the account can list keys. Issuing, rotating and revoking require the account OWNER or ADMIN role; any other role gets 403 with code API_KEY_ROLE_REQUIRED.
#Endpoints
#Issue a key
POST /v1/api-keyscurl -X POST https://api.liqfy.com.br/v1/api-keys \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{ "label": "production-backend", "test": false }'| Field | Type | Required | Description |
|---|---|---|---|
label | string | no | Free-form, ≤ 64 chars. Shown in dashboard for humans. |
test | boolean | no | true issues a lq_test_… key. Default false. |
Response 201 Created
{
"id": "5b3a9c1d-...",
"apiKey": "lq_live_F8A2K7M3N9PQRSTUVWXYZAB",
"fingerprint": "9a3f7e1c5d8b2a40",
"prefix": "lq_live_F8A",
"label": "production-backend",
"createdAt": "2026-04-25T18:32:11.000Z",
"mode": "live"
}mode is the key's environment: test (sandbox, the charge never reaches a real provider) or live. It is the same rule the gateway uses to route the charge; read this field instead of comparing the prefix.
apiKeyis shown only here. Store it in a secret manager immediately. The dashboard does not display it on subsequent loads.
#List your keys
GET /v1/api-keysReturns metadata only — no cleartext.
{
"data": [
{
"id": "5b3a9c1d-...",
"prefix": "lq_live_F8A",
"label": "production-backend",
"createdAt": "2026-04-25T18:32:11.000Z",
"mode": "live"
},
{
"id": "7f1c4e9a-...",
"prefix": "lq_test_QRX",
"label": "ci-tests",
"createdAt": "2026-04-12T09:14:08.000Z",
"mode": "test"
}
],
"access": { "canManage": true }
}access.canManage tells whether the caller can issue, rotate and revoke (account owner or admin).
#Rotate a key
POST /v1/api-keys/{id}/rotateAtomically revokes the named key and issues a fresh one. Use this on a regular cadence (every 90 days is reasonable) or whenever you suspect compromise.
curl -X POST https://api.liqfy.com.br/v1/api-keys/5b3a9c1d-.../rotate \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{ "label": "production-backend (rotated 2026-04-25)" }'Response shape is identical to Issue a key — including the new cleartext.
The new key keeps the old key's environment: rotating a test key issues another test key, and rotating a live key issues another live key. The label is kept too, unless you send a new label. An id that is not in your account returns 404, and nothing is revoked.
Operational note: the old key stops working the moment this call completes. Deploy the new key to your servers BEFORE calling rotate, or schedule a brief overlap by issuing a parallel key first and revoking the old one once the new one is in place.
#Revoke a key
DELETE /v1/api-keys/{id}Permanent — there is no undo.
curl -X DELETE https://api.liqfy.com.br/v1/api-keys/5b3a9c1d-... \
-H "Authorization: Bearer $JWT"Response 200 OK
{ "revoked": true }#Security checklist
- Treat
lq_live_…like a password — never commit, never log, never paste into Slack. - Store in a secret manager (1Password, Vault, AWS Secrets Manager, GitHub Actions secrets, etc.).
- Different keys per environment (
lq_live_…for prod,lq_test_…for staging/CI). - One key per service / one key per developer machine — easier to revoke a single key when something leaks.
- Rotate on a schedule. Quarterly minimum; monthly for high-sensitivity workloads.
- Revoke immediately when an employee leaves.
- Set up alerting on the dashboard's "key issued" / "key rotated" audit events.
#What's stored where
| Storage | What's there |
|---|---|
Kong (key-auth plugin) | The cleartext key — used to authenticate inbound requests. |
| Liqfy database (merchant record) | kongConsumerUsername — the merchant slug, for reverse lookup. Never the cleartext. |
| Audit log | Issue / rotate / revoke events, with the issuing user's id and the key's fingerprint. |
| Dashboard | Prefix + label only. |
#CLI alternative
For ops/onboarding from a workstation, the same operations are available through an internal provisioning CLI (ops-only tooling; not part of the public API or SDK). The CLI talks to the Kong Admin API directly, and keys it issues are interchangeable with HTTP-issued keys.
#FAQ
Q: Can I have multiple live keys at once? A: Yes — useful for zero-downtime rotation and per-service isolation. No hard limit. Keep in mind that all keys of the same account share the account's rate-limit budget.
Q: I lost the cleartext immediately after creation. A: It's gone. Rotate (or revoke + re-issue) — there is no recovery path by design.
Q: How do I tell which key is making which request?
A: The dashboard's request logs show the key fingerprint on every call. Filter by apiKeyFingerprint to attribute traffic.
Q: Can I restrict a key to certain endpoints / methods? A: Not yet. Per-key scopes are on the Phase 2 roadmap. Today, every key has full account access.