Billing API
Plans, prices, checkout links, the budget cap and the subscription. 11 ops: get_pricing, get_account, get_billing, create_checkout_link, subscribe, cancel_subscription, resume_subscription, set_budget_cap, claim_checkout, create_billing_portal_link, get_billing_link.
Plans, prices, checkout links, the budget cap and the subscription.
Get pricing · POST /api/v1/get_pricing · scope billing:read or GET …?input=
The plans (Free, Starter, Growth, Scale, Enterprise): price {monthly, yearly} in USD, included messages and AI replies a month, limits (live numbers, WhatsApp accounts, members, agents, history days; null is unlimited), features, overage rates and the default budget cap, a checkout_url per paid plan, and how_to_buy. Meta's own message fees are billed by Meta to the customer's WABA at cost and are not part of these prices. The same document as GET /api/v1/pricing; needs no credential (REST, the catalog MCP server at /api/mcp/catalog, `wabi pricing`). Call before recommending or buying a plan.
curl -X POST https://getwabi.dev/api/v1/get_pricing \ -H "Authorization: Bearer wabi_…"npx @meterapp/wabi get_pricing{
"type": "object",
"properties": {}
}get_account
readGet account · POST /api/v1/get_account · scope billing:read or GET …?input=
Who this credential acts for and what it may use: the organization, your role in it (viewer, member, admin, owner) and whether you are a person, an OAuth client or an API key (acting_as, with the key's scopes), the plan in force (status, interval, renewal or end date, budget cap), usage this period against every limit (messages, AI replies, live numbers, members, agents) with what remains and the overage so far, and next_tier: what the next plan adds, its price and a checkout_url. Same data as GET /api/v1/account and `wabi account`. Call before a bulk send or when a human asks about plan or usage.
curl -X POST https://getwabi.dev/api/v1/get_account \ -H "Authorization: Bearer wabi_…"npx @meterapp/wabi get_account{
"type": "object",
"properties": {}
}get_billing
readGet billing · POST /api/v1/get_billing · scope billing:read or GET …?input=
This organization's plan, subscription status, renewal or end date, budget cap, whether a card is saved (so subscribe can charge it), and usage this period against the plan (messages, AI replies, numbers, members, agents, overage so far). Pass refresh: true right after a human finished a checkout to pull the latest state from Stripe.
curl -X POST https://getwabi.dev/api/v1/get_billing \ -H "Authorization: Bearer wabi_…"npx @meterapp/wabi get_billing{
"type": "object",
"properties": {
"refresh": {
"default": false,
"description": "Re-read the subscription from Stripe instead of the stored copy.",
"type": "boolean"
}
}
}Create checkout link · POST /api/v1/create_checkout_link · scope billing:write
A Stripe Checkout URL where a human pays for a plan; hand it to them (or open it in their browser). Works before signup: with no credential (REST, the catalog MCP server, `wabi upgrade` before login) the human pays first, then signs in with the same email and the plan attaches to their organization. Nothing is charged and the plan does not change until they complete it; then get_billing {refresh: true} shows the new plan. The link expires after 24 hours. If the organization already has a subscription, the URL is a Stripe page where they confirm the plan change instead. Returns {url, kind: checkout | plan_change, plan, interval, amount_cents, expires_at, session_id}. Never collect card details yourself.
curl -X POST https://getwabi.dev/api/v1/create_checkout_link \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"plan":"starter"}'npx @meterapp/wabi create_checkout_link --json '{"plan":"starter"}'{
"type": "object",
"properties": {
"plan": {
"type": "string",
"enum": [
"starter",
"growth",
"scale"
],
"description": "starter, growth or scale. get_pricing lists what each includes. Enterprise is sold by email."
},
"interval": {
"default": "month",
"description": "month, or year (two months free: 10x the monthly price).",
"type": "string",
"enum": [
"month",
"year"
]
},
"ref": {
"description": "Optional attribution slug for the link (e.g. agent-cursor). Defaults to the surface: agent-mcp, agent-cli or agent-api.",
"type": "string",
"pattern": "^[a-z0-9][a-z0-9_-]{0,39}$"
}
},
"required": [
"plan"
]
}Subscribe · POST /api/v1/subscribe · scope billing:write
Start or change this organization's paid plan in one call, charging the card already saved for the organization. Only after a human approved this plan and price: confirm must be true. Without a saved card (or if the card needs the human, e.g. 3-D Secure) nothing is charged and it returns status checkout_required with a checkout_url for a human to finish. A plan change is prorated and invoiced immediately. Returns {status: subscribed | changed | unchanged | checkout_required, billing}.
curl -X POST https://getwabi.dev/api/v1/subscribe \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"plan":"starter","confirm":false}'npx @meterapp/wabi subscribe --json '{"plan":"starter","confirm":false}'{
"type": "object",
"properties": {
"plan": {
"type": "string",
"enum": [
"starter",
"growth",
"scale"
],
"description": "starter, growth or scale. get_pricing lists what each includes. Enterprise is sold by email."
},
"interval": {
"default": "month",
"description": "month, or year (two months free: 10x the monthly price).",
"type": "string",
"enum": [
"month",
"year"
]
},
"confirm": {
"type": "boolean",
"const": true,
"description": "Must be true: a human has seen the plan and price and asked you to buy it. Never set it on your own initiative."
}
},
"required": [
"plan",
"confirm"
]
}Cancel subscription · POST /api/v1/cancel_subscription · scope billing:write
Cancel the paid plan at the end of the current period (no refund; the plan stays until then, then the organization is on Free). Only when a human asked: confirm must be true. resume_subscription undoes it before the period ends.
curl -X POST https://getwabi.dev/api/v1/cancel_subscription \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"confirm":false}'npx @meterapp/wabi cancel_subscription --json '{"confirm":false}'{
"type": "object",
"properties": {
"confirm": {
"type": "boolean",
"const": true,
"description": "Must be true: a human has seen the plan and price and asked you to buy it. Never set it on your own initiative."
}
},
"required": [
"confirm"
]
}Resume subscription · POST /api/v1/resume_subscription · scope billing:write
Undo a cancellation that has not taken effect yet, so the plan renews as before. Nothing is charged until the normal renewal date.
curl -X POST https://getwabi.dev/api/v1/resume_subscription \ -H "Authorization: Bearer wabi_…"npx @meterapp/wabi resume_subscription{
"type": "object",
"properties": {}
}Set budget cap · POST /api/v1/set_budget_cap · scope billing:write
Set this organization's monthly overage budget cap in US dollars: usage past the plan's allowance is billed up to this amount, then non-critical sends (campaigns, bulk sends) stop until the next period. null restores the default (2x the plan price). Free has no overage and ignores it. Owners and admins; a human decision, so only when asked.
curl -X POST https://getwabi.dev/api/v1/set_budget_cap \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"amount":0}'npx @meterapp/wabi set_budget_cap --json '{"amount":0}'{
"type": "object",
"properties": {
"amount": {
"anyOf": [
{
"type": "number",
"minimum": 0,
"maximum": 1000000
},
{
"type": "null"
}
],
"description": "Dollars per billing period, or null for the default."
}
},
"required": [
"amount"
]
}Claim checkout · POST /api/v1/claim_checkout · scope billing:write
Attach a checkout paid before signup (create_checkout_link without a credential) to this organization, by its session_id (cs_…). Usually automatic: returning from Stripe, or signing up with the email used at checkout, claims it. Call it when a human paid first and the plan has not appeared. Returns {outcome: claimed | already_yours, billing}.
curl -X POST https://getwabi.dev/api/v1/claim_checkout \ -H "Authorization: Bearer wabi_…" \ -H "Content-Type: application/json" \ -d '{"session_id":"session_id"}'npx @meterapp/wabi claim_checkout --json '{"session_id":"session_id"}'{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"pattern": "^cs_(live|test)_[A-Za-z0-9]+$",
"description": "The Checkout Session id create_checkout_link returned (cs_live_… or cs_test_…)."
}
},
"required": [
"session_id"
]
}Create billing portal link · POST /api/v1/create_billing_portal_link · scope billing:write
A private Stripe page where a human downloads invoices, updates the card or billing details, or cancels. The link is for a human and expires after a few minutes of inactivity; never open it on your own.
curl -X POST https://getwabi.dev/api/v1/create_billing_portal_link \ -H "Authorization: Bearer wabi_…"npx @meterapp/wabi create_billing_portal_link{
"type": "object",
"properties": {}
}Get billing link · POST /api/v1/get_billing_link · scope billing:write
The Stripe customer portal for a human: invoices, card and billing details, plan change and cancellation. The same as create_billing_portal_link, under the name every Meter product uses (POST /api/v1/billing/portal, `wabi billing portal`). The link expires after a few minutes of inactivity; never open it on your own.
curl -X POST https://getwabi.dev/api/v1/get_billing_link \ -H "Authorization: Bearer wabi_…"npx @meterapp/wabi get_billing_link{
"type": "object",
"properties": {}
}