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,3of12zijn. 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_failedofexpired. cursor- Optioneel. Geef
next_cursorvan 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 opfalseom 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"
}
Instellingen¶
Instellingen ophalen¶
GET /settings
Retourneert je volledige niet-geheime partnerconfiguratie in één payload — gekozen modes, apex-domein, DNS-provider, bot-provider, customization repo, subdomeinpatroon (met een weergegeven preview-label), prijzen per tier, API-key-metadata, webhook-metadata en dezelfde readiness / per-sectie status die de banner van het MintOffice-dashboard aanstuurt.
Ontworpen voor integratie-agents die moeten ontdekken hoe de partner is opgezet zonder het dashboard te scrapen of de operator te bevragen. Een typische caller is een coding-agent die jouw white-label-setup op een verse server installeert — die kan deze endpoint lezen, vertakken op readiness.status en de operator precies vertellen welke secties nog aandacht nodig hebben.
Er wordt nooit een secret geretourneerd
Alles wat de partner als credential heeft opgegeven — Telegram-bottoken, Zone.ee API-key, webhook-ondertekeningssecret, de API-key in platte tekst zelf — verschijnt alleen als een *_set-boolean. Het webhook-secret toont daarnaast hetzelfde 8-tekens displayprefix dat al in het dashboard wordt getoond, zodat een caller kan bevestigen welk secret is geconfigureerd zonder ooit de waarde te zien.
Response
{
"id": 12,
"email": "you@kliendifirma.com",
"status": "live",
"created_at": "2026-05-12 14:22:01",
"onboarded_at": "2026-05-12 14:48:33",
"activated_at": "2026-05-13 09:10:05",
"last_login_at": "2026-05-20 00:51:18",
"preferred_language": "en",
"pricing_currency": "usd",
"balance_unpaid_cents": 800,
"domain": {
"mode": "byo",
"client_apex_domain": "agent99.cc",
"dns_provider": "zone.ee",
"zone_ee_username": "you@kliendifirma.com",
"zone_ee_api_key_set": true,
"subdomain_prefix": "agent",
"subdomain_numbering": "natural",
"subdomain_pad_width": 3,
"subdomain_label_preview": "agent1"
},
"bot": {
"mode": "own",
"provider": "telegram",
"telegram_bot_username": "agent99cc_bot",
"telegram_bot_token_set": true
},
"template": {
"mode": "default",
"repo_url": null
},
"api": {
"key_prefix": "mo_live_a12b",
"key_created_at": "2026-05-13 09:11:42",
"webhook_url": "https://your.app/mintbot-webhook",
"webhook_secret_set": true,
"webhook_secret_prefix": "ab12cd34"
},
"pricing": {
"mode": "default",
"currency": "usd",
"tiers": {
"trial": { "price_cents": 0, "partner_cut_cents": 0, "updated_at": null },
"s1": { "price_cents": 1200, "partner_cut_cents": 200, "updated_at": "2026-05-13 09:05:00" },
"s2": { "price_cents": 2400, "partner_cut_cents": 400, "updated_at": "2026-05-13 09:05:00" },
"s4": { "price_cents": 4800, "partner_cut_cents": 800, "updated_at": "2026-05-13 09:05:00" }
}
},
"readiness": {
"ready": true,
"missing_fields": [],
"dns_blocker": null,
"status": "live"
},
"section_status": {
"domain": { "status": "ready", "mode": "byo", "issue": null, "dns_blocker": null },
"bot": { "status": "ready", "mode": "own", "issue": null, "dns_blocker": null },
"template": { "status": "ready", "mode": "default", "issue": null, "dns_blocker": null },
"api": { "status": "ready", "mode": "live", "issue": null, "dns_blocker": null },
"all_ready": true
}
}
Veldreferentie¶
status- Partner-lifecycle. Een van
onboarding,live,paused. De Brand Partner API weigert writes zolangonboarding. domain.modebyo(je brengt je eigen apex-domein mee) ofhosted(mintbot levert een*.mintbot.ai-subdomein). Bijhostedzijn de DNS-providervelden bewust leeg, ongeacht wat de partner eerder heeft ingevuld.domain.subdomain_label_preview- Het weergegeven label dat de eerste klant-agent zou krijgen (
agent1,1,001, …) gegeven de huidigesubdomain_prefix,subdomain_numberingensubdomain_pad_width. Gebruik het voor een "dit is wat je klanten zullen zien"-preview zonder de nummeringsregels opnieuw te implementeren. bot.modeown(door de partner geleverde Telegram-bot),borrow(mintbots bot gebruiken tijdens het testen) ofweb(alleen paneel, geen Telegram).template.modedefault(geen agent customization repo — de agent draait op de kale, merkloze basis) ofcustom(de agent customization repo van de partner oprepo_url). Bijcustomkloont de eigen VPS van de agent die repo na de standaarddeploy en draait diensinstall.sh/update.shom jouw persona, paneelthema en eventuele extra tooling bovenop de basis toe te passen — central voert de repo zelf nooit uit. Wijsrepo_urlnaar je GitHub-HTTPS agent customization repo wanneer je eigen branding wilt.api.webhook_secret_prefix- De eerste 8 tekens van het webhook-ondertekeningssecret, alleen aanwezig wanneer een secret is geconfigureerd. Laat een caller onderscheiden welk secret actief is zonder de volledige waarde te zien. Het dashboard toont hetzelfde prefix.
readiness.missing_fields- Lijst met dashboard-veldnamen die nog vereist zijn vóór Go Live. Leeg wanneer
readytrueis. Stabiel genoeg om een "wat ontbreekt er nog"-UI in je eigen admin aan te sturen. readiness.dns_blocker- Ingesteld op een korte redenstring wanneer DNS-verificatie mislukt (bijv.
nameservers_not_pointing,glue_record_missing). Andersnull. section_status.*.issue- Per sectie een menselijk leesbare hint wanneer die sectie Go Live blokkeert. Spiegelt de per-sectie statuspills van het dashboard.
Voorbeeld
curl https://mint.mintbot.ai/api/v1/settings \
-H "Authorization: Bearer ***
import os, requests
r = requests.get(
"https://mint.mintbot.ai/api/v1/settings",
headers={"Authorization": f"Bearer {os.environ['MINTBOT_API_KEY']}"},
timeout=10,
)
r.raise_for_status()
settings = r.json()
if not settings["readiness"]["ready"]:
print("Still missing:", settings["readiness"]["missing_fields"])
Catalogus¶
De verkoopbare pakkettenlijst voor je storefront — de publieke pakketten
(trial / starter / pro) samengevoegd met jouw opgeloste prijzen, in
jouw prijsvaluta. Render je plankaarten hieruit in plaats van
tier-slugs en prijzen hard te coderen: ingetrokken pakketten verdwijnen
vanzelf, en een prijs- of valutawijziging die je in het dashboard maakt, bereikt
jouw storefront binnen het cachevenster — geen redeploy.
Dit is de endpoint die voorkomt dat een storefront de pakketten van gisteren
adverteert. Het referentieportaal roept hem aan bij elke landing- / /buy- /
/extend-render (gecachet, met een sticky fallback).
Displaytekst blijft van jou
display_name / description / featured zijn de canonieke mintbot-
pakketmetadata. Wil je een pakket hernoemen of de omschrijving herschrijven
voor je merk, override het dan in je eigen storefront (het referentie-
portaal levert een PLAN_OVERRIDES-map precies hiervoor) — de catalogus is
de bron van waarheid voor welke pakketten bestaan en wat ze kosten, niet
voor je marketingtekst.
Catalogus ophalen¶
GET /api/v1/catalog
Geen parameters. Alleen Bearer-auth — er is geen activatiepoort, zodat een storefront de catalogus kan renderen voordat je partneraccount live is gezet.
Response
{
"currency": "usd",
"packages": [
{
"tier": "trial",
"display_name": "Trial",
"description": "One day to kick the tires.",
"featured": false,
"default_credit_usd": 5,
"durations": [
{ "months": 1, "label": "24 hours", "price_cents": 0 }
],
"subscription": { "available": false, "price_cents": null }
},
{
"tier": "starter",
"display_name": "Starter",
"description": "A month of assistant time.",
"featured": true,
"default_credit_usd": 10,
"durations": [
{ "months": 1, "label": "1 month", "price_cents": 1500 },
{ "months": 3, "label": "3 months", "price_cents": 4500 },
{ "months": 12, "label": "12 months", "price_cents": 18000 }
],
"subscription": { "available": true, "price_cents": 1500 }
}
]
}
| Veld | Betekenis |
|---|---|
currency |
Je prijsvaluta. Elke price_cents hieronder is hierin uitgedrukt. |
packages[] |
Eén entry per publiek pakket, in aanbod-/weergavevolgorde. |
tier |
De slug die je doorgeeft aan POST /orders / POST /subscriptions. |
display_name / description / featured |
Canonieke displaytekst (override in je storefront als je wilt). |
default_credit_usd |
De gebundelde LLM-tegoedhint van het pakket (informatief). |
durations[] |
De setup-looptijden waarvoor dit pakket gekocht kan worden. months is de waarde die je als duration_months verstuurt; price_cents is wat de order in rekening brengt. Maandpakketten adverteren 1 / 3 / 12 maanden; trial adverteert één enkele looptijd van 24 uur. |
subscription |
available is true voor pakketten die als maandelijkse auto-renew via POST /subscriptions gekocht kunnen worden; price_cents is het maandbedrag. trial is nooit abonnementsgeschikt. |
Prijzen komen overeen met wat je in rekening wordt gebracht
Elke price_cents wordt berekend met dezelfde prijsresolver die de
order-endpoint gebruikt, dus een kaartprijs is altijd gelijk aan het uiteindelijke Stripe
Checkout-totaal voor die (tier, duration_months).
Voorbeeld¶
curl -s https://mint.mintbot.ai/api/v1/catalog \
-H "Authorization: Bearer *** | jq
import os, requests
r = requests.get(
"https://mint.mintbot.ai/api/v1/catalog",
headers={"Authorization": f"Bearer {os.environ['MINTBOT_API_KEY']}"},
timeout=10,
)
r.raise_for_status()
catalog = r.json()
for pkg in catalog["packages"]:
month1 = next(d for d in pkg["durations"] if d["months"] == 1)
print(pkg["display_name"], month1["price_cents"], catalog["currency"])
DNS-records¶
Brand-partner-integraties moeten vaak DNS-records provisionen op het apex-domein van de partner — @, www of subdomeinen per klant naar de juiste server laten wijzen. MintOffice biedt een vendor-blinde proxy zodat je dit kunt doen zonder ooit de API-key van de upstream-provider in je eigen infrastructuur te verwerken. De credentials die je tijdens onboarding hebt opgeslagen (vandaag: zone.ee; cloudflare en route53 staan op de roadmap achter dezelfde vorm) blijven versleuteld in MintOffice; jouw call komt binnen met Bearer mo_live_… en wij doen de upstream-call namens jou.
Scope is de eigen geconfigureerde apex van de partner (domain.client_apex_domain uit GET /settings). Je kunt geen record aanraken op een zone die je niet bezit.
Vandaag ondersteunt de proxy de operaties die de deploy pipeline zelf gebruikt — A-records (upsert / list / delete op id). Ondersteuning voor CNAME / TXT / MX volgt in dezelfde vorm zodra de onderliggende provider-abstractie ze ondersteunt.
Idempotency-Key hier niet vereist
Anders dan bij order-creatie-endpoints zijn DNS-upserts van nature idempotent op de providerlaag (opnieuw uitvoeren met dezelfde (subdomain, ip) is een no-op en verouderde duplicaten worden bij elke call opgeruimd). Je hoeft de Idempotency-Key header niet te sturen — retries convergeren altijd naar één A-record per FQDN.
Een A-record upserten¶
POST /dns/records
Laat <subdomain>.<your-apex> idempotent naar een IPv4-adres wijzen. Geef "" (of "@") door voor de apex zelf.
Request
{
"subdomain": "www",
"ip": "203.0.113.10"
}
subdomain accepteert:
""of"@"— de apex zelf (example.com).- Eén DNS-label —
"www","api"— voor<label>.<apex>. - Gepunte sublabels —
"api.eu"— voor geneste subdomeinen (api.eu.example.com).
ip moet een gepunt IPv4-adres zijn. Elk label is [a-z0-9_-], 1–63 tekens, geen leidende/afsluitende -.
Response — 200
{
"apex": "example.com",
"provider": "zone_ee",
"fqdn": "www.example.com",
"records": [
{ "id": "9182734", "name": "www.example.com", "destination": "203.0.113.10" }
]
}
De records-lijst na de write weerspiegelt altijd de actuele kijk van de upstream-provider op de FQDN na een duplicatensweep — een geslaagde response met precies één record is dus het happy-path-signaal dat er niets verouderds overblijft.
Records weergeven¶
GET /dns/records
Retourneert elk A-record op de geconfigureerde apex. Voeg ?name=<label-or-fqdn> toe om te filteren op één FQDN — de waarde mag een kaal label ("www"), een gepunt subdomein ("api.eu") of de volledige FQDN ("www.example.com") zijn.
Response — 200
{
"apex": "example.com",
"provider": "zone_ee",
"items": [
{ "id": "9182734", "name": "example.com", "destination": "203.0.113.10" },
{ "id": "9182735", "name": "www.example.com", "destination": "203.0.113.10" }
]
}
Een record verwijderen¶
DELETE /dns/records/{record_id}
record_id is de vendor-identifier die door GET /dns/records wordt geretourneerd (zone.ee geeft integer-id's uit, gestringificeerd op de API-grens). Het verwijderen van een record dat niet meer bestaat wordt als een succes behandeld — de endpoint is idempotent aan de clientzijde.
Response — 200
{ "deleted": true, "id": "9182734" }
Fouten¶
| HTTP | error.code |
Oorzaak |
|---|---|---|
| 401 | unauthenticated / invalid_api_key |
Ontbrekend / fout Bearer-token. |
| 422 | validation_error |
Fout subdomein of niet-IPv4-bestemming. |
| 422 | dns_not_configured |
Partner heeft geen client_apex_domain of de credentials van de geconfigureerde provider ontbreken. Fix in Settings → Domain. |
| 422 | dns_provider_unsupported |
De DNS-provider van de partner is nog niet aangesloten op de MintOffice-proxy (bijv. cloudflare-placeholder). Schakel voorlopig over naar zone_ee. |
| 502 | dns_provider_error |
Upstream-provider gaf een 4xx/5xx terug, of het transport mislukte. De fout-message bevat de upstream-status en een korte, secret-geredigeerde uittreksel van de upstream-body. Veilig om opnieuw te proberen. |
Voorbeeld¶
# Point apex + www at your server's IP.
curl https://mint.mintbot.ai/api/v1/dns/records \
-H "Authorization: Bearer *** \
-H "Content-Type: application/json" \
-d '{"subdomain": "", "ip": "203.0.113.10"}'
curl https://mint.mintbot.ai/api/v1/dns/records \
-H "Authorization: Bearer *** \
-H "Content-Type: application/json" \
-d '{"subdomain": "www", "ip": "203.0.113.10"}'
# Verify.
curl "https://mint.mintbot.ai/api/v1/dns/records" \
-H "Authorization: Bearer ***
import os, requests
URL = "https://mint.mintbot.ai/api/v1/dns/records"
H = {"Authorization": f"Bearer {os.environ['MINTBOT_API_KEY']}"}
for sub in ("", "www"):
r = requests.post(URL, headers=H, json={"subdomain": sub, "ip": "203.0.113.10"})
r.raise_for_status()
print(sub or "@", r.json()["records"])
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
exhausteden stopt het opnieuw proberen. - Reageer binnen 10 seconden met een
2xxstatus 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_limitedmet eenRetry-Afterheader (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.