Ваши клиенты и их кредиты

Добавляйте своих клиентов, ведите их счета кредитов, пополняйте, списывайте и корректируйте их кредиты, блокируйте клиента и задавайте, сколько кредитов стоит операция.

Клиент здесь — это клиент вашего собственного продукта, названный идентификатором, который ему даёт ваша система. Slen ведёт счета кредитов ваших клиентов, берёт с них кредиты, когда флоу выполняется для них, и отклоняет запуск, за который они не могут заплатить. Операции этой страницы добавляют и удаляют клиентов, настраивают их счета, двигают их кредиты, блокируют клиента и задают, сколько кредитов стоит операция. Консоль показывает тех же клиентов на экране Клиенты.

Клиенты и счета

  • Клиента называет external_user_id — тот же идентификатор, который запрос, запускающий флоу, отправляет в context.user_id. Это непрозрачный идентификатор вашей системы, а не адрес почты и не имя.

  • PUT /v1/customers/{externalUserId} добавляет клиента без кредитов и без счёта. Он отвечает 201, когда создал клиента, и 200, когда клиент уже был, поэтому повтору не нужен ключ.

  • Счёт принадлежит одному клиенту и одному типу кредитов. Тип кредитов — имя, которое вы выбираете сами; если его не указать, это default. У клиента с двумя типами кредитов два счёта.

  • Счёт создаёт первое пополнение его типа кредитов или его настройки. Списание и корректировка ничего не создают.

  • Счёт несёт balance, reserved и available. reserved — это то, что держат идущие вызовы, а available — это balance минус reserved.

  • Для клиента, которого проект никогда не видел, ответ — 404 с кодом customer_not_found. Для клиента без счетов accounts в ответе пустой.

Чтение требует customers:read, а каждое изменение — customers:write, кроме задания цены, которое требует management:write. Ключ вашего приложения с gateway:write и customers:write запускает флоу и ведёт своих клиентов и больше ничего не меняет.

Настройки счёта

PUT /v1/customers/{externalUserId}/accounts/{creditType} задаёт обе настройки счёта сразу. Он создаёт клиента и счёт, когда их нет, и отвечает 201, а иначе меняет настройки и отвечает 200.

  • allow_negative разрешает счёту уходить ниже нуля. По умолчанию разрешение выключено, и тогда холд или списание, которые счёт не может покрыть, отклоняются с insufficient_credits. Его можно выключить, пока баланс ниже нуля: защита действует со следующего движения.

  • low_balance_threshold задаёт уровень события вебхука customer.balance_low. Событие отправляется, когда движение переводит available с этого уровня или выше на значение ниже него. Ноль, значение по умолчанию, отключает событие.

  • Пополнение и корректировка не меняют настройки: тело, в котором названо любое из этих полей, отклоняется с 422.

Как запуск тратит кредиты

Запуск тратит кредиты, когда он называет клиента в context.user_id и у проекта есть цена в кредитах для его операции. context.credit_type называет тип кредитов, а без него тип — default. Тип кредитов решает, какой счёт платит и какая цена применяется.

  • Операция без цены для этого типа кредитов или с нулевой ценой не берёт кредитов.

  • Каждый вызов модели в запуске резервирует цену на счёте до того, как модель вызвана. Когда вызов завершён и рассчитан, холд становится расходом, а вызов, который не удался, возвращает его.

  • Счёт, который не может покрыть цену, отклоняет вызов с кодом insufficient_credits. Запуск для клиента, у которого нет счёта этого типа кредитов, отклоняется так же.

  • Запуск для клиента, которого проект не знает, отклоняется с кодом customer_not_found.

  • Запуск для заблокированного клиента отклоняется с кодом customer_blocked — Заблокировать клиента.

Цена задаётся для кода операции и типа кредитов, и следующий холд уже использует её. Повторное задание цены заменяет её, а уже взятый холд сохраняет цену, по которой он взят.

Движения кредитов

Кредиты двигают три операции. Каждая требует заголовок Idempotency-Key длиной не больше 190 символов, а запрос без него отвечает 400 с кодом idempotency_key_required.

  • Пополнение добавляет кредиты. Оно создаёт клиента и счёт, когда их нет.

  • Списание (charge) снимает кредиты за то, что ваше приложение продаёт само, — выгрузку, место. Выписка показывает его как charge. Для клиента, которого проект не знает, ответ — 404 с кодом customer_not_found, а для клиента без счёта этого типа кредитов — 402 с кодом insufficient_credits.

  • Корректировка исправляет баланс. Её credits имеет знак, а ноль отклоняется. Если счёта нет, ответ — 404 с кодом customer_not_found.

Что у трёх общего:

  • У credits не больше четырёх знаков после точки. Пятый знак отклоняется с 422, а не округляется.

  • note, до 255 символов, сохраняется в записи и виден в выписке: номер счёта на оплату, причина.

  • Списание или корректировка не могут опустить баланс ниже того, что держит счёт, если счёт не допускает отрицательный баланс. Такой запрос отвечает 402 с кодом insufficient_credits. Пополнение так не отклоняется никогда, в том числе на счёте ниже нуля.

  • Заблокированного клиента можно пополнять, с него можно списывать, и его можно корректировать.

  • Списание — не расход: отчёт маржи сопоставляет кредиты вызова с тем, сколько вызов стоил, а за списанием не стоит никакой вызов.

