<!-- /en/docs/reference (en) -->

# FrankLab Partner API — reference

The FrankLab partner programmatic interface. Authentication is a partner API key (X-API-Key header or Authorization: Bearer); the exception is minting and revoking the keys themselves, which requires the partner session. This projection is generated from source code; on any mismatch the code is the truth.

Base URL: https://apergrex.ru/franklab/api

## GET /v1/billing/api-keys

List API keys

The partner's keys: prefix, label, active flag, dates. Raw keys are never returned.

Responses:

- `200` — Key list
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## POST /v1/billing/api-keys

Create an API key

Creates a new fl_live_… key (partner SESSION auth, not an API key: a key must not be able to mint keys). The raw value is returned exactly once — store it immediately.

Responses:

- `201` — Key created; the raw value is shown once
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## DELETE /v1/billing/api-keys/{id}

Revoke an API key

Deactivates one of your keys by its id (partner SESSION auth). Idempotent: a foreign id matches nothing and returns no error.

Parameters:

- `id` (path, required) `{"type":"string"}` — Key identifier

Responses:

- `200` — Key deactivated (or already inactive)
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## GET /v1/billing/balance

Partner balance

Returns total (lifetime credited), used (lifetime confirmed spend), reserved (held by open task reservations), available (total − used − reserved, floored at 0) and the isLow flag. Amounts are in franks (₣), the platform's internal accounting unit.

Responses:

- `200` — Balance returned
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## GET /v1/billing/legal-invoices/{id}/pdf

Invoice PDF

