I-skip tungo sa nilalaman

Brand Partner API

Isang maliit at predictable na REST API para gumawa ng mintbot orders, mag-poll ng status nila, at tumanggap ng lifecycle events. JSON in, JSON out. Bearer-token auth. Idempotent writes. Signed webhooks.

API access dashboard Tumalon sa webhooks


Mabilisang overview

Base URL https://mint.mintbot.ai/api/v1
Auth Authorization: Bearer mo_live_…
Idempotency Idempotency-Key: <uuid> sa bawat POST maliban sa POST /dns/records
Content type application/json
Rate limit 120 req / 60 s bawat partner
Webhooks Signed gamit ang HMAC-SHA256, nire-retry hanggang 7 beses

Authentication

Bawat request ay nagpapadala ng partner API key sa Authorization header. I-generate o i-rotate ang key sa dashboard.

Authorization: Bearer mo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

Walang grace window ang rotation

Kapag ni-rotate ang key, atomically nare-revoke ang nauna. Planuhin na palitan ang value sa iyong config bago i-click ang Rotate.

Idempotency

Bawat POST ay nangangailangan ng Idempotency-Key header — maliban sa POST /dns/records, na natural na idempotent sa provider layer at tumatanggap ng retries kahit wala nito. Gumagana ang anumang UUID para sa bawat distinct request.

  • Kina-cache namin ang response sa loob ng 24 oras. Ang retry gamit ang parehong key ay ire-replay ang orihinal na response na may Idempotent-Replay: true.
  • Ang paggamit ulit ng parehong key na may ibang body ay magbabalik ng 409 idempotency_key_mismatch.

Orders

Gumawa ng order

POST /orders

Gumagawa ng order at nagbabalik ng Stripe Checkout URL. Kapag na-confirm ang payment, ipo-provision ng mintbot ang agent at awtomatikong ire-record ang partner-cut revenue event.

Request

{
  "tier": "mo_month",
  "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
Isa sa mo_test (Test 24h), mo_month (Standard), mo_month_plus (Performance).
duration_months
Bilang ng calendar months ng buhay ng server. Dapat isa sa 1, 3, o 12. Ang mo_test ay laging iisang 24-oras na run, anuman ang ipadala mo.
credit_usd
Opsyonal, default 0. Isa sa 0, 5, 10, 20, 50. Pre-funded na chat credit (USD) na kasama sa order. Idinadagdag ito sa order total at napupunta sa mintbot — hindi ito bahagi ng margin mo.
language
Opsyonal. Nakakaapekto sa Stripe Checkout locale at welcome-email language.
external_id
Opsyonal. Ibabalik sa bawat webhook at order response — gamitin ito para i-thread ang mintbot orders sa rows sa sarili mong system.
success_url · cancel_url
Stripe Checkout return URLs. Ang {ORDER_ID} ay pinapalitan server-side.
webhook_url
Opsyonal. Per-order override ng partner-level webhook URL.
product_name
Opsyonal. Ang line-item label na nakikita ng customer sa Stripe Checkout (hanggang 250 character). Default ay generated na label na TIER · N months.
price_usd
Opsyonal. Price override sa USD para sa buong order. Hindi ito puwedeng bumaba sa wholesale floor mo para sa tier at duration na iyon — kung hindi, 400 validation_error.

Response — 201 Created

{
  "id": 42,
  "tier": "mo_month",
  "duration_months": 1,
  "credit_usd": 10,
  "amount_cents": 1200,
  "currency": "usd",
  "status": "pending",
  "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,
  "price_cents": 1200,
  "partner_cut_cents": 200
}

Kung nasa custom pricing mode ka at hindi mo pa napepresyuhan ang tier na ito, may kasama ring "pricing_fallback": true ang response.

Halimbawa

curl -X POST https://mint.mintbot.ai/api/v1/orders \
  -H "Authorization: Bearer $MINTBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "tier": "mo_month",
    "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": "mo_month",
        "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"]

Kunin ang order

