Endpoint (API v2): Перенос даты автосписания подписки (подарочные дни)

ℹ️ EasyPay API v2. Это ручка второго поколения EasyPay API (база https://api.appsign.me), пришедшего на смену legacy-API v1 (https://n8n.thenextgen.store/webhook/*). Отличия v2 от v1: авторизация заголовком X-Partner-Api-Key, плоское тело запроса, идемпотентность через опциональный client_token (полный ключ собирает сервер), коды ошибок — в UPPER_CASE.

Когда это нужно

Вы хотите подарить подписчику несколько дней доступа — как компенсацию за неудобство, как бонус или в рамках акции — и чтобы следующее списание прошло позже ровно на этот срок.

Как это работает

Подарочные дни выдаются подписке как бесплатный период. Дата следующего списания переносится вперёд на подаренный срок, и вместе с ней переезжает весь дальнейший график.

Пример: подписка списывалась 6-го числа каждого месяца, вы подарили 14 дней — следующее списание пройдёт 20-го, и дальше каждое 20-е.

  • Деньги в момент подарка не списываются и не возвращаются.

  • Может появиться служебный счёт на 0 — это нормальная часть операции, клиент по нему ничего не платит.

  • Тариф не меняется: мы не трогаем ни цену, ни состав подписки. Сумма счёта может отличаться от прежней только там, где она и так зависит от периода — оплата по факту потребления, заканчивающаяся скидка, налоги, привязанные к дате.

Что обязательно учесть в своей интеграции

На время подарка статус подписки — **trialing**, а не **active**.

Если доступ к вашему продукту открывается по условию status === 'active', подписчик потеряет доступ ровно в подаренные дни — то есть подарок сработает наоборот. Расширьте условие: доступ открыт при active и при trialing.

Если вы подписаны на события подписок, вы получите customer.subscription.updated с новым статусом и новой датой списания — по нему удобно продлевать доступ на своей стороне автоматически.

Ограничения

  • Только вперёд. Сдвинуть дату списания на более раннюю нельзя.

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

  • Если по подписке уже запланирована отмена — сначала снимите отмену, иначе результат сдвига непредсказуем.

  • Горизонт подарка — недели, а не годы. Это компенсация или бонус, а не бессрочная заморозка биллинга.

Как это сделать через API

POST https://api.appsign.me/postpone-partner-stripe-subscription

Ключ передаётся заголовком X-Partner-Api-Key (или полем api_key в теле). Метод доступен по отдельному праву — напишите команде заботы, мы его включим.

Параметры

Поле

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

Описание

subscription_id

да

ID подписки в Stripe, sub_…

next_charge_at

одно из двух

Новая дата списания. YYYY-MM-DD — берётся конец этих суток по UTC; можно передать и точное время в ISO

extend_days

одно из двух

На сколько суток отложить, от 1 до 90. Требует expected_current_charge_at

expected_current_charge_at

вместе с extend_days

Текущая дата списания, от которой вы считаете сдвиг. Мы сверим её с действительной

client_token

нет

Ваш идемпотентный токен — номер заказа, uuid, что угодно короткое. Не передали — сервер дедупит по содержимому запроса: повтор того же запроса вернёт первый результат, а не подарит дни второй раз.

Почему сверка обязательна для **extend_days**. «Плюс семь дней» — это сдвиг относительно текущей даты, и если запрос уйдёт дважды (ретрай по таймауту, повтор из очереди), клиент получит четырнадцать дней вместо семи. Назовите дату, от которой считаете: если она разошлась с действительной, мы откажем, а не подарим второй раз. Абсолютный next_charge_at этого не требует — повтор просто просит ту же дату.



Пример запроса

POST /postpone-partner-stripe-subscription
X-Partner-Api-Key: <ваш ключ>
Content-Type: application/json

{
  "subscription_id": "sub_1ABCdefGHIjklMNO",
  "extend_days": 7,
  "expected_current_charge_at": "2026-10-09T10:50:57.000Z",
  "client_token": "gift-2417"
}

Пример ответа

{
  "success": true,
  "subscription_id": "sub_1ABCdefGHIjklMNO",
  "environment": "live",
  "status": "trialing",
  "previous_charge_at": "2026-10-09T10:50:57.000Z",
  "next_charge_at": "2026-10-16T10:50:57.000Z",
  "granted_days": 7,
  "cancel_at_period_end": false,
  "already_applied": false
}

already_applied: true означает, что подписка уже стояла на запрошенной дате и мы ничего не меняли — так выглядит безопасный повтор запроса. В этом случае granted_days равен нулю.

Ошибки

Ответ всегда приходит с HTTP 200; успех или отказ различайте по полю success. При отказе приходит error_code и понятное error_message.

Код

Когда

Что делать

INVALID_INPUT

не указано ни одного из двух полей даты, указаны оба сразу, extend_days вне 1..90 или без сверки, дата раньше текущей, сдвиг дальше 90 суток

поправить запрос по сообщению

PRECONDITION_FAILED

expected_current_charge_at разошёлся с действительной датой

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

SUBSCRIPTION_NOT_FOUND

подписки нет среди ваших

проверить ID; только что созданная подписка появляется через несколько секунд

SUBSCRIPTION_NOT_POSTPONABLE

подписка не в статусе active или trialing

при неоплаченном счёте сначала нужен платёж

SUBSCRIPTION_SCHEDULED_FOR_CANCEL

по подписке запланирована отмена

снять отмену, затем дарить дни

NO_AUTOMATIC_CHARGE

у подписки не автосписание, а выставление счёта

переносить дату автосписания нечему

COLLECTION_PAUSED

сбор платежей по подписке приостановлен

снять паузу

OPERATION_IN_PROGRESS

другой запрос по этой же подписке ещё выполняется

повторить через секунду

IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_PAYLOAD

тот же client_token пришёл с другим содержимым запроса

передать новый client_token

Есть ещё три отказа для редких конфигураций подписки — расписание фаз, нестандартный режим биллинга, настройка «отменить подписку по окончании пробного периода». Во всех трёх перенос сработал бы не так, как обещает этот метод, поэтому мы отказываем и просим написать команде заботы.

Если делать руками

Метод нужен не всем: разовый подарок можно попросить у команды заботы — пришлите номер подписки (sub_…) и срок, обработаем в течение рабочего дня.