Перейти к содержанию

Brand Partner API

Небольшой, предсказуемый REST API для создания заказов mintbot, опроса их статуса и получения событий жизненного цикла. JSON на входе, JSON на выходе. Авторизация bearer-token. Идемпотентные записи. Подписанные webhooks.

Панель доступа к API Перейти к webhooks


Кратко

Base URL https://mint.mintbot.ai/api/v1
Auth `Authorization: Bearer ***
Идемпотентность Idempotency-Key: <uuid> при каждом POST
Content type application/json
Rate limit 120 req / 60 s на партнёра
Webhooks Подписываются HMAC-SHA256, повторяются до 7 раз

Аутентификация

Каждый запрос передаёт партнёрский API-ключ в заголовке Authorization. Создайте или ротируйте ключ в панели.

Authorization: Bearer mo_liv...xxxx
Content-Type: application/json

У ротации нет льготного окна

Ротация ключа атомарно отзывает предыдущий. Заранее подготовьте замену значения в своей конфигурации, прежде чем нажимать Rotate.

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

Каждый POST требует заголовок Idempotency-Key. Подойдёт любой UUID для каждого отдельного запроса.

  • Мы кэшируем ответ на 24 часа. Повтор с тем же ключом возвращает исходный ответ с Idempotent-Replay: true.
  • Повторное использование того же ключа с другим телом возвращает 409 idempotency_key_mismatch.

Заказы

Создать заказ

POST /orders

Создаёт заказ и возвращает URL Stripe Checkout. После подтверждения оплаты mintbot разворачивает агента, а событие дохода с долей партнёра записывается автоматически.

Запрос

{
  "tier": "s1",
  "duration_months": 1,
  "credit_usd": 10,
  "language": "en",
  "external_id": "your-side-id",
  "success_url": "https://your.app/thanks?id={ORDER_ID}",
  "cancel_url":  "https://your.app/cart",
  "webhook_url": "https://your.app/mintbot-webhook"
}
tier
Один из trial, s1, s2, s4.
duration_months
Срок жизни сервера в календарных месяцах. Должно быть 1, 3 или 12.
credit_usd
Необязательно. Предоплаченный чат-кредит, включённый в заказ.
language
Необязательно. Влияет на локаль Stripe Checkout и язык приветственного email.
external_id
Необязательно. Возвращается в каждом webhook и ответе заказа — используйте его, чтобы связывать заказы mintbot со строками в собственной системе.
success_url · cancel_url
URL возврата Stripe Checkout. {ORDER_ID} подставляется на стороне сервера.
webhook_url
Необязательно. Переопределение URL webhook уровня партнёра для конкретного заказа.

Ответ — 201 Created

{
  "id": 42,
  "tier": "s1",
  "duration_months": 1,
  "credit_usd": 10,
  "amount_cents": 1200,
  "currency": "usd",
  "status": "awaiting_payment",
  "checkout_url": "https://checkout.stripe.com/c/pay/cs_test_…",
  "panel_url": null,
  "expires_at": null,
  "language": "en",
  "external_id": "your-side-id",
  "created_at": "2026-05-16 09:58:00",
  "paid_at": null
}

Пример

curl -X POST https://mint.mintbot.ai/api/v1/orders \
  -H "Authorization: Bearer *** \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "tier": "s1",
    "duration_months": 1,
    "credit_usd": 10,
    "success_url": "https://your.app/thanks?id={ORDER_ID}",
    "cancel_url":  "https://your.app/cart"
  }'
import os, uuid, requests

r = requests.post(
    "https://mint.mintbot.ai/api/v1/orders",
    headers={
        "Authorization": f"Bearer {os.environ['MINTBOT_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "tier": "s1",
        "duration_months": 1,
        "credit_usd": 10,
        "success_url": "https://your.app/thanks?id={ORDER_ID}",
        "cancel_url":  "https://your.app/cart",
    },
    timeout=10,
)
r.raise_for_status()
order = r.json()
redirect_to = order["checkout_url"]

Получить заказ

GET /orders/{id}

Получает один заказ по его mintbot id. Возвращает ту же структуру, что и POST /orders.

curl https://mint.mintbot.ai/api/v1/orders/42 \
  -H "Authorization: Bearer ***

Список заказов

GET /orders

Список с курсорной пагинацией, сначала самые новые.

Query parameters

status
Необязательно. Фильтр по awaiting_payment, completed, deployed, deploy_failed или expired.
cursor
Необязательно. Передайте next_cursor с предыдущей страницы, чтобы продолжить.

Ответ

{
  "items": [ /* OrderResponse … */ ],
  "next_cursor": "37"
}

next_cursor равен null, когда страниц больше нет.


Продлить заказ

POST /orders/{id}/renew

Продлевает существующего агента ещё на duration_months. Только инфраструктура — новый чат-кредит не включается. Возвращает новый id заказа и свежий URL Stripe Checkout.

Запрос

{
  "duration_months": 1,
  "external_id": "your-side-id",
  "success_url": "https://your.app/thanks?id={ORDER_ID}",
  "cancel_url":  "https://your.app/account"
}

Доход

Прочитать доход

GET /revenue

Итоги плюс последние 200 событий ledger.

Query parameters

include_paid
Необязательно, по умолчанию true. Установите false, чтобы видеть только ещё не выплаченные события.

Ответ

{
  "currency": "usd",
  "gross_cents": 12000,
  "partner_cut_cents": 2000,
  "mintbot_cut_cents": 10000,
  "unpaid_cents": 800,
  "events": [
    {
      "id": 7,
      "order_id": 42,
      "kind": "order_paid",
      "gross_cents": 1200,
      "partner_cut_cents": 200,
      "mintbot_cut_cents": 1000,
      "currency": "usd",
      "created_at": "2026-05-16 09:58:00",
      "payout_id": null,
      "payout_at": null
    }
  ]
}

Профиль партнёра

Получить профиль

GET /partner

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

Ответ

{
  "id": 12,
  "email": "you@kliendifirma.com",
  "pricing_currency": "usd",
  "balance_unpaid_cents": 800,
  "webhook_url": "https://your.app/mintbot-webhook",
  "api_key_prefix": "mo_live_a12b"
}

Webhooks

Когда с заказом что-то происходит, мы отправляем POST с подписанным JSON-событием на настроенный вами URL webhook.

Типы событий

Event Когда срабатывает
order.created Создана сессия Stripe Checkout, ожидается оплата.
order.paid Stripe подтвердил оплату. Событие дохода записано.
order.cancelled Заказ истёк по времени или был явно отменён.
agent.provisioning_started Для этого заказа запущен deploy pipeline.
agent.ready Deploy завершился успешно. Payload содержит panel_url и expires_at.
agent.failed Deploy pipeline завершился ошибкой. Проверьте поле error, чтобы увидеть сломавшийся шаг.
agent.expired TTL агента истёк. Партнёр может продлить через POST /orders/{id}/renew.

Доставка и повторы

  • До 7 попыток по экспоненциальному расписанию: 0s, 30s, 2m, 10m, 1h, 6h, 24h.
  • После последней попытки доставка помечается как exhausted и повторы прекращаются.
  • Ответьте статусом 2xx в течение 10 секунд, чтобы подтвердить получение.

Заголовки запроса

Content-Type: application/json
User-Agent: mintbot-webhook/1.0
X-Mintbot-Signature: t=<unix_ts>,v1=<hex_hmac_sha256>
X-Mintbot-Event-Id: evt_42_order.paid_1747371234567
X-Mintbot-Event-Type: order.paid

Пример payload — order.paid

{
  "id": 42,
  "tier": "s1",
  "duration_months": 1,
  "credit_usd": 10,
  "amount_cents": 1200,
  "currency": "usd",
  "status": "completed",
  "external_id": "your-side-id",
  "paid_at": "2026-05-16 10:02:14"
}

Проверка подписи

Подпись — это HMAC-SHA256(secret, "{timestamp}.{raw_body}"). Всегда проверяйте сырое тело запроса — повторная сериализация разобранного JSON сломает сравнение.

import hmac, hashlib, time

def verify(secret: str, body: bytes, header: str, tolerance: int = 300) -> bool:
    try:
        ts_part, v1_part = header.split(",", 1)
        ts  = int(ts_part.split("=", 1)[1])
        sig = v1_part.split("=", 1)[1]
    except Exception:
        return False
    if abs(int(time.time()) - ts) > tolerance:
        return False
    expected = hmac.new(
        secret.encode(),
        f"{ts}.".encode() + body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, sig)
const crypto = require("crypto");

function verify(secret, rawBody, header, toleranceSec = 300) {
  const [tsPart, v1Part] = header.split(",");
  const ts  = Number(tsPart.split("=")[1]);
  const sig = v1Part.split("=")[1];
  if (Math.abs(Date.now() / 1000 - ts) > toleranceSec) return false;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${ts}.`)
    .update(rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected, "hex"),
    Buffer.from(sig, "hex"),
  );
}