GET /orders/{id}

Kinukuha ang isang order gamit ang mintbot id nito. Nagbabalik ng parehong shape gaya ng POST /orders.

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

I-list ang orders

GET /orders

Cursor-paginated list, pinakabago muna.

Query parameters

status
Opsyonal. I-filter ayon sa pending, completed, o expired. Nananatiling completed ang bayad na order sa buong deploy nito — sundan ang progreso ng deploy sa pamamagitan ng agent.* webhooks.
cursor
Opsyonal. Ipasa ang next_cursor mula sa nakaraang page para magpatuloy.
limit
Opsyonal. Laki ng page, default 50, max 200.

Response

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

Ang next_cursor ay null kapag wala nang mga page.


I-renew ang order

POST /orders/{id}/renew

Pinapahaba ang existing agent para sa panibagong duration_months. Infra-only — walang bagong chat credit na naka-bundle. Nagbabalik ng bagong order id at fresh na 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"
}

Subscriptions

Gumawa ng subscription

POST /subscriptions

Nagbubukas ng Stripe Checkout sa subscription mode: buwan-buwang nagbabayad ang customer para sa monthly package at awtomatikong nire-renew ang subscription. Tulad ng POST /orders, kailangan nito ng Idempotency-Key at partner account na live. Ang buwanang presyo ay mula sa pricing mo para sa tier na iyon.

Request

{
  "tier": "mo_month",
  "language": "en",
  "success_url": "https://your.app/thanks",
  "cancel_url":  "https://your.app/cart",
  "customer_email": "customer@example.com",
  "external_id": "your-side-id"
}

Opsyonal ang customer_email, agent_id (isang existing agent mo kung saan itatali ang subscription), external_id, at product_name.

Response — 201 Created ay may id, tier, currency, amount_cents, partner_cut_cents, status, checkout_url, current_period_end, cancel_at_period_end, agent_id, language, customer_email, external_id, at created_at.

Kunin ang subscription

GET /subscriptions/{id}

Nagbabalik ng parehong shape gaya ng POST /subscriptions.


Revenue

Basahin ang revenue

GET /revenue

Totals plus ang pinakabagong 200 ledger events.

Query parameters

include_paid
Opsyonal, default true. I-set sa false para makita lang ang events na hindi pa paid out.

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

Partner profile

Kunin ang profile

GET /partner

Ibabalik ang iyong partner profile kasama ang unpaid balance — useful para ipakita ang earnings sa loob ng sarili mong admin UI nang hindi mo kailangang i-store ang mga ito mismo.

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

Settings

Kunin ang settings

GET /settings

Nagbabalik ng buo mong non-secret partner configuration sa isang payload — napiling modes, apex domain, DNS provider, bot provider, Agent customization repo, subdomain pattern (may rendered preview label), per-tier pricing, API key metadata, webhook metadata, at ang parehong readiness / per-section status na nagpapatakbo sa MintOffice dashboard banner.

Dinisenyo para sa integration agents na kailangang malaman kung paano naka-set up ang partner nang hindi nag-scrape ng dashboard o nagtatanong sa operator. Ang typical caller ay coding agent na nag-i-install ng white-label setup mo sa fresh server — mababasa nito ang endpoint na ito, mag-branch sa readiness.status, at masasabi sa operator kung aling sections pa ang nangangailangan ng attention.

Walang secret na ibinabalik kailanman

