Endpoint (API v2): Payment Link для корзины — несколько продуктов

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

Зачем это нужно

Обычная ручка создаёт платёжную ссылку на один продукт. Эта — собирает корзину: одну Stripe Payment Link сразу из нескольких уже одобренных продуктов партнёра, с указанием количества каждого. Клиент оплачивает весь набор за один чекаут.

Типичные сценарии: бандл «3 товара по акции», набор «пакет + дополнения», заказ из нескольких позиций с разными количествами, тариф подписки, собранный из частей — «базовый план + места + дополнительные аккаунты».

Повторно проходить модерацию не нужно — ручка переиспользует уже одобренные продукты и создаёт только новые Stripe Price + одну Payment Link с несколькими позициями.

Разовые и подписочные корзины (с 16.09.2026). Тип корзины определяется продуктами, передавать его не нужно:

Продукты в корзине

Что получит клиент

все разовые

одну оплату всей корзины

все подписочные с одинаковым периодом (например, все помесячные)

одну подписку из нескольких позиций: каждый период списывается сумма всех позиций × количества

Разовые и подписочные продукты в одной корзине смешивать нельзя, как и подписки с разным периодом (месяц + год) — вернётся INVALID_INPUT. Пробного периода у корзины нет: если нужен trial, выпускайте ссылку на один продукт.

Как подключиться

  1. Запросите API-ключ у вашего менеджера EasyPay (или скопируйте в мини-аппе, «Show key» на первом шаге онбординга).

  2. Менеджер активирует разрешение product_create для вашего аккаунта (то же, что и для создания продукта — отдельного разрешения не нужно).

  3. Узнайте stripe_product_id каждого нужного одобренного продукта (есть в мини-аппе в карточке продукта).

Endpoint

POST https://api.appsign.me/create-partner-stripe-cart-payment-link
Content-Type: application/json
X-Partner-Api-Key: ваш-api-ключ

Формат запроса

{
  "items": [
    { "stripe_product_id": "prod_AAA", "unit_amount": 1875, "quantity": 2 },
    { "stripe_product_id": "prod_BBB", "unit_amount": 3750, "quantity": 1 }
  ],
  "currency": "USD",
  "payment_method_types": ["card", "link"],
  "allow_promotion_codes": false,
  "success_url": "https://example.com/thanks",
  "client_token": "order-42"
}

Параметры:

Параметр

Обязательный

Описание

items

Да

Массив позиций корзины, от 1 до 20 (лимит Stripe на line items).

items[].stripe_product_id

Да

ID одобренного продукта партнёра (prod_…). Все продукты должны принадлежать вам и быть одобрены. Дубликаты одного stripe_product_id в корзине запрещены — объедините в одну позицию через quantity.

items[].unit_amount

Да

Цена за единицу в наименьшей единице валюты (центы): 1875 = $18.75. Для подписки — цена единицы за период. Целое от 50 до 99999999.

items[].quantity

Да

Количество единиц этой позиции. Целое от 1 до 999.

currency

Нет

"USD", "EUR" или "GBP". Если указана — должна совпадать с валютой всех продуктов (Stripe Payment Link использует одну валюту). Если не указана — берётся из продуктов (она у всех должна быть одинаковой).

payment_method_types

Нет

Массив способов оплаты для ссылки. Если не указан — Stripe подберёт по умолчанию. Значения проверяются: неподключённый или несовместимый с валютой способ вернёт invalid_input. См. раздел «Способы оплаты» ниже.

allow_promotion_codes

Нет

Разрешить ввод промокода на чекауте. По умолчанию false.

success_url

Нет

HTTPS-URL для редиректа после оплаты. Максимум 2048 символов.

client_token

Нет

Ваш идемпотентный токен (см. ниже).

Способы оплаты. Проверенные и работающие: card, link (под USD, EUR, GBP, BRL), sepa_debit (только EUR), pix (только BRL), us_bank_account (только USD).

Два способа не подключены в Stripe-аккаунте EasyPay и отклоняются с ошибкой invalid_input: zip и bacs_debit. Нужны — напишите команде заботы EasyPay.

Остальные способы Stripe передавайте, если нужны: мы их не блокируем, но и не обещаем — совместимость определяет Stripe. Способ, несовместимый с валютой корзины, отклоняется до обращения в Stripe, с текстом, называющим и способ, и валюту.

Что наследуется от продуктов (нельзя переопределить): тип корзины (разовая или подписка) и период подписки, тестовый/боевой режим, базовая валюта. Все продукты корзины должны быть в одной валюте и одном режиме (все live или все test).

Идемпотентность — client_token

Вам не нужно конструировать сложный ключ идемпотентности — сервер собирает его сам. Достаточно опционального client_token:

  • Передали **client_token** → повтор того же запроса с тем же токеном вернёт ту же ссылку (поле duplicate: true), без создания дублей. Используйте, если хотите безопасный retry — например, привяжите токен к ID заказа.

  • Не передали **client_token** → одинаковые по составу корзины в пределах окна дедупятся автоматически (по содержимому).

