Authentication
The partner API key, headers, rate limits and safety.
Register and get an API key
API access requires an Apergrex account. Register on Apergrex and create your API key in settings. Keep the key private.
Partner API key
Authentication is a partner API key shaped fl_live_<64 hex>. Use it for generation, billing and webhooks. Exception: minting and revoking API keys require the cabinet session; use Settings → API.
Pass it in one of two ways:
# X-API-Key header (recommended)
curl -H "X-API-Key: $FRANKLAB_KEY" https://apergrex.ru/franklab/api/v1/billing/balance
# Or Authorization: Bearer
curl -H "Authorization: Bearer $FRANKLAB_KEY" https://apergrex.ru/franklab/api/v1/billing/balanceResponse statuses
| Code | Reason | What to do |
|---|---|---|
| 401 | Key missing, unknown or deactivated | Check the key; issue a new one in the cabinet (Settings → API) |
| 403 | A legacy service key was sent | A partner fl_live_ key is required |
| 429 | Rate limit exceeded | Retry later; the default is 60 requests/minute per API key |
Rate limits
These are default settings, not a throughput guarantee. Billing and webhooks share a bucket: 60 requests/minute per API key, or 60/minute per partner for session requests. A separate per-IP limiter applies to each method (default 100/minute), with these overrides:
| Method | Per-IP limit per minute |
|---|---|
POST /v1/billing/payment/link | 3 |
POST /v1/billing/legal-invoices/create | 3 |
POST /v1/billing/legal-invoices/{id}/refresh | 6 |
POST /v1/billing/legal-invoices/{id}/sbp-link | 6 |
GET /v1/billing/legal-invoices/{id}/pdf | 12 |
POST /v1/webhooks/endpoints | 10 |
POST /v1/webhooks/endpoints/{id}/rotate-secret | 10 |
POST /v1/webhooks/endpoints/{id}/test | 6 |
POST /v1/webhooks/deliveries/{id}/replay | 30 |
Limits apply together. For 429 follow Retry-After and the retry rules; do not assume generation submissions use the billing limit.
Key permissions (scopes) and lifetime
A key is full-access by default: it opens generation, billing and webhooks. Keys issued earlier are unchanged — they keep working exactly as before and need no action.
A key can be limited to a set of permissions at issue time. The current permission list, and which methods each one opens, is served by the API itself:
# permission reference (cabinet session)
curl -b "franklab_token=$COOKIE" https://apergrex.ru/franklab/api/auth/api-keys/operations| Permission | What it opens |
|---|---|
usage:read | Daily account spend; the n8n credential test |
billing:read | Balance, tariff, ledger, top-up history |
pricing:read | Price catalog and cost estimates (no charge) |
tasks:read | Status and results of your own tasks |
media:run | Submitting processing and generation (may spend) |
webhooks:read | Reading endpoints and the delivery log |
webhooks:manage | Create, rotate secret, test, replay a delivery |
Rules worth knowing up front:
- Permissions can only be narrowed. A limited key can never be returned to full access — issue a new one.
- Creating payment links is out of reach for every limited key: no permission opens it. Do it from the cabinet session.
- A limited key can always read its own permissions (
GET /v1/billing/api-keys), but sibling keys' permissions are withheld in that response (scopes: null). *is not a permission and is accepted neither by the API nor by the database.
Lifetime is set at issue time (expiresInDays, 1 to 365 days) and there is no default: a key without a lifetime never expires. An expired key answers 401 with code API_KEY_EXPIRED and stays in the cabinet list until you turn on "hide expired". An expired key cannot be extended — issue a new one; PATCH changes only permissions and the label, never the lifetime.
Revocation takes effect on the next request: the key row is re-read on every call and there is no credential cache. A reason can be recorded at revocation (DELETE /auth/api-keys/{id}?reason=...) and is shown in the list.
| Code | When | HTTP |
|---|---|---|
API_KEY_EXPIRED | The key's lifetime has ended | 401 |
API_KEY_SCOPE_REQUIRED | The key lacks the permission for this method | 403 |
API_KEY_SCOPE_UNKNOWN | An unknown permission was requested (including *) | 400 |
API_KEY_SCOPE_EMPTY | A limited key was requested with no permissions at all | 400 |
API_KEY_SCOPE_DOWNGRADE_FORBIDDEN | Attempt to return a limited key to full access | 400 |
API_KEY_EXPIRY_OUT_OF_RANGE | Lifetime outside 1...365 days | 400 |
API_KEY_QUOTA_EXCEEDED | More than 20 active keys on the account | 400 |
Changes to delivery replay responses
POST /v1/webhooks/deliveries/{id}/replay used to answer a single 404 for every refusal. The reasons are now distinguishable:
| Code | HTTP | Reason |
|---|---|---|
DELIVERY_NOT_FOUND | 404 | You have no delivery with that id |
DELIVERY_NOT_REPLAYABLE | 409 | The delivery is in a status a replay cannot start from (for example, already queued) |
DELIVERY_ENDPOINT_DELETED | 409 | This delivery's endpoint was deleted — there is nowhere to replay to |
DELIVERY_ENDPOINT_INACTIVE | 409 | This delivery's endpoint is inactive |
If your code read every replay failure as "404 — no such delivery", update it: three of the reasons now arrive as 409. The delivery list also gained pagination — GET /v1/webhooks/deliveries?limit=1..100&cursor=... returns {deliveries, nextCursor, shown}.
Key safety
- The key is stored server-side as a hash only — it cannot be "shown again"; a lost key is revoked and replaced.
- Send the key over HTTPS only — never in URLs, logs or client-side code.
- Revoke instantly from your signed-in cabinet session:
DELETE /v1/billing/api-keys/{id}(or the Settings → API page). Revocation never needs the key itself — and a key cannot mint a replacement for itself. - Use a separate key per integration — labels keep them apart in the list.
Managing keys
Listing your keys is API-key authenticated. Minting and revoking keys requires the cabinet partner session (partner cookie): an API key must not be able to issue further keys, so a compromised key is fully revoked by its own deactivation — it leaves no "children" that would outlive it. This is the same trust model as the Settings → API page.
# list (prefixes only; the raw value is never returned) — API-key auth
curl -H "X-API-Key: $FRANKLAB_KEY" https://apergrex.ru/franklab/api/v1/billing/api-keysCreate (POST /v1/billing/api-keys) and revoke (DELETE /v1/billing/api-keys/{id}) a key from the cabinet: the Settings → API page — or the same request sent from a signed-in cabinet session (the franklab_token cookie).