Anumang ibinigay ng partner bilang credential — Telegram bot token, Zone.ee API key, webhook signing secret, mismong plaintext ng API key — lumalabas lamang bilang *_set boolean. Dagdag pa rito, ine-expose ng webhook secret ang parehong 8-char display prefix na ipinapakita na sa dashboard, kaya mako-confirm ng caller aling secret ang naka-configure nang hindi kailanman nakikita ang value.

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": "own",
    "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": "text",
    "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": {
      "mo_test":       { "price_cents": 100,  "partner_cut_cents": 0,   "updated_at": "2026-05-13 09:05:00" },
      "mo_month":      { "price_cents": 1200, "partner_cut_cents": 200, "updated_at": "2026-05-13 09:05:00" },
      "mo_month_plus": { "price_cents": 1800, "partner_cut_cents": 300, "updated_at": "2026-05-13 09:05:00" }
    },
    "allowed_credit_options": [10, 20, 50]
  },

  "readiness": {
    "ready": true,
    "missing_fields": [],
    "dns_blocker": null,
    "status": "live"
  },

  "section_status": {
    "domain":   { "status": "ok",      "mode": "own",     "issue": null, "dns_blocker": null },
    "bot":      { "status": "ok",      "mode": "own",     "issue": null, "dns_blocker": null },
    "template": { "status": "default", "mode": "default", "issue": null, "dns_blocker": null },
    "api":      { "status": "ok",      "mode": "active",  "issue": null, "dns_blocker": null },
    "all_ready": true
  }
}

Sanggunian ng mga field

status
Lifecycle ng partner. Isa sa onboarding, live, suspended. Nire-reject ng Brand Partner API ang writes maliban kung live ang status; ang mintbot team lang ang naglilipat sa iyo sa live.
domain.mode
own (dala mo ang sarili mong apex domain) o mintbot (nagpo-provide ang mintbot ng *.mintbot.ai subdomain). Kapag mintbot, sadyang walang laman ang DNS-provider fields kahit ano pa ang dating inilagay ng partner.
domain.subdomain_label_preview
Ang rendered label na matatanggap ng unang customer agent (agent1, 1, 001, …) base sa kasalukuyang subdomain_prefix, subdomain_numbering, at subdomain_pad_width. Gamitin ito para sa preview na "ito ang makikita ng customers mo" nang hindi kailangang i-reimplement ang numbering rules.
bot.mode
own (Telegram bot na provided ng partner), mintbot (gamit ang bot ng mintbot habang testing), o none (panel lang, walang Telegram).
template.mode
default (walang Agent customization repo — tumatakbo ang agent sa plain unbranded na base) o own (ang Agent customization repo ng partner sa repo_url). Kapag own, kino-clone ng sariling VPS ng agent ang repo na iyon pagkatapos ng standard deploy at pinapatakbo ang install.sh / update.sh nito para i-apply ang persona, panel theme, at anumang extra tooling sa ibabaw ng base — hindi kailanman pinapatakbo ng central ang repo mismo. Ituro ang repo_url sa GitHub HTTPS Agent customization repo mo kapag gusto mo ng custom branding.
api.webhook_secret_prefix
Unang 8 character ng webhook signing secret, naroroon lang kapag may naka-configure na secret. Hinahayaan nitong matukoy ng caller kung aling secret ang ginagamit nang hindi nakikita ang buong value. Ipinapakita rin ng dashboard ang parehong prefix.
pricing.allowed_credit_options
Ang mga credit_usd bundle na ino-offer mo sa customers mo (pinipili sa Settings → Pricing).
readiness.missing_fields
Listahan ng dashboard field names na kailangan pa bago mag-Go Live. Walang laman kapag ready ay true. Sapat ang stability nito para mag-drive ng "ano pa ang kulang" UI sa sarili mong admin.
readiness.dns_blocker
Isang human-readable na dahilan kapag pumalya ang DNS provider check (hal. partner has no zone.ee username configured). Kung hindi, null.
section_status.*
Katulad ng per-section status pills sa dashboard. Ang status ay ok, warn, o default (default ng mintbot ang ginagamit); pinapangalanan ng issue ang field na humaharang sa section na iyon (hal. client_apex_domain, telegram_bot_token, dns_blocker), o null.

Halimbawa

curl https://mint.mintbot.ai/api/v1/settings \
  -H "Authorization: Bearer $MINTBOT_API_KEY"
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"])

Catalog

