Быстрый старт Merchant API
Пошаговый сценарий для серверной интеграции без пользовательского портала BillBill: один биллинговый аккаунт на команду/организацию, бесплатный тариф, учёт usage и self-serve апгрейд на платный план.
Клиент: @wilix/billbill-client-js .
Предварительные условия
- OpenAPI-ключ мерчанта (
Authorization: Bearer …, вUser-Agent— подстрокаOpenAPI). - В админке настроены план (бесплатный и платный) и активный платёжный шлюз (
gatewayId). - Системный продукт по умолчанию имеет
productId: 0— не путайте сplanId(см. Справочник полей подписки).
1. Создать пользователя
Один BillBill-пользователь на workspace/команду. Для корреляции с вашей системой используйте externalUserId; email — контакт для счетов и чеков.
const { user } = await merchant.userNew({
email: 'billing@customer.example.com',
externalUserId: 'myapp-team-42',
firstName: 'Acme',
lastName: 'Team',
})
const userId = user!.id!B2B-паттерн: стабильный ключ — externalUserId; email может меняться через userChangeEmail (не через userUpdate — см. справочник).
2. Оформить бесплатную подписку
Даже для плана с нулевой ценой передайте gatewayId — без него возможна ошибка BaseGateway invalid.
const create = await merchant.subscriptionCreateSubmit({
planId: FREE_PLAN_ID,
userId,
gatewayId: GATEWAY_ID,
quantity: 1,
})
// subscriptionId — строка вида sub2026…, сохраните для дальнейших вызовов
const subscriptionId = create.subscription!.subscriptionId!Для платного плана при создании добавьте returnUrl (и рекомендуется cancelUrl), затем перенаправьте пользователя на create.link, если paid === false.
3. Получить квоты
Используйте productId: 0 для системного продукта. В JavaScript проверяйте productId != null, а не truthy — 0 валиден.
const snapshot = await merchant.getQuotaResolve({
productId: 0,
planId: FREE_PLAN_ID,
})
// кэшируйте snapshot.etag / version у себя4. Отправлять metered-события
await merchant.metricEventNew({
userId,
metricCode: 'token_usage',
metricProperties: { tokens: 1500 },
aggregationProperty: 'tokens',
})Свойства события должны соответствовать aggregationProperty, заданному при создании метрики в админке.
5. Апгрейд на платный план
5.1 Preview
const preview = await merchant.subscriptionUpdatePreview({
subscriptionId, // строка subscription.subscriptionId, НЕ subscription.id
newPlanId: PAID_PLAN_ID,
quantity: 1,
})Если preview.totalAmount > 0, для update_submit обязателен returnUrl.
5.2 Submit и редирект
import { assertReturnUrlForPaidOperation } from '@wilix/billbill-client-js'
assertReturnUrlForPaidOperation(preview.totalAmount, {
returnUrl: 'https://app.example.com/billing?billing=return',
})
const upgrade = await merchant.subscriptionUpdateSubmit({
subscriptionId,
newPlanId: PAID_PLAN_ID,
quantity: 1,
returnUrl: 'https://app.example.com/billing?billing=return',
cancelUrl: 'https://app.example.com/billing?billing=cancel',
})
if (!upgrade.paid && upgrade.link) {
// перенаправьте пользователя на upgrade.link
}5.3 После возврата с оплаты
- Обновите локальное состояние:
getSubscriptionUserSubscriptionDetailилиsubscriptionDetail. - Обработайте вебхуки:
payment.success,invoice.paid,subscription.updated,subscription.pending_update.success(порядок — в каталоге вебхуков). - Сбросьте кэш квот при смене
planId.
Матрица обязательных полей
| Endpoint | Сценарий | Обязательные поля |
|---|---|---|
subscription/create_submit | Бесплатный план | planId, пользователь (userId / email+externalUserId), gatewayId |
subscription/create_submit | Платный план | То же + returnUrl; рекомендуется cancelUrl |
subscription/update_submit | Смена без оплаты | subscriptionId, newPlanId, quantity |
subscription/update_submit | Апгрейд с оплатой | То же + returnUrl; рекомендуется cancelUrl |
Подробнее: Справочник полей подписки.
Пример в репозитории клиента
yarn example:merchant:plan-upgradeСм. billbill-client-js/examples/merchant-plan-upgrade/.