Сменили состав корзины — используйте новый client_token (тот же токен с другим составом вернёт IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_PAYLOAD).

Формат ответа

Успешный ответ (200)

{
  "success": true,
  "payment_link_id": "plink_XXXXXXXXXXXX",
  "short_url": "https://short.appsign.me/abc",
  "short_url_id": "lnk_5hfk_...",
  "currency": "USD",
  "mode": "one_time",
  "interval": null,
  "interval_count": null,
  "line_item_count": 2,
  "items": [
    { "stripe_product_id": "prod_AAA", "stripe_price_id": "price_YYY", "quantity": 2 },
    { "stripe_product_id": "prod_BBB", "stripe_price_id": "price_ZZZ", "quantity": 1 }
  ],
  "duplicate": false
}

Поле

Описание

short_url

Короткая ссылка (short.appsign.me) — единственная партнёр-смотрящая ссылка для чекаута. Отправляйте её клиенту. Сохраните на своей стороне — отдельного метода для повторного чтения нет.

short_url_id

ID короткой ссылки (на случай будущего удаления/обновления).

payment_link_id

ID Stripe Payment Link (plink_…) — для сверки в Stripe Dashboard. Полный buy.stripe.com URL партнёру не возвращается.

items[].stripe_price_id

Созданный Stripe Price для каждой позиции.

mode

one_time — разовая оплата, subscription — одна подписка из всех позиций.

interval / interval_count

Период подписки (например, month и 1). У разовой корзины — null.

line_item_count

Число позиций в корзине.

duplicate

true, если запрос с этим client_token уже обрабатывался и вернулся закэшированный результат.

Ошибки

Все ошибки возвращаются с HTTP 200 + полем success: false и error_code. Проверяйте success, а не HTTP-статус.

error_code

Когда срабатывает

INVALID_INPUT

Невалидное тело: пустой/слишком большой items (>20), дубликат продукта, unit_amount/quantity вне диапазона, несовпадение валюты, разовые и подписочные продукты вместе, подписки с разным периодом, смешанные валюты или режимы (live/test) в корзине.

AUTH_REQUIRED / INVALID_API_KEY

Не передан или невалиден API-ключ.

PRODUCT_NOT_FOUND

Один из stripe_product_id не принадлежит партнёру или не существует.

PRODUCT_NOT_APPROVED

Один из продуктов ещё не прошёл модерацию.

CROSS_TENANT_ATTEMPT

Один из stripe_product_id принадлежит другому партнёру.

IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_PAYLOAD

Тот же client_token использован с другим составом корзины. Сгенерируйте новый токен.

PREVIOUS_ATTEMPT_FAILED

Прошлая попытка с этим токеном завершилась ошибкой. Используйте новый client_token.

OPERATION_IN_PROGRESS

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

SHORT_URL_UNAVAILABLE

Payment Link создан, но короткая ссылка временно недоступна. Напишите в команду заботы с вашим client_token.

INTEGRATION_TIMEOUT / INTEGRATION_UPSTREAM_ERROR

Временный сбой Stripe. Повторите с новым client_token.

INTERNAL_ERROR

Внутренний сбой EasyPay. Команда заботы уведомлена.

Ограничения

  • От 1 до 20 позиций в корзине.

  • Только одобренные продукты (первая ссылка на новый продукт — через мини-апп, чтобы пройти модерацию).

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

  • Состав выданной ссылки не редактируется — изменилось количество, создайте новую корзину.

  • Все продукты — в одной валюте (USD/EUR/GBP) и одном режиме (все live или все test).

  • unit_amount за единицу: от 50 до 99999999 (центы). quantity: от 1 до 999.

  • Сохраните short_url сразу после получения ответа.

Пример на Python

import urllib.request
import json
import uuid

url = "https://api.appsign.me/create-partner-stripe-cart-payment-link"
payload = {
    "items": [
        {"stripe_product_id": "prod_AAA", "unit_amount": 1875, "quantity": 2},
        {"stripe_product_id": "prod_BBB", "unit_amount": 3750, "quantity": 1},
    ],
    "client_token": f"order-{uuid.uuid4().hex[:12]}",
}

req = urllib.request.Request(
    url,
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "Content-Type": "application/json",
        "X-Partner-Api-Key": "ваш-api-ключ",
    },
    method="POST",
)

with urllib.request.urlopen(req) as resp:
    result = json.loads(resp.read().decode("utf-8"))

if result.get("success"):
    print("Ссылка для клиента:", result["short_url"])
    print("Позиций:", result["line_item_count"])
else:
    print("Ошибка:", result.get("error_code"), "—", result.get("error_message"))

Пример на cURL

curl -X POST "https://api.appsign.me/create-partner-stripe-cart-payment-link" \
  -H "Content-Type: application/json" \
  -H "X-Partner-Api-Key: ваш-api-ключ" \
  -d '{
    "items": [
      { "stripe_product_id": "prod_AAA", "unit_amount": 1875, "quantity": 2 },
      { "stripe_product_id": "prod_BBB", "unit_amount": 3750, "quantity": 1 }
    ],
    "client_token": "order-42"
  }'