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 — він передасть відгук, і ми оновимо сторінку.