Skip to content
LIQFYdocs
PTENENEN
Go to dashboard

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

text
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:

text
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.

text
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

text
POST /v1/api-keys
bash
curl -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 }'
FieldTypeRequiredDescription
labelstringnoFree-form, ≤ 64 chars. Shown in dashboard for humans.
testbooleannotrue issues a lq_test_… key. Default false.

Response 201 Created

json
{
  "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.

apiKey is shown only here. Store it in a secret manager immediately. The dashboard does not display it on subsequent loads.

#List your keys

text
GET /v1/api-keys

Returns metadata only — no cleartext.

json
{
  "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

text
POST /v1/api-keys/{id}/rotate

Atomically 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.

bash
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

text
DELETE /v1/api-keys/{id}

Permanent — there is no undo.

bash
curl -X DELETE https://api.liqfy.com.br/v1/api-keys/5b3a9c1d-... \
  -H "Authorization: Bearer $JWT"

Response 200 OK

json
{ "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

StorageWhat'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 logIssue / rotate / revoke events, with the issuing user's id and the key's fingerprint.
DashboardPrefix + 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.