The invoice PDF (inline; occasionally a redirect to the bank's file). Limit: 12 requests/min.

Parameters:

- `id` (path, required) `{"type":"string"}` — Invoice identifier

Responses:

- `200` — PDF file
- `302` — Redirect to the bank's PDF file
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## POST /v1/billing/legal-invoices/{id}/refresh

Refresh an invoice

Fetches the current invoice status from the bank. Limit: 6 requests/min.

Parameters:

- `id` (path, required) `{"type":"string"}` — Invoice identifier

Responses:

- `200` — Current status
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## POST /v1/billing/legal-invoices/{id}/sbp-link

SBP B2B link

Creates an SBP B2B payment QR link for the invoice. Limit: 6 requests/min.

Parameters:

- `id` (path, required) `{"type":"string"}` — Invoice identifier

Responses:

- `200` — SBP link
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## POST /v1/billing/legal-invoices/create

Create a legal invoice

Creates an invoice via T-Bank Business; on payment the balance is credited automatically (RUB→₣ 1:1). Limit: 3 requests/min.

Responses:

- `201` — Invoice created
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## GET /v1/billing/legal-invoices/history

Invoice history

Legal invoices with statuses, amounts and credit dates.

Parameters:

- `page` (query) `{"type":"integer","minimum":1,"default":1}` — Page number
- `limit` (query) `{"type":"integer","minimum":1,"maximum":100,"default":20}` — Page size

Responses:

- `200` — Invoice list
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## GET /v1/billing/legal-invoices/profile

Legal company profile

The company profile used for legal invoicing (tax id, name, address, etc.).

Responses:

- `200` — Profile
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## PUT /v1/billing/legal-invoices/profile

Upsert the company profile

Creates or updates the invoicing company profile.

Responses:

- `200` — Profile saved
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## GET /v1/billing/payment/history

Top-up history

The list of top-up payments with their statuses (pending/authorized/confirmed/canceled/rejected/failed). Returns the last 50 payments.

Responses:

- `200` — Top-up history
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## POST /v1/billing/payment/link

Top-up payment link

Creates a T-Bank payment link for topping up the balance (RUB→₣ 1:1). The Idempotency-Key header is required: a retry with the same key returns the same payment instead of creating a new one. Card saving is not available programmatically. The link is opened by the payer in a browser. Limit: 3 requests/min.

Parameters:

- `Idempotency-Key` (header, required) `{"type":"string"}` — Idempotency key (up to 128 chars; a retry with the same key and amount returns the same payment, a different amount yields 409)

Responses:

- `201` — Payment created (or an existing one returned): paymentUrl to pay
- `400` — Missing/invalid Idempotency-Key or amount out of range
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## GET /v1/billing/pricing/catalog

Price catalog

The base price showcase grouped by media family (video/image/audio/text/processing) with billing units. The response is not cached (no-store); re-reading once per 24 hours is enough (refreshAfterSeconds).

Responses:

- `200` — Price catalog
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## POST /v1/billing/pricing/estimate

Operation cost estimate

A side-effect-free cost quote for a planned operation at your tariff (the same seam that reserves funds on submit). Pass the model and parameters; media URLs are not accepted — pass reference counts instead.

Responses:

- `200` — Cost quote at the effective tariff
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## GET /v1/billing/tariff

Tariff plan

The effective tariff (base/pro/max/ultra), assigned and earned plans, lifetime spend (₣), the next tier and the spend still required, plus the discount percent against the base price list.

Responses:

- `200` — Tariff returned
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## GET /v1/billing/transactions

Transaction history

Paginated ledger of operations: type (topup/reservation/confirm/refund; debit is a rare legacy row kind), amount in ₣, price per unit, task, date, attribution. Pagination by page/limit (limit ≤ 100).

Parameters:

- `type` (query) `{"type":"string","enum":["topup","reservation","confirm","refund","debit"]}` — Filter by transaction type (debit is a legacy row kind)
- `attribution` (query) `{"type":"string","enum":["all","company","personal"]}` — Whose top-ups to show: all / company / personal
- `dateFrom` (query) `{"type":"string"}` — Range start (ISO 8601)
- `dateTo` (query) `{"type":"string"}` — Range end (ISO 8601)
- `page` (query) `{"type":"integer","minimum":1,"default":1}` — Page number
- `limit` (query) `{"type":"integer","minimum":1,"maximum":100,"default":20}` — Page size

Responses:

- `200` — Paginated transaction list
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## GET /v1/billing/transactions/export

Export transactions as CSV

CSV download of the ledger (attachment). Same filters as the list endpoint; up to 10,000 rows per export — beyond that a `# truncated: …` comment line with the full count is appended.

Parameters:

- `type` (query) `{"type":"string","enum":["topup","reservation","confirm","refund","debit"]}` — Filter by transaction type (debit is a legacy row kind)
- `dateFrom` (query) `{"type":"string"}` — Range start (ISO 8601)
- `dateTo` (query) `{"type":"string"}` — Range end (ISO 8601)
- `format` (query) `{"type":"string","enum":["csv"]}` — Export format; csv is the only option
- `attribution` (query) `{"type":"string","enum":["all","company","personal"]}` — Whose top-ups to include: all / company / personal

Responses:

- `200` — CSV file
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## GET /v1/billing/usage/daily

Daily usage

Confirmed spend per UTC day: confirm rows minus task-less refunds.

Parameters:

- `dateFrom` (query) `{"type":"string"}` — Range start (ISO 8601)
- `dateTo` (query) `{"type":"string"}` — Range end (ISO 8601)

Responses:

- `200` — Per-day aggregation
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## GET /v1/webhooks/deliveries

Delivery history

The partner's last 50 deliveries with statuses (pending/delivering/delivered/uncertain/dead_lettered), attempts and response codes.

Parameters:

- `endpointId` (query) `{"type":"string"}` — Filter by endpoint
- `status` (query) `{"type":"string","enum":["pending","delivering","delivered","uncertain","dead_lettered"]}` — Filter by delivery status

Responses:

- `200` — Delivery list
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## POST /v1/webhooks/deliveries/{id}/replay

Replay a delivery

Re-queues a delivery (uncertain, dead_lettered or delivered) under the same eventId. Limit: 30 requests/min.

Parameters:

- `id` (path, required) `{"type":"string"}` — Delivery identifier

Responses:

- `200` — Delivery re-queued
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## GET /v1/webhooks/endpoints

List webhook endpoints

The partner's endpoints: URL, subscriptions, active flag. Secrets are never returned.

Responses:

- `200` — Endpoint list
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## POST /v1/webhooks/endpoints

Register an endpoint

Creates an endpoint; the whsec_… secret is returned exactly once. The URL must be public HTTPS; internal addresses are rejected. Up to 10 endpoints per partner. Limit: 10 requests/min.

Responses:

- `201` — Endpoint created; the secret is shown once
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## DELETE /v1/webhooks/endpoints/{id}

Delete an endpoint

Deletes one of your endpoints; its pending deliveries go with it.

Parameters:

- `id` (path, required) `{"type":"string"}` — Endpoint identifier

Responses:

- `200` — Endpoint deleted
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## POST /v1/webhooks/endpoints/{id}/rotate-secret

Rotate the secret

Generates a new signing secret; the old one stops working immediately. The new value is shown once. There is no dual-secret grace window: in-flight deliveries sign with the new secret immediately. Limit: 10 requests/min.

Parameters:

- `id` (path, required) `{"type":"string"}` — Endpoint identifier

Responses:

- `200` — The new secret
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets

## POST /v1/webhooks/endpoints/{id}/test

Send a test event

Enqueues a webhook.test event for EXACTLY this endpoint — verify receipt and the signature. Limit: 6 requests/min.

Parameters:

- `id` (path, required) `{"type":"string"}` — Endpoint identifier

Responses:

- `200` — Event enqueued
- `401` — Missing or invalid API key
- `403` — Legacy service keys are rejected: a partner API key is required
- `429` — Rate limit exceeded (default 60 requests/minute per partner); the Retry-After header gives seconds until the window resets
