Ведите своих клиентов и их кредиты
PHPСоздайте клиента, пополните и спишите его кредиты, прочитайте баланс и выписку, запустите флоу, который оплачивает клиент, и заблокируйте клиента.
7 мин чтения
Клиент — пользователь вашего приложения, который платит за то, что Slen выполняет для него, кредитами — вашей собственной единицей, без валюты. Ваше приложение создаёт клиента, пополняет его кредиты и называет клиента в каждом запуске; Slen берёт кредиты за вызовы моделей в запуске. Вызовам этой страницы нужен ключ с customers:write, а чтению — с customers:read.
Создать клиента
// The external user id is your own opaque id of the customer — not an email address or a name.
$customer = $slen->customers()->create('user_8421');
echo $customer->externalUserId, ' ', $customer->status->value, PHP_EOL;Внешний идентификатор — ваш собственный идентификатор клиента. Держите его непрозрачным — не адрес почты и не имя: он виден в консоли и в каждой выписке.
customers.create()гарантирует, что клиент существует: второй вызов отвечает тем же клиентом. Он не двигает кредиты, и у нового клиента нет счетов.У клиента по одному счёту на каждый тип кредитов:
default, если вы не назвали другой.
Пополнить и списать
use Slen\Sdk\Modules\Customers\Options\MovementOptions;
$account = $slen->customers()->topUp('user_8421', '100.0000', new MovementOptions(note: 'Invoice 7781', idempotencyKey: 'invoice-7781:topup'));
echo $account->balance, PHP_EOL;customers.topUp()добавляет кредиты. Он создаёт счёт этого типа кредитов, а также клиента, когда их ещё нет.Примечание записывается в строку выписки: номер счёта на оплату, причина.
Ключ идемпотентности называет движение: под тем же ключом кредиты движутся один раз — Ключи идемпотентности.
Тип кредитов, примечание и ключ движения — именованные аргументы MovementOptions, последнего аргумента вызова. Остальные вызовы этой страницы принимают свои опции так же — CustomerListOptions, AccountOptions, BlockOptions, EntryListOptions, PriceListOptions, — а RequestOptions там, где больше ничего не принимают.
// A service of your own application, paid for in the customer's credits.
$charged = $slen->customers()->charge('user_8421', '5.0000', new MovementOptions(note: 'PDF export', idempotencyKey: 'export-991:charge'));
echo $charged->balance, PHP_EOL;customers.charge()берёт кредиты за услугу вашего собственного приложения, которую Slen не выполняет: экспорт, отчёт, место в команде. Выписка показывает его отдельным списанием, а не тратой вызова модели.Списание, которое счёт не может покрыть, отклоняется с
insufficient_credits, если счёту нельзя уходить ниже нуля. Списание ничего не создаёт: списание для клиента, которого Slen не знает, отклоняется сcustomer_not_found.customers.adjust()вручную корректирует баланс, со знаком: положительная сумма добавляет кредиты, отрицательная — забирает.Кредиты — десятичная строка не больше чем с четырьмя знаками после точки:
'5','5.25'. Любое другое значение, ноль и отрицательное пополнение или списание отклоняются до отправки запроса, с кодомinvalid_request.
Прочитать баланс и выписку
$customer = $slen->customers()->get('user_8421');
foreach ($customer->accounts as $held) {
echo $held->creditType, ' ', $held->available, PHP_EOL;
}customers.get() отвечает клиентом со всеми его счетами. У счёта три суммы:
balance— сколько на счёте;reserved— сколько на нём держат идущие запуски;available—balanceминусreserved: сколько может взять новый запуск.
use Slen\Sdk\Modules\Customers\Options\EntryListOptions;
$statement = $slen->customers()->entries('user_8421', new EntryListOptions(limit: 2));
foreach ($statement->data as $entry) {
echo $entry->entryType->value, ' ', $entry->credits, ' ', $entry->note, PHP_EOL;
}customers.entries() читает выписку: каждое движение кредитов клиента, сначала самые новые, постранично. Её можно сузить до одного типа кредитов и одного вида записи.
| Вид | Кто пишет | Что делает |
|---|---|---|
topup | customers.topUp() | Добавляет к балансу |
charge | customers.charge() | Забирает из баланса |
adjust | customers.adjust() | Двигает баланс в любую сторону |
hold | Вызов модели в запуске | Забирает цену из доступного до вызова модели |
commit | Тот же вызов, когда он удался | Забирает цену из баланса |
release | Тот же вызов, когда он не удался | Возвращает цену в доступное |
Страница несёт курсор следующей: передайте его в следующий вызов и остановитесь, когда он равен null. customers.list() так же читает клиентов проекта с их счетами. Он находит их по части внешнего идентификатора, по статусу, по типу кредитов или по lowBalance — доступно меньше кредитов, чем число, которое вы передали.
Запуск, который оплачивает клиент
Назовите клиента в запуске, а тип кредитов — когда он не default, — Отправить запрос.
Когда у проекта есть цена в кредитах для операции, каждый вызов модели в запуске резервирует эту цену на счёте клиента до вызова модели. Кредиты забираются, когда вызов удался, и возвращаются, когда он не удался.
Операция без цены в кредитах кредитов не берёт. Цены задают в консоли, а
customers.prices()их читает.Запуск, который счёт не может оплатить, отклоняется до вызова модели, с
insufficient_credits.Платный запуск для клиента, которого Slen не знает, отклоняется с
customer_not_found. Сначала создайте клиента и пополните его кредиты.
use Slen\Sdk\Exceptions\InsufficientCreditsException;
use Slen\Sdk\Modules\Operations\Options\ExecuteOptions;
try {
$slen->operations()->execute(
'generate_email',
['messages' => [['role' => 'user', 'content' => 'Write a short follow-up email.']]],
new ExecuteOptions(customer: 'user_9310', idempotencyKey: 'order-45:email'),
);
} catch (InsufficientCreditsException $refused) {
// The customer's account cannot pay for the run: nothing ran, nothing was held.
echo $refused->errorCode, PHP_EOL;
}insufficient_credits — один из отказов в трате, и оба SDK выбрасывают его как тип этого семейства — Когда трата отклонена.
Настройки счёта
customers.updateAccount() задаёт две настройки одного счёта:
может ли баланс уходить ниже нуля — по умолчанию нет;
порог, ниже которого движение отправляет вебхук
customer.balance_low, —'0', значение по умолчанию, его выключает.
Вызов задаёт обе сразу: настройка, которую вы не передали, возвращается к значению по умолчанию. Он создаёт клиента и счёт, когда их нет. Вебхук низкого баланса отправляется один раз — когда движение опускает доступные кредиты ниже порога, — Вебхуки.
Заблокировать клиента
use Slen\Sdk\Modules\Customers\Options\BlockOptions;
// New runs for the customer are refused from now on; the balance can still be settled.
$blocked = $slen->customers()->block('user_8421', new BlockOptions(reason: 'chargeback'));
echo $blocked->status->value, ' ', $blocked->blockReason, PHP_EOL;Новые запуски заблокированного клиента отклоняются с
customer_blocked. Запуск, который стоял в очереди или ждал до блокировки, отклоняется на следующем вызове модели, который берёт кредиты. Оба SDK выбрасывают этот код как отказ политики.Пополнения, списания, корректировки и выписка остаются открытыми, чтобы вы могли рассчитаться с клиентом.
customers.unblock()снимает блокировку.customers.delete()удаляет клиента без истории: без движений и без баланса. Удаление клиента с историей отклоняется с409и кодомcustomer_has_history— заблокируйте его вместо этого.
Что читать дальше
Когда трата отклонена — запуск, отклонённый из-за нехватки кредитов, и что с этим делать.
Вебхуки — узнайте, что кредиты клиента заканчиваются.
Кредиты клиентов — те же клиенты и счета в консоли.
Объекты ответа — каждое поле клиента, счёта и строки выписки.
Клиенты и кредиты — те же операции по HTTP.