Идемпотентные получатели

Используйте X-Mintbot-Event-Id как ключ дедупликации — повторы используют тот же id, поэтому строковый INSERT … ON CONFLICT DO NOTHING по этому столбцу делает ваш обработчик безопасным.


Ошибки

Каждый ответ с ошибкой содержит стабильный code, по которому можно ветвиться программно. Поле message — человекочитаемая подсказка, оно может меняться между релизами. request_id повторяет заголовок ответа X-Request-Id — указывайте его в обращениях в поддержку.

{
  "error": {
    "code": "invalid_api_key",
    "message": "API key is unknown or revoked.",
    "request_id": "f0c2d6c4-…"
  }
}
Code Значение
unauthenticated Отсутствует или некорректно сформирован заголовок Authorization.
invalid_api_key API key неизвестен или был выведен из обращения ротацией.
rate_limited Превышен лимит на партнёра или на IP — см. Retry-After.
missing_idempotency_key Запрос POST без Idempotency-Key.
idempotency_key_mismatch Тот же ключ повторно использован с другим телом запроса.
validation_error Тело запроса не прошло проверку схемы.
not_found Ресурс не существует или не принадлежит вашему партнёру.
payment_gateway_error Stripe отклонил создание сессии Checkout.

Rate limits

  • 120 requests / 60 s rolling window на партнёра. Burst и steady-state используют один и тот же bucket.
  • 60 requests / 60 s — отдельный bucket на IP для неаутентифицированных запросов и запросов с неудачной аутентификацией, чтобы brute-force bearer не расходовал партнёрскую квоту.
  • Лишние запросы возвращают 429 rate_limited с заголовком Retry-After (секунды ожидания).

Нужна помощь?

Эта документация написана для партнёров, которые реально пользуются API. Если чего-то не хватает, что-то непонятно или устарело, скажите об этом своему агенту mintbot — он передаст обратную связь, и мы обновим страницу.