Ang listahan ng mga package na puwedeng ibenta sa storefront mo — ang mga Brand Partner package (mo_test / mo_month / mo_month_plus) kasama ang iyong resolved pricing, sa pricing currency mo. Dito mo i-render ang plan cards mo sa halip na i-hard-code ang tier slugs at mga presyo: kusang nawawala ang mga retired package, at ang pagbabago ng presyo o currency na ginawa mo sa dashboard ay umaabot sa storefront mo sa loob ng cache window nito — walang kailangang redeploy.

Ito ang endpoint na pumipigil sa storefront na mag-advertise ng mga lumang package. Tinatawag ito ng reference portal sa bawat render ng landing / /buy / /extend (naka-cache, may sticky fallback).

Sa iyo pa rin ang display copy

Ang display_name / description / featured ay ang canonical na package metadata ng mintbot. Kung gusto mong palitan ang pangalan ng package o isulat muli ang blurb nito para sa brand mo, i-override ito sa sarili mong storefront (may PLAN_OVERRIDES map ang reference portal para mismo rito) — ang catalog ang source of truth kung aling mga package ang umiiral at magkano ang mga ito, hindi ang marketing copy mo.

Kunin ang catalog

GET /api/v1/catalog

Walang parameters. Bearer auth lang — walang activation gate, kaya puwedeng i-render ng storefront ang catalog kahit hindi pa naka-live ang partner account mo.

Response

{
  "currency": "usd",
  "packages": [
    {
      "tier": "mo_test",
      "display_name": "Test 24h",
      "description": "2 vCPU · 4 GB RAM · 40 GB SSD · 24-hour evaluation. EU.",
      "featured": false,
      "default_credit_usd": 5,
      "durations": [
        { "months": 1, "label": "24 hours", "price_cents": 0 }
      ],
      "subscription": { "available": false, "price_cents": null }
    },
    {
      "tier": "mo_month",
      "display_name": "Standard",
      "description": "2 vCPU · 4 GB RAM · 40 GB SSD, monthly. EU.",
      "featured": false,
      "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 }
    }
  ],
  "credit_options": [
    { "usd": 5,  "price_cents": 500 },
    { "usd": 10, "price_cents": 1000 }
  ]
}
Field Kahulugan
currency Ang pricing currency mo. Lahat ng price_cents sa ibaba ay nasa currency na ito.
packages[] Isang entry bawat public package, sunod sa offer/display order.
tier Ang slug na ipinapasa mo sa POST /orders / POST /subscriptions.
display_name / description / featured Canonical na display copy (i-override sa storefront mo kung gusto mo).
default_credit_usd Ang hint ng LLM credit na kasama sa package (informational lang).
durations[] Ang mga setup duration na puwedeng bilhin para sa package na ito. Ang months ay ang value na ipinapadala mo bilang duration_months; ang price_cents ang sisingilin ng order. Nag-a-advertise ang monthly packages ng 1 / 3 / 12 buwan; isang 24-oras na duration lang ang sa mo_test.
subscription Ang available ay true para sa packages na puwedeng bilhin bilang monthly auto-renew sa POST /subscriptions; ang price_cents ang buwanang halaga. Hindi kailanman puwedeng i-subscribe ang mo_test.
credit_options[] Bawat credit_usd bundle na may presyo sa currency mo (usd = halaga ng credit, price_cents = idinadagdag nito sa order total). Kung aling bundles ang ino-offer mo ay nasa pricing.allowed_credit_options ng GET /settings.

Tugma ang mga presyo sa sisingilin sa iyo

Kinukuwenta ang bawat price_cents gamit ang parehong pricing resolver na ginagamit ng order endpoint, kaya laging katumbas ng presyo sa card ang huling Stripe Checkout total para sa (tier, duration_months) na iyon.

Halimbawa

curl -s https://mint.mintbot.ai/api/v1/catalog \
  -H "Authorization: Bearer $MINTBOT_API_KEY" | 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