Повтор с ключом ничего не двигает.

  • Повтор того же запроса с его ключом отвечает 200. В течение 24 часов, если сервис не настроен иначе, ответом служит первый ответ, с балансом того момента. Потом — счёт в его нынешнем виде.

  • Если ключ уже называет другое пополнение, списание или корректировку проекта, ответ — 409 с кодом idempotency_conflict. В эти 24 часа любое другое тело под этим ключом — другой запрос, в том числе другой note. Потом другой клиент, другой тип кредитов, другой вид движения или другая сумма — это другое движение. Новому движению нужен новый ключ.

  • Отклонённое движение не сохраняется: тот же запрос можно отправить снова с его ключом.

Заблокировать клиента

POST /v1/customers/{externalUserId}/block блокирует клиента, а POST /v1/customers/{externalUserId}/unblock снова его пускает.

  • Новый запуск заблокированного клиента отклоняется с 403 и кодом customer_blocked до того, как что-либо создано.

  • Его запуск, который уже идёт, — в очереди или в ожидании согласования, — отклоняется на следующем холде кредитов вызова модели. Узел модели выходит через Отказ, а без ветки там выполнение заканчивается со статусом rejected и кодом customer_blocked. Запуск операции без цены в кредитах не резервирует кредиты и доходит до конца.

  • Повтор запроса с ключом, с которым он был отправлен до блокировки, получает в ответ то выполнение.

  • Кредиты по-прежнему двигаются, настройки меняются, а выписка читается, поэтому с заблокированным клиентом можно рассчитаться.

  • blocked_at — момент первой блокировки. Повторная блокировка его сохраняет и заменяет block_reason, только когда передан reason. Разблокировка очищает оба поля.

Удалить клиента

DELETE /v1/customers/{externalUserId} удаляет клиента и его счета, только когда с ним ничего не происходило: каждый счёт на нуле и ничего не зарезервировано, а в выписке нет ни одной записи. Иначе клиент остаётся, а ответ объясняет почему.

409 Conflict
{
  "error": {
    "code": "customer_has_history",
    "message": "The customer has credits or a credit history and cannot be deleted; block it instead",
    "request_id": "5d8a3f1c-2b6e-4c9a-8f17-3e0b9d4c6a25"
  }
}

Выписка объясняет баланс, поэтому она хранится. Такого клиента заблокируйте. Удаление и движение одного и того же клиента никогда не обходят друг друга: удаление, которое встретило идущее пополнение, ждёт и затем отказывает, а пополнение, которое встретило идущее удаление, ждёт и затем создаёт клиента заново.

Читать клиентов и выписки

  • Список делится на страницы, самый новый клиент — первым, и каждый клиент приходит со всеми своими счетами. status оставляет активных или заблокированных клиентов, q — клиентов, чей external_user_id его содержит, а credit_type — тех, у кого есть счёт этого типа кредитов.

  • low_balance — это число, а не флаг: он оставляет клиентов, у которых есть счёт с available ниже него, — счёт типа credit_type, когда переданы оба. Фильтры выбирают клиентов и никогда не укорачивают список их счетов.

  • Выписка клиента перечисляет каждое движение его кредитов, самое новое — первым. Запись несёт счёт таким, каким его оставило движение, в balance_after и available_after, и note запроса. entry_type оставляет один вид движений, а credit_type — движения одного счёта. У клиента без счетов выписка пустая.

entry_typeЧто сдвинулосьcredits
topupПополнениеПоложительное
chargeСписание вашего приложенияОтрицательное
adjustКорректировкаС любым знаком
holdВызов модели зарезервировал свою цену из availableОтрицательное
commitВызов рассчитан, и зарезервированная цена ушла из balanceОтрицательное
releaseХолд вернулся в availableПоложительное

Не складывайте credits, чтобы узнать, сколько потратил клиент. У вызова, который потратил кредиты, две отрицательные записи на одну и ту же цену — его hold и его commit, и расход — это только записи commit.

Операции

Описания операций и полей приведены на английском.

Клиенты и их счета

GET /v1/customers

  • Разрешение: customers:read
  • Доступно в SDK для PHP и Node.js

One cursor page of the project's end customers, newest first, each with every credit account it holds (accounts, by credit_type; empty for a customer created by PUT /v1/customers/{externalUserId} that holds none yet). The filters choose customers: credit_type — those holding an account of that type; low_balance — those holding an account with fewer credits still spendable (balance - reserved) than the threshold, of credit_type when it is given too; status, q. The nested list is never narrowed: a customer that matches comes with all its accounts.

Параметры

ПараметрОписание
cursor необязательно

querystring

The meta.next_cursor of the previous page.

view необязательно

querystring

customers, the only value and what an absent view answers too. Kept for the clients that send it; any other value is 422.

  • Одно из: customers
  • По умолчанию: customers
limit необязательно

queryinteger

Page size.

  • Минимум: 1
  • Максимум: 100
  • По умолчанию: 50
status необязательно

queryCustomerStatus

Only customers in this status.

  • Одно из: active, blocked
credit_type необязательно

querystring

Customers holding an account of this credit type.

  • Максимальная длина: 50
low_balance необязательно

querystring

A threshold, not a flag: ?low_balance=10 means "holds an account with fewer than 10 credits still spendable".

q необязательно

querystring

Narrows the list to the customers whose external_user_id contains this text. % and _ are matched as themselves.

  • Максимальная длина: 255

Ответы

200

One cursor page of customers

