Перейти до змісту

Brand Partner API

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

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


Коротко

Base URL https://mint.mintbot.ai/api/v1
Auth `Authorization: Bearer ***
Idempotency 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

Список із курсорною пагінацією, найновіші спочатку.

Параметри запиту

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 подій реєстру.

Параметри запиту

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 Для цього замовлення запущено pipeline розгортання.
agent.ready Розгортання успішне. Payload містить panel_url і expires_at.
agent.failed 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-ключ невідомий або був виведений з обігу ротацією.
rate_limited Перевищено ліміт запитів на партнера або IP — див. Retry-After.
missing_idempotency_key Запит POST без Idempotency-Key.
idempotency_key_mismatch Той самий ключ повторно використано з іншим тілом запиту.
validation_error Тіло запиту не пройшло валідацію схеми.
not_found Ресурс не існує або не належить вашому партнеру.
payment_gateway_error Stripe відхилив створення сесії Checkout.

Ліміти запитів

  • 120 запитів / 60 s ковзного вікна, на партнера. Burst і steady-state використовують один кошик.
  • 60 запитів / 60 s в окремому кошику на IP для неавтентифікованих запитів і запитів із невдалою автентифікацією — це не дає brute-force bearer-токена витрачати квоту партнера.
  • Надлишкові запити повертають 429 rate_limited із заголовком Retry-After (секунди очікування перед повтором).

Потрібна допомога?

Ця документація написана для партнерів, які справді користуються API. Якщо щось відсутнє, незрозуміле або застаріле, згадайте це своєму агенту mintbot — він передасть відгук, і ми оновимо сторінку.