Madalas kailangan ng brand-partner integrations na mag-provision ng DNS records sa apex domain ng partner — itinuturo ang @, www, o per-customer subdomains sa tamang server. Nag-e-expose ang MintOffice ng vendor-blind proxy para magawa mo ito nang hindi kailanman hinahawakan ang API key ng upstream provider sa sarili mong infrastructure. Ang credentials na sinave mo noong onboarding (ngayon: zone.ee; naka-roadmap ang cloudflare at route53 sa likod ng parehong shape) ay nananatiling encrypted sa MintOffice; pumapasok ang call mo gamit ang Bearer mo_live_… at kami ang gumagawa ng upstream call para sa iyo.

Ang scope ay sariling configured apex ng partner (domain.client_apex_domain mula sa GET /settings). Hindi mo maaaring galawin ang record sa zone na hindi mo pagmamay-ari.

Kung Manual ang DNS provider mo, walang binabago ang proxy: no-op ang writes at walang laman ang lists na ibinabalik.

Sa ngayon, sinusuportahan ng proxy ang operations na ginagamit mismo ng deploy pipeline — A-records (upsert / list / delete by id). Susunod sa parehong shape ang CNAME / TXT / MX support kapag pinalawak na ng underlying provider abstraction ang mga iyon.

Hindi kailangan ang Idempotency-Key dito

Hindi tulad ng order-creation endpoints, natural na idempotent ang DNS upserts sa provider layer (ang muling pag-run gamit ang parehong (subdomain, ip) ay no-op at nililinis ang stale duplicates sa bawat call). Hindi mo kailangang ipadala ang Idempotency-Key header — palaging nagko-converge ang retries sa iisang A-record per FQDN.

Mag-upsert ng A-record

POST /dns/records

Idempotently ituro ang <subdomain>.<your-apex> sa isang IPv4 address. Ipasa ang "" (o "@") para sa mismong apex.

Request

{
  "subdomain": "www",
  "ip": "203.0.113.10"
}

Tinatanggap ng subdomain ang:

  • "" o "@" — ang mismong apex (example.com).
  • Isang DNS label — "www", "api" — para sa <label>.<apex>.
  • Dotted sub-labels — "api.eu" — para sa nested subdomains (api.eu.example.com).

Ang ip ay dapat dotted IPv4 address. Bawat label ay [a-z0-9_-], 1–63 chars, walang leading/trailing -.

Response — 200

{
  "apex": "example.com",
  "provider": "zone_ee",
  "fqdn": "www.example.com",
  "records": [
    { "id": "9182734", "name": "www.example.com", "destination": "203.0.113.10" }
  ]
}

Palaging ipinapakita ng post-write records list ang kasalukuyang view ng upstream provider sa FQDN pagkatapos ng duplicate sweep — kaya ang successful response na may eksaktong isang record ang happy-path signal na wala nang stale na natitira.

I-list ang records

GET /dns/records

Ibinabalik ang bawat A-record sa configured apex. Idagdag ang ?name=<label-or-fqdn> para mag-filter sa isang FQDN — maaaring bare label ("www"), dotted subdomain ("api.eu"), o full FQDN ("www.example.com") ang value.

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

Mag-delete ng record

DELETE /dns/records/{record_id}

Ang record_id ay vendor identifier na ibinalik ng GET /dns/records (nag-i-issue ang zone.ee ng integer ids, na sini-stringify sa API boundary). Ang pag-delete ng record na wala na ay itinuturing na success — idempotent ang endpoint sa client side.

Response — 200

{ "deleted": true, "id": "9182734" }

Mga error

HTTP error.code Sanhi
401 unauthenticated / invalid_api_key Kulang / mali ang Bearer token.
422 validation_error Mali ang subdomain o non-IPv4 destination.
422 dns_not_configured Walang client_apex_domain ang partner o nawawala ang credentials ng configured provider. Ayusin sa Settings → Domain.
422 dns_provider_unsupported Hindi pa naka-wire ang DNS provider ng partner sa MintOffice proxy (hal. cloudflare placeholder). Lumipat muna sa zone_ee.
502 dns_provider_error Nagbalik ang upstream provider ng 4xx/5xx, o pumalya ang transport. Dala ng error message ang upstream status at maikling secret-redacted excerpt ng upstream body. Safe na mag-retry.