application/json
{
  "data": [
    {
      "customer_id": "74438200973594624",
      "external_user_id": "user_8421",
      "status": "active",
      "blocked_at": "2026-10-02T09:30:00Z",
      "block_reason": "string",
      "accounts": [
        {
          "customer_account_id": "74438200973594624",
          "customer_id": "74438200973594624",
          "project_id": "74438200973594624",
          "external_user_id": "user_8421",
          "credit_type": "default",
          "balance": "12.5000",
          "reserved": "12.5000",
          "available": "12.5000",
          "allow_negative": true,
          "low_balance_threshold": "12.5000",
          "created_at": "2026-10-02T09:30:00Z",
          "updated_at": "2026-10-02T09:30:00Z"
        }
      ],
      "created_at": "2026-10-02T09:30:00Z",
      "updated_at": "2026-10-02T09:30:00Z"
    }
  ],
  "meta": {
    "limit": 1,
    "next_cursor": "string"
  }
}

Ошибки

СтатусКодыКогда
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Клиент и его счета

GET /v1/customers/{externalUserId}

  • Разрешение: customers:read
  • Доступно в SDK для PHP и Node.js

The customer and every credit account it holds, by credit_type. A customer with no account yet answers with accounts: []; an external_user_id the project has never seen is 404 customer_not_found, and so is one of another project. The external_user_id is the caller's opaque identifier — not an email address or a name.

Параметры

ПараметрОписание
externalUserId обязательно

pathstring

The end customer's identifier in the caller's own system.

  • Максимальная длина: 190

Ответы

200

The customer

