billing
POST /v1/subscriptions/{subscriptionId}/plan
Move a subscription onto a bigger or smaller plan.
Аутентификация
Отправьте ключ API в качестве токена носителя (bearer token). Ключ должен иметь разрешение billing.payment.manage; ключ без него отклоняется с кодом 403, а не 404.
Этот эндпоинт не принимает идентификатор организации. Ваш ключ уже определяет организацию, к которой он принадлежит, и ответ ограничивается ее рамками.
Попробовать
Замените всё в угловых скобках на собственные значения, а плейсхолдер ключа — на ключ из вашей панели управления.
curl -X POST https://api.zinndigital.com/v1/subscriptions/{subscriptionId}/plan \
-H "Authorization: Bearer zdk_live_…" \
-H "Content-Type: application/json" \
-d '{ "plan_version_id": <Uuid> }'Вошли в систему? Консоль API в вашей панели управления автоматически подставляет реальный идентификатор вашей организации и ваш собственный ключ, а также выполняет запрос к работающему API, чтобы вы могли увидеть актуальный ответ. Откройте эту конечную точку в API-консоли
Подробнее
Charges the prorated difference for the remainder of the current period, moves every site the subscription entitles, and supersedes the subscription onto the new plan version — keeping the existing period window, so the customer's renewal date does not move and they are not handed a free extra period. ⛔ A plan change SUPERSEDES rather than mutates, because a subscription pins the exact version it was sold so that a later catalogue edit cannot rewrite what a live subscriber pays. subscription_id in the response is therefore a new id and a client holding the old one must replace it. ⭐⭐ slots_before and slots_after are read back from the subscription rows, not derived from the plan that was asked for. A plan change that answers 200 and silently does not take effect is the worst outcome on this path, and a status code cannot tell that apart from one that worked. Mid-period money. A larger plan is charged the difference now — the customer asked for more room today, and applying it at the next renewal is the buy-flow dead end in another costume. A smaller plan returns the unused difference as account credit, not a card refund: it is instant, it cannot be unavailable, it is idempotent, and it is spendable on their next order. ⛔ Account credit carries no VAT credit note; a proration credit spans the current period's invoice rather than reversing it. ⛔ expected_total_minor is a money guard, not a convenience. It is the figure the customer was actually shown, and the change is refused 422 when the freshly-computed quote differs. Every other refusal is 422 as well, with nothing charged and nothing changed: a plan on another product line, the plan they are already on, a plan that has been re-priced since the page loaded, account usage above what a smaller plan allows, a card decline. ⛔ The downgrade guard is account-wide and there is no override. The same check_downgrade the site endpoint and the staff tariff endpoint call: sites, mailboxes, mailbox storage and disk across the org's subtree. Staff have an audited override because they sometimes genuinely need to move an over-limit account; a customer overriding their own quota check is not an override, it is no check. Repeating an identical request is the recovery and it is safe. Every step is idempotent on a key anchored to the subscription being left, so an attempt that died part-way is finished rather than duplicated: one order, one charge, one credit, one supersede. 404 for a subscription in another tenant as well as for one that does not exist. 503 when the driver behind an entitled site cannot move a package between types at all — our gap, not theirs. Requires billing.payment.manage — it charges a card, so the key that gates paying is the key that gates committing to a payment.
Параметры
| Имя | Тип | Обязательно | Что это |
|---|---|---|---|
subscriptionId (path) | Uuid | Да | The subscription whose plan is being read or changed. |
Тело запроса
| Имя | Тип | Обязательно | Что это |
|---|---|---|---|
plan_version_id | Uuid | Да | The priced plan version to move onto, exactly as getSitePlanChoices reported it. |
expected_total_minor | integer | Нет | ⛔ A money guard, not a convenience. The figure the customer was actually shown, in minor units. The engine refuses 422 when its freshly-computed quote differs, so a price… |
gateway | object | Нет | The payment rail the customer picked, from getPaymentOptions. Omit it (or send null) for "no preference", which follows the payment method the organization would be charged on… |
Ответ
| Имя | Тип | Обязательно | Что это |
|---|---|---|---|
plan_code | string | Да | The plan this subscription is now on. |
plan_name | string | Да | Its catalogue name, so a receipt can name it without a second lookup. |
plan_version_id | string | Да | The priced version the new subscription carries. |
subscription_id | string | Да | The new subscription. A plan change supersedes rather than mutates, because a subscription pins the exact version it was sold — so this id differs from the one in the request… |
order_id | string | Да | The order the charge was raised against, or "" when the change resulted in a credit and no order was minted. |
charged_minor | integer | Да | What was actually taken, in minor units. |
credited_minor | integer | Да | What was actually returned as account balance, in minor units. |
package_type | string | Да | The vendor package type, read back after the move. "" on our own fleet and "" when the subscription entitles no site — there is no package to move. |
slots_before | integer | Да | The site allowance the subscription held before the change. |
slots_after | integer | Да | The site allowance it holds now. |
slots_before_unlimited | boolean | Да | The old plan sold unlimited sites, so slots_before is null by design. |
slots_after_unlimited | boolean | Да | The new plan sells unlimited sites, so slots_after is null by design. |
quote | SitePlanQuote | Да | The quote the change was performed against. |
Ошибки, которые может возвращать этот эндпоинт
401 · 403 · 404 · 422 · 429 · 503