Halimbawa

# Point apex + www at your server's IP.
curl https://mint.mintbot.ai/api/v1/dns/records \
  -H "Authorization: Bearer $MINTBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"subdomain": "",    "ip": "203.0.113.10"}'

curl https://mint.mintbot.ai/api/v1/dns/records \
  -H "Authorization: Bearer $MINTBOT_API_KEY" \
  -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 $MINTBOT_API_KEY"
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

Kapag may nangyari sa isang order, nag-POST kami ng signed JSON event sa configured webhook URL mo.

Opsyonal ang webhooks

Ang Webhook URL at Webhook signing secret sa Settings → API access ay ganap na opsyonal — iwanang blank ang mga ito habang onboarding kung wala ka pang receiver. Saka lang may ipapadalang deliveries kapag naka-set na ang pareho — kung may URL pero walang signing secret, walang event na ipapadala. Gumagana nang maayos ang dashboard at ang natitirang API kahit walang webhooks; puwede mong i-poll ang GET /api/v1/orders/{id} para i-track ang lifecycle sa halip. Idagdag ang URL (at i-generate ang secret) kapag ready ka na, walang kailangang re-activation.

Mga uri ng event

Event Kailan ito nagti-trigger
order.created Nagawa ang Stripe Checkout session, naghihintay ng payment.
order.paid Kinumpirma ng Stripe ang payment. Na-record ang revenue event.
order.cancelled Nag-time out ang order o tahasang kinansela.
agent.provisioning_started Nagsimula ang deploy pipeline para sa order na ito.
agent.ready Successful ang deploy. May panel_url at expires_at ang payload.
agent.failed Nag-error ang deploy pipeline. Pinapangalanan ng error_step ang step na pumalya; maikling buod ang error_message.
agent.expired Lumipas na ang Agent TTL. Maaaring mag-renew ang partner gamit ang POST /orders/{id}/renew.
agent.resumed Na-renew ang dating expired na agent sa loob ng grace window nito at live na ulit. Recovery counterpart ng agent.expired.
subscription.created · subscription.activated · subscription.updated · subscription.cancelled Lifecycle ng subscription mula sa POST /subscriptions.
partner.activated · partner.deactivated In-activate ng mintbot team ang account mo o inalis ito sa live (sinasabi ng suspended sa payload kung na-suspend ito o ibinalik sa onboarding).

Delivery at retries

  • Hanggang 7 attempts sa exponential schedule: 0s, 30s, 2m, 10m, 1h, 6h, 24h.
  • Pagkatapos ng huling attempt, mamamarkahan ang delivery bilang exhausted at hihinto sa retrying.
  • Mag-respond ng 2xx status sa loob ng 10 seconds para i-acknowledge.

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

Sample payload — order.paid

{
  "id": 42,
  "tier": "mo_month",
  "duration_months": 1,
  "currency": "usd",
  "amount_cents": 1200,
  "status": "completed",
  "external_id": "your-side-id",
  "created_at": "2026-05-16 09:58:00",
  "paid_at": "2026-05-16 10:02:14",
  "expires_at": null
}

Pag-verify ng signature

Ang signature ay HMAC-SHA256(secret, "{timestamp}.{raw_body}"). Palaging i-verify ang raw request body — masisira ang comparison kapag ni-re-serialise mo ang parsed 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"),
  );
}

Idempotent receivers

Gamitin ang X-Mintbot-Event-Id bilang dedup key mo — ginagamit muli ng retries ang parehong id, kaya pinapanatiling safe ng row-level INSERT … ON CONFLICT DO NOTHING sa column na iyon ang handler mo.

Reference portal