application/json
{
  "data": {
    "customer_id": "74438200973594624",
    "external_user_id": "user_8421",
    "status": "active",
    "blocked_at": "2026-10-02T09:30:00Z",
    "block_reason": "string",
    "accounts": [
      {
        "customer_account_id": "74438200973594624",
        "customer_id": "74438200973594624",
        "project_id": "74438200973594624",
        "external_user_id": "user_8421",
        "credit_type": "default",
        "balance": "12.5000",
        "reserved": "12.5000",
        "available": "12.5000",
        "allow_negative": true,
        "low_balance_threshold": "12.5000",
        "created_at": "2026-10-02T09:30:00Z",
        "updated_at": "2026-10-02T09:30:00Z"
      }
    ],
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Ошибки

СтатусКодыКогда
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Создать клиента, если его ещё нет

PUT /v1/customers/{externalUserId}

  • Разрешение: customers:write
  • Доступно в SDK для PHP и Node.js

Creates the customer when the project has none by this external_user_id (201) and answers the one it has otherwise (200) — idempotent by nature, so no Idempotency-Key: a repeat, or two first calls at once, end with one customer. No credit account is created: a customer without accounts is a legal state, and the first top-up or account setting creates the account of its credit type. The body is an empty object; any field is 422.

Параметры

ПараметрОписание
externalUserId обязательно

pathstring

The end customer's identifier in the caller's own system.

  • Максимальная длина: 190

Тело запроса необязательно

application/json
{}
  • Максимум ключей: 0

Ответы

200

The customer already existed

application/json
{
  "data": {
    "customer_id": "74438200973594624",
    "external_user_id": "user_8421",
    "status": "active",
    "blocked_at": "2026-10-02T09:30:00Z",
    "block_reason": "string",
    "accounts": [
      {
        "customer_account_id": "74438200973594624",
        "customer_id": "74438200973594624",
        "project_id": "74438200973594624",
        "external_user_id": "user_8421",
        "credit_type": "default",
        "balance": "12.5000",
        "reserved": "12.5000",
        "available": "12.5000",
        "allow_negative": true,
        "low_balance_threshold": "12.5000",
        "created_at": "2026-10-02T09:30:00Z",
        "updated_at": "2026-10-02T09:30:00Z"
      }
    ],
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}
201

The customer was created

application/json
{
  "data": {
    "customer_id": "74438200973594624",
    "external_user_id": "user_8421",
    "status": "active",
    "blocked_at": "2026-10-02T09:30:00Z",
    "block_reason": "string",
    "accounts": [
      {
        "customer_account_id": "74438200973594624",
        "customer_id": "74438200973594624",
        "project_id": "74438200973594624",
        "external_user_id": "user_8421",
        "credit_type": "default",
        "balance": "12.5000",
        "reserved": "12.5000",
        "available": "12.5000",
        "allow_negative": true,
        "low_balance_threshold": "12.5000",
        "created_at": "2026-10-02T09:30:00Z",
        "updated_at": "2026-10-02T09:30:00Z"
      }
    ],
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Ошибки

СтатусКодыКогда
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Удалить клиента без истории

DELETE /v1/customers/{externalUserId}

  • Разрешение: customers:write
  • Доступно в SDK для PHP и Node.js

Removes the customer and its credit accounts — only when nothing ever happened to them: every account at a zero balance with nothing reserved, and not one entry in its statement. Otherwise 409 customer_has_history: the journal is append-only, its entries explain the balance, so a customer with history is blocked (POST /v1/customers/{externalUserId}/block) rather than deleted. A delete that meets a top-up or a charge of the same customer under way waits for it, and then refuses; a top-up that meets a delete under way waits, and then creates the customer again. An external_user_id the project has never seen is 404 customer_not_found. The external_user_id is the caller's opaque identifier — not an email address or a name: erasing one with history is not offered. Audited.

Параметры

ПараметрОписание
externalUserId обязательно

pathstring

The end customer's identifier in the caller's own system.

  • Максимальная длина: 190

Ответы

204

The customer and its accounts are gone

Без тела

Ошибки

СтатусКодыКогда
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

409

State conflict: idempotency clash, stale draft, illegal transition; the last owner of an organization (last_owner); the owned-organization limit (organization_limit_reached); an end customer with credit history that cannot be deleted (customer_has_history)

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Задать настройки счёта

PUT /v1/customers/{externalUserId}/accounts/{creditType}

  • Разрешение: customers:write
  • Доступно в SDK для PHP и Node.js

The settings of the customer's account of this credit_type: whether it may go below zero (allow_negative) and the level under which a movement sends customer.balance_low (low_balance_threshold, 0 switches the warning off). Both fields are required — the body is the whole of the settings. Creates the customer and the account when they do not exist yet (201); otherwise changes the settings and answers 200. Not a movement of credits, so no Idempotency-Key: the same settings put twice are the same settings. allow_negative: false on an account already below zero is allowed — the guard holds from the next movement on. A blocked customer's settings can be changed.

This is the one place the settings change: a top-up or an adjustment that names either field is 422.

Параметры

ПараметрОписание
externalUserId обязательно

pathstring

The end customer's identifier in the caller's own system.

  • Максимальная длина: 190
creditType обязательно

pathstring

The credit type of the account — tenant-defined text, default when the tenant sells one kind.

  • Максимальная длина: 50

Тело запроса

application/json
{
  "allow_negative": true,
  "low_balance_threshold": "12.5000"
}

Ответы

200

The settings were changed

application/json
{
  "data": {
    "customer_account_id": "74438200973594624",
    "customer_id": "74438200973594624",
    "project_id": "74438200973594624",
    "external_user_id": "user_8421",
    "credit_type": "default",
    "balance": "12.5000",
    "reserved": "12.5000",
    "available": "12.5000",
    "allow_negative": true,
    "low_balance_threshold": "12.5000",
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}
201

The account was created with these settings

application/json
{
  "data": {
    "customer_account_id": "74438200973594624",
    "customer_id": "74438200973594624",
    "project_id": "74438200973594624",
    "external_user_id": "user_8421",
    "credit_type": "default",
    "balance": "12.5000",
    "reserved": "12.5000",
    "available": "12.5000",
    "allow_negative": true,
    "low_balance_threshold": "12.5000",
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Ошибки

СтатусКодыКогда
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Заблокировать клиента

POST /v1/customers/{externalUserId}/block

  • Разрешение: customers:write
  • Доступно в SDK для PHP и Node.js

A blocked customer's new runs are refused 403 customer_blocked before anything is created (POST /v1/operations/execute with its context.user_id), and a run of theirs already under way is refused at its next hold of credits. The balance can still be moved — top-up, charge, adjustment and the account settings stay open, so the customer can be settled with — and the statement still reads. blocked_at is set the first time; blocking again answers 200 without moving it, and replaces block_reason only when a reason is given. An external_user_id the project has never seen is 404 customer_not_found. Audited.

Параметры

ПараметрОписание
externalUserId обязательно

pathstring

The end customer's identifier in the caller's own system.

  • Максимальная длина: 190

Тело запроса необязательно

application/json
{
  "reason": "string"
}

Ответы

200

The customer, blocked

application/json
{
  "data": {
    "customer_id": "74438200973594624",
    "external_user_id": "user_8421",
    "status": "active",
    "blocked_at": "2026-10-02T09:30:00Z",
    "block_reason": "string",
    "accounts": [
      {
        "customer_account_id": "74438200973594624",
        "customer_id": "74438200973594624",
        "project_id": "74438200973594624",
        "external_user_id": "user_8421",
        "credit_type": "default",
        "balance": "12.5000",
        "reserved": "12.5000",
        "available": "12.5000",
        "allow_negative": true,
        "low_balance_threshold": "12.5000",
        "created_at": "2026-10-02T09:30:00Z",
        "updated_at": "2026-10-02T09:30:00Z"
      }
    ],
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Ошибки

СтатусКодыКогда
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Разблокировать клиента

POST /v1/customers/{externalUserId}/unblock

  • Разрешение: customers:write
  • Доступно в SDK для PHP и Node.js

The customer is active again: blocked_at and block_reason are cleared and new runs are accepted. Unblocking a customer that is not blocked answers 200 with the customer as it is. The body is empty; any field is 422. An external_user_id the project has never seen is 404 customer_not_found. Audited.

Параметры

ПараметрОписание
externalUserId обязательно

pathstring

The end customer's identifier in the caller's own system.

  • Максимальная длина: 190

Тело запроса необязательно

application/json
{}
  • Максимум ключей: 0

Ответы

200

The customer, active

application/json
{
  "data": {
    "customer_id": "74438200973594624",
    "external_user_id": "user_8421",
    "status": "active",
    "blocked_at": "2026-10-02T09:30:00Z",
    "block_reason": "string",
    "accounts": [
      {
        "customer_account_id": "74438200973594624",
        "customer_id": "74438200973594624",
        "project_id": "74438200973594624",
        "external_user_id": "user_8421",
        "credit_type": "default",
        "balance": "12.5000",
        "reserved": "12.5000",
        "available": "12.5000",
        "allow_negative": true,
        "low_balance_threshold": "12.5000",
        "created_at": "2026-10-02T09:30:00Z",
        "updated_at": "2026-10-02T09:30:00Z"
      }
    ],
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Ошибки

СтатусКодыКогда
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Выписка по кредитам клиента

GET /v1/customers/{externalUserId}/entries

  • Разрешение: customers:read
  • Доступно в SDK для PHP и Node.js

Every movement of the customer's credits, newest first, each carrying the balance it left behind — so a reader never has to replay the feed to know where the customer stood — and the note its caller gave. Cursor-paged, no date window: a statement is read from the top. An external_user_id the project has never seen is 404 customer_not_found; a customer without an account (or without one of the credit_type asked for) has an empty statement.

Параметры

ПараметрОписание
externalUserId обязательно

pathstring

The end customer's identifier in the caller's own system.

  • Максимальная длина: 190
cursor необязательно

querystring

The meta.next_cursor of the previous page.

limit необязательно

queryinteger

Page size (default 30).

  • Минимум: 1
  • Максимум: 100
credit_type необязательно

querystring

Narrows a customer who holds several pots down to one.

  • Максимальная длина: 50
entry_type необязательно

querystring

Only the movements of this type — the top-ups, say, or the charges.

  • Одно из: hold, commit, release, topup, adjust, charge

Ответы

200

One cursor page of credit movements

application/json
{
  "data": [
    {
      "entry_id": "74438200973594624",
      "customer_account_id": "74438200973594624",
      "external_user_id": "user_8421",
      "credit_type": "default",
      "entry_type": "hold",
      "credits": "12.5000",
      "balance_after": "12.5000",
      "available_after": "12.5000",
      "reservation_id": "74438200973594624",
      "note": "string",
      "created_at": "2026-10-02T09:30:00Z"
    }
  ],
  "meta": {
    "limit": 1,
    "next_cursor": "string"
  }
}

Ошибки

СтатусКодыКогда
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Пополнить кредиты клиента

POST /v1/customers/{externalUserId}/topup

  • Разрешение: customers:write
  • Нужен Idempotency-Key
  • Доступно в SDK для PHP и Node.js

Creates the account when it does not exist yet. Moves money, so it is behind the idempotency middleware.

The Idempotency-Key is also written on the journal entry, where it is unique within the project for as long as the entry exists. A key that already names this top-up — same customer, same credit_type, same credits — answers 200 with the account as it stands now and credits nothing, however long ago the first call was and even while it is still running. A key that names any other top-up, adjustment or charge of the project answers 409 idempotency_conflict and moves nothing. The note does not take part in that comparison; while the stored answer of the first call lasts, any other body under its key — another note included — is 409 idempotency_conflict as for every financial write.

An account the top-up creates starts with allow_negative: false and no low-balance warning. The settings are PUT /v1/customers/{externalUserId}/accounts/{creditType}'s: a body that names allow_negative or low_balance_threshold is 422, as is any field this body does not describe.

Параметры

ПараметрОписание
externalUserId обязательно

pathstring

The end customer's identifier in the caller's own system.

  • Максимальная длина: 190
Idempotency-Key обязательно

headerstring

Replay guard for a financial write. The same key returns the original result with the original status and never charges twice; a different body under a used key answers idempotency_conflict.

  • Максимальная длина: 190

Тело запроса

application/json
{
  "credits": "12.5000",
  "credit_type": "default",
  "note": "string"
}

Ответы

200

The account after the top-up

application/json
{
  "data": {
    "customer_account_id": "74438200973594624",
    "customer_id": "74438200973594624",
    "project_id": "74438200973594624",
    "external_user_id": "user_8421",
    "credit_type": "default",
    "balance": "12.5000",
    "reserved": "12.5000",
    "available": "12.5000",
    "allow_negative": true,
    "low_balance_threshold": "12.5000",
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Ошибки

СтатусКодыКогда
400

Malformed request — e.g. the Idempotency-Key header is missing

401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

409

State conflict: idempotency clash, stale draft, illegal transition; the last owner of an organization (last_owner); the owned-organization limit (organization_limit_reached); an end customer with credit history that cannot be deleted (customer_has_history)

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Скорректировать баланс клиента

POST /v1/customers/{externalUserId}/adjust

  • Разрешение: customers:write
  • Нужен Idempotency-Key
  • Доступно в SDK для PHP и Node.js

Signed: an adjustment may take credits away. Zero is refused — it would be an audit row saying nothing.

The Idempotency-Key is unique within the project on the journal entry, exactly as for a top-up: repeating the same adjustment under its key answers 200 with the account as it stands now and moves nothing — also when the balance could no longer cover it a second time — and a key that names any other top-up, adjustment or charge answers 409 idempotency_conflict. The note takes no part in that comparison, exactly as for a top-up.

Параметры

ПараметрОписание
externalUserId обязательно

pathstring

The end customer's identifier in the caller's own system.

  • Максимальная длина: 190
Idempotency-Key обязательно

headerstring

Replay guard for a financial write. The same key returns the original result with the original status and never charges twice; a different body under a used key answers idempotency_conflict.

  • Максимальная длина: 190

Тело запроса

application/json
{
  "credits": "12.5000",
  "credit_type": "default",
  "note": "string"
}

Ответы

200

The account after the adjustment

application/json
{
  "data": {
    "customer_account_id": "74438200973594624",
    "customer_id": "74438200973594624",
    "project_id": "74438200973594624",
    "external_user_id": "user_8421",
    "credit_type": "default",
    "balance": "12.5000",
    "reserved": "12.5000",
    "available": "12.5000",
    "allow_negative": true,
    "low_balance_threshold": "12.5000",
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Ошибки

СтатусКодыКогда
400

Malformed request — e.g. the Idempotency-Key header is missing

401

No credential, or one that is not valid

402
403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

409

State conflict: idempotency clash, stale draft, illegal transition; the last owner of an organization (last_owner); the owned-organization limit (organization_limit_reached); an end customer with credit history that cannot be deleted (customer_has_history)

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Списать кредиты клиента за услугу приложения

POST /v1/customers/{externalUserId}/charge

  • Разрешение: customers:write
  • Нужен Idempotency-Key
  • Доступно в SDK для PHP и Node.js

The application's own charge — a PDF export, a seat, anything it sells outside an operation. credits is the positive amount to take; the journal entry is a charge with the amount negative and the note the caller gave. Guarded like every debit: an account with allow_negative off cannot go below what is held on it (402 insufficient_credits). A charge is not spend: the margin report sets credits against provider dollars, and no provider stands behind it. Crossing the account's low_balance_threshold sends customer.balance_low like any movement.

An external_user_id the project has never seen is 404 customer_not_found — nothing is created; a known customer without an account of the credit_type holds no such credits: 402 insufficient_credits. A blocked customer can be charged. Moves money, so it is behind the idempotency middleware, and the Idempotency-Key is unique within the project on the journal entry exactly as for a top-up: the same charge repeated under its key answers 200 with the account as it stands now and takes nothing — also when the balance could no longer cover it a second time — and a key that names any other top-up, adjustment or charge answers 409 idempotency_conflict.

Параметры

ПараметрОписание
externalUserId обязательно

pathstring

The end customer's identifier in the caller's own system.

  • Максимальная длина: 190
Idempotency-Key обязательно

headerstring

Replay guard for a financial write. The same key returns the original result with the original status and never charges twice; a different body under a used key answers idempotency_conflict.

  • Максимальная длина: 190

Тело запроса

application/json
{
  "credits": "12.5000",
  "credit_type": "default",
  "note": "string"
}

Ответы

200

The account after the charge

application/json
{
  "data": {
    "customer_account_id": "74438200973594624",
    "customer_id": "74438200973594624",
    "project_id": "74438200973594624",
    "external_user_id": "user_8421",
    "credit_type": "default",
    "balance": "12.5000",
    "reserved": "12.5000",
    "available": "12.5000",
    "allow_negative": true,
    "low_balance_threshold": "12.5000",
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Ошибки

СтатусКодыКогда
400

Malformed request — e.g. the Idempotency-Key header is missing

401

No credential, or one that is not valid

402
403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

409

State conflict: idempotency clash, stale draft, illegal transition; the last owner of an organization (last_owner); the owned-organization limit (organization_limit_reached); an end customer with credit history that cannot be deleted (customer_has_history)

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Цены операций в кредитах

GET /v1/credit-prices

  • Разрешение: customers:read
  • Доступно в SDK для PHP и Node.js

The project's price list: how many credits of which type one run of an operation holds from the customer named by context.user_id. An operation without a price does not touch credits at all. A handful of rows per project, so no cursor; the filters are equality.

Параметры

ПараметрОписание
operation_code необязательно

querystring

Only the prices of this operation code (equality).

  • Максимальная длина: 120
credit_type необязательно

querystring

Only the prices in this credit type (equality).

  • Максимальная длина: 50

Ответы

200

Credit prices of the project, by operation code and credit type

application/json
{
  "data": [
    {
      "credit_price_id": "74438200973594624",
      "project_id": "74438200973594624",
      "operation_code": "generate_email",
      "credit_type": "default",
      "credits": "12.5000",
      "created_at": "2026-10-02T09:30:00Z",
      "updated_at": "2026-10-02T09:30:00Z"
    }
  ]
}

Ошибки

СтатусКодыКогда
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Задать цену операции в кредитах

PUT /v1/credit-prices

  • Разрешение: management:write

Upsert by (operation_code, credit_type). Zero is allowed — it marks an operation free without deleting the row. A new price takes effect on the next hold; holds already taken keep theirs.

Тело запроса

application/json
{
  "operation_code": "generate_email",
  "credits": "12.5000",
  "credit_type": "default"
}

Ответы

200

The stored price

application/json
{
  "data": {
    "credit_price_id": "74438200973594624",
    "project_id": "74438200973594624",
    "operation_code": "generate_email",
    "credit_type": "default",
    "credits": "12.5000",
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Ошибки

СтатусКодыКогда
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Заголовки

  • X-Request-Id

Тело каждой ошибки — конверт ошибки.

Примеры

Найти клиентов, у которых заканчиваются кредиты

low_balance оставляет клиентов, у которых есть счёт, где доступно меньше 20 кредитов. У этого клиента на балансе 18, и 4 из них зарезервированы.

Terminal
curl "https://api.slen.ai/api/v1/customers?low_balance=20" \
  -H "Authorization: Bearer $SLEN_API_KEY"
200 OK
{
  "data": [
    {
      "customer_id": "74439840149372928",
      "external_user_id": "user_3107",
      "status": "active",
      "blocked_at": null,
      "block_reason": null,
      "accounts": [
        {
          "customer_account_id": "74439840153567232",
          "customer_id": "74439840149372928",
          "project_id": "74438200973594624",
          "external_user_id": "user_3107",
          "credit_type": "default",
          "balance": "18.0000",
          "reserved": "4.0000",
          "available": "14.0000",
          "allow_negative": false,
          "low_balance_threshold": "0.0000",
          "created_at": "2026-09-28T11:02:17+00:00",
          "updated_at": "2026-10-02T08:39:51+00:00"
        }
      ],
      "created_at": "2026-09-28T11:02:17+00:00",
      "updated_at": "2026-10-02T08:39:51+00:00"
    }
  ],
  "meta": {
    "limit": 50,
    "next_cursor": null
  }
}

Прочитать клиента

У клиента один счёт, типа кредитов default. Движение, которое опускает его available ниже 10, отправляет customer.balance_low.

Terminal
curl https://api.slen.ai/api/v1/customers/user_8421 \
  -H "Authorization: Bearer $SLEN_API_KEY"
200 OK
{
  "data": {
    "customer_id": "74439117522108416",
    "external_user_id": "user_8421",
    "status": "active",
    "blocked_at": null,
    "block_reason": null,
    "accounts": [
      {
        "customer_account_id": "74439117526302720",
        "customer_id": "74439117522108416",
        "project_id": "74438200973594624",
        "external_user_id": "user_8421",
        "credit_type": "default",
        "balance": "82.5000",
        "reserved": "0.0000",
        "available": "82.5000",
        "allow_negative": false,
        "low_balance_threshold": "10.0000",
        "created_at": "2026-10-02T08:40:30+00:00",
        "updated_at": "2026-10-02T09:20:05+00:00"
      }
    ],
    "created_at": "2026-10-02T08:40:00+00:00",
    "updated_at": "2026-10-02T08:40:00+00:00"
  }
}

Добавить клиента

Тело пустое. Клиент новый, поэтому ответ — 201, а accounts пуст, пока пополнение или настройки не создадут счёт.

Terminal
curl -X PUT https://api.slen.ai/api/v1/customers/user_8421 \
  -H "Authorization: Bearer $SLEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
201 Created
{
  "data": {
    "customer_id": "74439117522108416",
    "external_user_id": "user_8421",
    "status": "active",
    "blocked_at": null,
    "block_reason": null,
    "accounts": [],
    "created_at": "2026-10-02T08:40:00+00:00",
    "updated_at": "2026-10-02T08:40:00+00:00"
  }
}

Удалить клиента

Этого клиента добавили и ни разу не пополнили, поэтому клиент удаляется. У ответа нет тела.

Terminal
curl -X DELETE https://api.slen.ai/api/v1/customers/user_9050 \
  -H "Authorization: Bearer $SLEN_API_KEY"

204 No Content

Настроить счёт

Настройки создают счёт типа кредитов default с предупреждением ниже 10 кредитов. Счёт не может уйти ниже нуля.

Terminal
curl -X PUT https://api.slen.ai/api/v1/customers/user_8421/accounts/default \
  -H "Authorization: Bearer $SLEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "allow_negative": false,
    "low_balance_threshold": "10"
  }'
201 Created
{
  "data": {
    "customer_account_id": "74439117526302720",
    "customer_id": "74439117522108416",
    "project_id": "74438200973594624",
    "external_user_id": "user_8421",
    "credit_type": "default",
    "balance": "0.0000",
    "reserved": "0.0000",
    "available": "0.0000",
    "allow_negative": false,
    "low_balance_threshold": "10.0000",
    "created_at": "2026-10-02T08:40:30+00:00",
    "updated_at": "2026-10-02T08:40:30+00:00"
  }
}

Заблокировать клиента

Причина видна как block_reason. Счета сохраняют свои кредиты.

Terminal
curl https://api.slen.ai/api/v1/customers/user_8421/block \
  -H "Authorization: Bearer $SLEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Chargeback on invoice 1042"
  }'
200 OK
{
  "data": {
    "customer_id": "74439117522108416",
    "external_user_id": "user_8421",
    "status": "blocked",
    "blocked_at": "2026-10-02T09:31:10+00:00",
    "block_reason": "Chargeback on invoice 1042",
    "accounts": [
      {
        "customer_account_id": "74439117526302720",
        "customer_id": "74439117522108416",
        "project_id": "74438200973594624",
        "external_user_id": "user_8421",
        "credit_type": "default",
        "balance": "82.5000",
        "reserved": "0.0000",
        "available": "82.5000",
        "allow_negative": false,
        "low_balance_threshold": "10.0000",
        "created_at": "2026-10-02T08:40:30+00:00",
        "updated_at": "2026-10-02T09:20:05+00:00"
      }
    ],
    "created_at": "2026-10-02T08:40:00+00:00",
    "updated_at": "2026-10-02T09:31:10+00:00"
  }
}

Разблокировать клиента

У запроса нет тела. Клиент снова active, а blocked_at и block_reason очищены.

Terminal
curl -X POST https://api.slen.ai/api/v1/customers/user_8421/unblock \
  -H "Authorization: Bearer $SLEN_API_KEY"
200 OK
{
  "data": {
    "customer_id": "74439117522108416",
    "external_user_id": "user_8421",
    "status": "active",
    "blocked_at": null,
    "block_reason": null,
    "accounts": [
      {
        "customer_account_id": "74439117526302720",
        "customer_id": "74439117522108416",
        "project_id": "74438200973594624",
        "external_user_id": "user_8421",
        "credit_type": "default",
        "balance": "82.5000",
        "reserved": "0.0000",
        "available": "82.5000",
        "allow_negative": false,
        "low_balance_threshold": "10.0000",
        "created_at": "2026-10-02T08:40:30+00:00",
        "updated_at": "2026-10-02T09:20:05+00:00"
      }
    ],
    "created_at": "2026-10-02T08:40:00+00:00",
    "updated_at": "2026-10-02T10:02:00+00:00"
  }
}

Прочитать выписку клиента

В ответе три движения, самое новое — первым: списание за выгрузку, корректировка, которая сняла 12.5 кредита, и пополнение перед ними.

Terminal
curl https://api.slen.ai/api/v1/customers/user_8421/entries \
  -H "Authorization: Bearer $SLEN_API_KEY"
200 OK
{
  "data": [
    {
      "entry_id": "74439673397166080",
      "customer_account_id": "74439117526302720",
      "external_user_id": "user_8421",
      "credit_type": "default",
      "entry_type": "charge",
      "credits": "-5.0000",
      "balance_after": "82.5000",
      "available_after": "82.5000",
      "reservation_id": null,
      "note": "PDF export 311",
      "created_at": "2026-10-02T09:20:05+00:00"
    },
    {
      "entry_id": "74439652312547328",
      "customer_account_id": "74439117526302720",
      "external_user_id": "user_8421",
      "credit_type": "default",
      "entry_type": "adjust",
      "credits": "-12.5000",
      "balance_after": "87.5000",
      "available_after": "87.5000",
      "reservation_id": null,
      "note": null,
      "created_at": "2026-10-02T09:15:42+00:00"
    },
    {
      "entry_id": "74439117530497024",
      "customer_account_id": "74439117526302720",
      "external_user_id": "user_8421",
      "credit_type": "default",
      "entry_type": "topup",
      "credits": "100.0000",
      "balance_after": "100.0000",
      "available_after": "100.0000",
      "reservation_id": null,
      "note": "Invoice 1042",
      "created_at": "2026-10-02T08:41:00+00:00"
    }
  ],
  "meta": {
    "limit": 30,
    "next_cursor": null
  }
}

Пополнить клиента

Ключ называет это пополнение, и повтор с тем же ключом ничего не добавляет. Примечание называет счёт на оплату, по которому оно оплачено.

Terminal
curl https://api.slen.ai/api/v1/customers/user_8421/topup \
  -H "Authorization: Bearer $SLEN_API_KEY" \
  -H "Idempotency-Key: topup-user_8421-invoice-1042" \
  -H "Content-Type: application/json" \
  -d '{
    "credits": "100",
    "note": "Invoice 1042"
  }'
200 OK
{
  "data": {
    "customer_account_id": "74439117526302720",
    "customer_id": "74439117522108416",
    "project_id": "74438200973594624",
    "external_user_id": "user_8421",
    "credit_type": "default",
    "balance": "100.0000",
    "reserved": "0.0000",
    "available": "100.0000",
    "allow_negative": false,
    "low_balance_threshold": "10.0000",
    "created_at": "2026-10-02T08:40:30+00:00",
    "updated_at": "2026-10-02T08:41:00+00:00"
  }
}

Скорректировать баланс

Отрицательная сумма снимает кредиты.

Terminal
curl https://api.slen.ai/api/v1/customers/user_8421/adjust \
  -H "Authorization: Bearer $SLEN_API_KEY" \
  -H "Idempotency-Key: adjust-user_8421-refund-77" \
  -H "Content-Type: application/json" \
  -d '{
    "credits": "-12.5"
  }'
200 OK
{
  "data": {
    "customer_account_id": "74439117526302720",
    "customer_id": "74439117522108416",
    "project_id": "74438200973594624",
    "external_user_id": "user_8421",
    "credit_type": "default",
    "balance": "87.5000",
    "reserved": "0.0000",
    "available": "87.5000",
    "allow_negative": false,
    "low_balance_threshold": "10.0000",
    "created_at": "2026-10-02T08:40:30+00:00",
    "updated_at": "2026-10-02T09:15:42+00:00"
  }
}

Списать с клиента

Ваше приложение снимает 5 кредитов за сделанную выгрузку. Ключ называет выгрузку, поэтому повтор больше ничего не снимает.

Terminal
curl https://api.slen.ai/api/v1/customers/user_8421/charge \
  -H "Authorization: Bearer $SLEN_API_KEY" \
  -H "Idempotency-Key: charge-user_8421-export-311" \
  -H "Content-Type: application/json" \
  -d '{
    "credits": "5",
    "note": "PDF export 311"
  }'
200 OK
{
  "data": {
    "customer_account_id": "74439117526302720",
    "customer_id": "74439117522108416",
    "project_id": "74438200973594624",
    "external_user_id": "user_8421",
    "credit_type": "default",
    "balance": "82.5000",
    "reserved": "0.0000",
    "available": "82.5000",
    "allow_negative": false,
    "low_balance_threshold": "10.0000",
    "created_at": "2026-10-02T08:40:30+00:00",
    "updated_at": "2026-10-02T09:20:05+00:00"
  }
}

Получить список цен в кредитах

У проекта одна цена.

Terminal
curl https://api.slen.ai/api/v1/credit-prices \
  -H "Authorization: Bearer $SLEN_API_KEY"
200 OK
{
  "data": [
    {
      "credit_price_id": "74440031913676800",
      "project_id": "74438200973594624",
      "operation_code": "generate_email",
      "credit_type": "default",
      "credits": "2.0000",
      "created_at": "2026-10-02T08:30:00+00:00",
      "updated_at": "2026-10-02T08:30:00+00:00"
    }
  ]
}

Задать цену в кредитах

Начиная со следующего холда один вызов модели в этой операции стоит клиенту два кредита.

Terminal
curl -X PUT https://api.slen.ai/api/v1/credit-prices \
  -H "Authorization: Bearer $SLEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operation_code": "generate_email",
    "credits": "2"
  }'
200 OK
{
  "data": {
    "credit_price_id": "74440031913676800",
    "project_id": "74438200973594624",
    "operation_code": "generate_email",
    "credit_type": "default",
    "credits": "2.0000",
    "created_at": "2026-10-02T08:30:00+00:00",
    "updated_at": "2026-10-02T08:30:00+00:00"
  }
}

Что читать дальше

Собрано из openapi b070e1f, sdk contract 5cc7055, php ae4a53b, node 84bc62d