Ga naar inhoud

Brand Partner API

Een kleine, voorspelbare REST API om mintbot-orders te maken, hun status op te vragen en lifecycle-events te ontvangen. JSON erin, JSON eruit. Bearer-token-authenticatie. Idempotente writes. Ondertekende webhooks.

Dashboard voor API-toegang Ga naar webhooks


In één oogopslag

Base URL https://mint.mintbot.ai/api/v1
Auth `Authorization: Bearer ***
Idempotency Idempotency-Key: <uuid> bij elke POST
Content type application/json
Rate limit 120 req / 60 s per partner
Webhooks Ondertekend met HMAC-SHA256, tot 7 keer opnieuw geprobeerd

Authenticatie

Elk request stuurt een partner-API-sleutel in de Authorization header. Genereer of roteer de sleutel in het dashboard.

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

Rotatie heeft geen respijtperiode

Het roteren van de sleutel trekt de vorige sleutel atomair in. Plan om de waarde in je config te vervangen voordat je op Rotate klikt.

Idempotency

Elke POST vereist een Idempotency-Key header. Elke UUID per afzonderlijk request werkt.

  • We cachen de response 24 uur. Een retry met dezelfde sleutel speelt de oorspronkelijke response opnieuw af met Idempotent-Replay: true.
  • Hergebruik van dezelfde sleutel met een andere body retourneert 409 idempotency_key_mismatch.

Orders

Order aanmaken

POST /orders

Maakt een order aan en retourneert een Stripe Checkout URL. Zodra betaling is bevestigd, provisiont mintbot de agent en wordt het revenue-event voor het partneraandeel automatisch vastgelegd.

Request

{
  "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
Een van trial, s1, s2, s4.
duration_months
Kalendermaanden serverlevensduur. Moet 1, 3 of 12 zijn.
credit_usd
Optioneel. Vooraf gefinancierd chattegoed dat met de order wordt gebundeld.
language
Optioneel. Beïnvloedt de locale van Stripe Checkout en de taal van de welkomstmail.
external_id
Optioneel. Wordt teruggestuurd op elke webhook en orderresponse — gebruik dit om mintbot-orders te koppelen aan rijen in je eigen systeem.
success_url · cancel_url
Retour-URL's voor Stripe Checkout. {ORDER_ID} wordt server-side vervangen.
webhook_url
Optioneel. Override per order van de webhook-URL op partnerniveau.

Response — 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
}

Voorbeeld

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"]

Order ophalen

GET /orders/{id}

Haalt één order op via zijn mintbot-id. Retourneert dezelfde vorm als POST /orders.

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

Orders weergeven

GET /orders

Cursor-gepagineerde lijst, nieuwste eerst.

Query parameters

status
Optioneel. Filter op awaiting_payment, completed, deployed, deploy_failed of expired.
cursor
Optioneel. Geef next_cursor van de vorige pagina door om verder te gaan.

Response

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

next_cursor is null wanneer er geen pagina's meer zijn.


Order verlengen

POST /orders/{id}/renew

Verlengt een bestaande agent met nog eens duration_months. Alleen infra — er wordt geen nieuw chattegoed gebundeld. Retourneert een nieuwe order-id en een nieuwe Stripe Checkout URL.

Request

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

Omzet

Omzet lezen

GET /revenue

Totalen plus de nieuwste 200 ledger-events.

Query parameters

include_paid
Optioneel, standaard true. Zet op false om alleen events te zien die nog niet zijn uitbetaald.

Response

{
  "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
    }
  ]
}

Partnerprofiel

Profiel ophalen

GET /partner

Geeft je partnerprofiel plus het onbetaalde saldo terug — handig om opbrengsten in je eigen admin UI te tonen zonder ze zelf op te slaan.

Response

{
  "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

Wanneer er iets met een order gebeurt, sturen we met POST een ondertekend JSON-event naar je geconfigureerde webhook-URL.

Eventtypen

Event Wanneer het wordt verzonden
order.created Stripe Checkout session aangemaakt, wacht op betaling.
order.paid Stripe heeft betaling bevestigd. Revenue-event vastgelegd.
order.cancelled Order is verlopen of expliciet geannuleerd.
agent.provisioning_started Deploy pipeline voor deze order gestart.
agent.ready Deploy geslaagd. Payload bevat panel_url en expires_at.
agent.failed Deploy pipeline gaf een fout. Controleer het veld error voor de stap die stukliep.
agent.expired Agent-TTL is verlopen. De partner kan verlengen via POST /orders/{id}/renew.

Bezorging en retries

  • Tot 7 pogingen volgens een exponentieel schema: 0s, 30s, 2m, 10m, 1h, 6h, 24h.
  • Na de laatste poging wordt de bezorging gemarkeerd als exhausted en stopt het opnieuw proberen.
  • Reageer binnen 10 seconden met een 2xx status om te bevestigen.

Request headers

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

Voorbeeldpayload — 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"
}

De handtekening verifiëren

De handtekening is HMAC-SHA256(secret, "{timestamp}.{raw_body}"). Verifieer altijd de raw request body — het opnieuw serialiseren van je geparste JSON breekt de vergelijking.

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"),
  );
}

Idempotente ontvangers

Gebruik X-Mintbot-Event-Id als je dedup-sleutel — retries hergebruiken dezelfde id, dus een rij-niveau INSERT … ON CONFLICT DO NOTHING op die kolom houdt je handler veilig.


Fouten

Elke foutresponse bevat een stabiele code waarop je programmatisch kunt vertakken. Het veld message is een menselijk leesbare hint en kan tussen releases veranderen. De request_id spiegelt de X-Request-Id response header — vermeld die in supporttickets.

{
  "error": {
    "code": "invalid_api_key",
    "message": "API key is unknown or revoked.",
    "request_id": "f0c2d6c4-…"
  }
}
Code Betekenis
unauthenticated Ontbrekende of verkeerd gevormde Authorization header.
invalid_api_key API key is onbekend of is weggeroteerd.
rate_limited Rate limit per partner of per IP overschreden — zie Retry-After.
missing_idempotency_key POST request zonder Idempotency-Key.
idempotency_key_mismatch Dezelfde sleutel opnieuw gebruikt met een andere request body.
validation_error Request body is niet door schemavalidatie gekomen.
not_found Resource bestaat niet of hoort niet bij je partner.
payment_gateway_error Stripe heeft het aanmaken van de Checkout session geweigerd.

Rate limits

  • 120 requests / 60 s rolling window, per partner. Burst en steady-state delen dezelfde bucket.
  • 60 requests / 60 s aparte bucket per IP voor niet-geauthenticeerde en mislukte-auth requests — voorkomt dat bearer brute-force de partnerquota opsoupeert.
  • Overtollige requests retourneren 429 rate_limited met een Retry-After header (seconden om te wachten).

Hulp nodig?

Deze documentatie is geschreven voor de partners die de API echt gebruiken. Als er iets ontbreekt, verwarrend of verouderd is, meld het dan aan je mintbot-agent — die stuurt de feedback door en wij werken de pagina bij.