May runnable end-to-end reference sa mintbot-ai/partner-portal-example — FastAPI + SQLite, Dockerised, may kasamang example brand na tinatawag na ExampleAI na ifo-fork at papalitan mo. Ang architectural picture — kung paano magkakasya ang storefront, itong API, deploy worker, at agent template — ay nasa MintOffice — Technical. Ini-implement ng portal ang:

  • landing / plan-picker / thank-you / cancel pages,
  • POST /buy → POST /api/v1/orders → Stripe redirect,
  • POST /webhooks/mintoffice kasama ang HMAC verifier na nire-reference sa itaas,
  • isang HTTP-Basic-auth /admin event browser para makita mo ang deliveries.

I-fork ito, i-set ang PARTNER_BRAND, MINTOFFICE_API_KEY, at MINTOFFICE_WEBHOOK_SECRET sa .env, patakbuhin ang docker compose up, at ituro ang webhook URL ng partner row mo sa https://<your-host>/webhooks/mintoffice. Tingnan ang MintOffice → Reference portal para sa buong walkthrough.


Mga error

Bawat error response ay may stable na code na puwede mong i-branch programmatically. Ang message field ay human-readable hint at maaaring magbago sa pagitan ng releases. Ine-echo ng request_id ang X-Request-Id response header — isama ito sa support tickets.

{
  "error": {
    "code": "invalid_api_key",
    "message": "API key is unknown or revoked.",
    "request_id": "f0c2d6c4-…"
  }
}
Code Kahulugan
unauthenticated Kulang o malformed ang Authorization header.
invalid_api_key Hindi kilala ang API key o na-rotate out na.
rate_limited Lumampas sa per-partner o per-IP rate limit — tingnan ang Retry-After.
missing_idempotency_key POST request na walang Idempotency-Key.
idempotency_key_mismatch Ginamit muli ang parehong key na may ibang request body.
validation_error Pumalya ang request body sa schema validation.
not_found Wala ang resource o hindi ito kabilang sa partner mo.
partner_not_live HTTP 403 — isang write (POST /orders, /orders/{id}/renew, /subscriptions) habang hindi live ang account mo. May status ang body, at para sa onboarding accounts, missing_fields + dns_blocker.
conflict HTTP 409 — pinoproseso pa ang request na may parehong Idempotency-Key. Subukang muli pagkatapos ng Retry-After.
unpriced_tier HTTP 409 — walang presyong masisingil para sa tier.
internal_error Hindi inaasahang error sa server side. Isama ang request_id kapag kumontak sa support.
payment_gateway_error Ni-reject ng Stripe ang Checkout session creation.
dns_not_configured POST /dns/records laban sa partner na walang apex / walang DNS credentials. Ayusin sa Settings → Domain.
dns_provider_unsupported Hindi pa naka-wire ang dns_provider value ng partner sa MintOffice proxy.
dns_provider_error Nagbalik ng error ang upstream DNS provider — may redacted excerpt ang message.
quota_exceeded HTTP 429, sa DEV environment (mint.mintbot.dev) lang — walang per-partner cap sa LIVE. Naubos na ng partner ang lahat ng deploy slot (10 bilang default, 20 pagkatapos ng Brand Partner setup fee). Kontakin ang mintbot support para itaas ang cap. Ibinabalik ng POST /orders at POST /orders/{id}/renew. May deploys_used + deploy_quota ang body.

Rate limits

  • 120 requests / 60 s rolling window, per partner. Magkapareho ang bucket ng burst at steady-state.
  • 60 requests / 60 s hiwalay na per-IP bucket para sa unauthenticated at failed-auth requests — pinipigilan nitong ubusin ng bearer brute-force ang partner quota.
  • Nagbabalik ang excess requests ng 429 rate_limited kasama ang Retry-After header (seconds bago mag-back off).

Kailangan ng tulong?

Isinulat ang docs na ito para sa partners na aktwal na gumagamit ng API. Kung may kulang, nakakalito, o stale, banggitin ito sa mintbot agent mo — ipapasa nila ang feedback at ia-update namin ang page.