Features
Credits and billing
What a message costs, why the cost varies by category, and what happens when the balance runs out.
How the cost is computed
Two axes decide the price of a single send:
- Category,
MARKETING,UTILITY,AUTHENTICATIONorSERVICE. Taken from the approved template's category. An e-commerce event carries its category in the catalog; a template the platform does not recognise is looked up in your template records; a non-template message inside an open window is aSERVICEconversation. - Country, derived from the recipient's number by longest-matching dialling code. Meta prices per country, so the same template costs different amounts to different destinations.
Those two give Meta's cost. Your plan's markup is applied to it, and the resulting sell price is divided by the credit value and rounded up. That is why the credits figure moves with the category and the destination rather than being fixed.
The shipped default rate card
Credits per message under the platform defaults
| Field | Required | Type | Description |
|---|---|---|---|
| AUTHENTICATION | No | category | otp_verification, password_reset, order_verification.Example: 1 to India / 6 elsewhere |
| UTILITY | No | category | Order, shipping, payment and return events, plus the welcome message. Example: 1 to India / 6 elsewhere |
| MARKETING | No | category | cart_recovery, review_request, back_in_stock, and most campaigns.Example: 8 to India / 18 elsewhere |
| SERVICE | No | category | Free-form replies inside an open 24-hour window, Inbox replies, auto-replies, bot steps. Example: 0, free |
Those are defaults; a plan can change every one of them. Read the response headers rather than assuming a price.
The headers on a successful send
Set on every successful send
| Field | Required | Type | Description |
|---|---|---|---|
| X-Message-Category | No | string | MARKETING, UTILITY, AUTHENTICATION or SERVICE, the category this message was priced under. |
| X-Message-Price | No | decimal string | Sell price for this message. |
| X-Credits-Charged | No | integer | Credits deducted. Credit-billed plans only. |
| X-Credits-Remaining | No | integer | Balance after the deduction. Credit-billed plans only. |
| X-Wallet-Balance | No | decimal string | Balance after the deduction. Wallet-billed plans only. |
X-Message-Category: UTILITY
X-Message-Price: 0.0014
X-Credits-Charged: 1
X-Credits-Remaining: 4821A credit-billed plan gets the two credit headers; a wallet-billed plan gets X-Wallet-Balance instead. Both always get the category and the price.
When the balance runs out
The send is refused with 402. Nothing was sent and nothing was spent.
{
"error": "Insufficient message credits, a marketing message costs 8 credits. Ask your administrator to add more.",
"reason": "INSUFFICIENT_CREDITS",
"category": "MARKETING",
"creditsRequired": 8,
"price": "0.0099",
"currency": "USD",
"balance": 3
}{
"error": "Insufficient wallet balance. Top up to continue sending.",
"reason": "INSUFFICIENT_BALANCE",
"category": "MARKETING",
"creditsRequired": 8,
"price": "0.0099",
"currency": "USD",
"balance": "0.0031"
}balance changes type with the plan, an integer credit count on credit plans, a decimal string on wallet plans. creditsRequired is present on both.
Failed sends are refunded automatically
The charge is a reservation, taken before the message is handed to Meta. It settles only if the response is a success. The reservation is reversed when:
- the response status is 400 or above, a validation error, a closed window, a missing template, or a Meta rejection; or
- the client disconnects before the response is written.
So a failed send costs nothing and you never have to reconcile one. The ledger keeps both movements, a DEDUCT followed by a matching REFUND, so the balance history stays reconstructable rather than the deduction quietly disappearing.
Campaigns do the same thing per contact: a contact whose send fails has its charge refunded before the run moves on.
Limits are not the same as credits
Sending limits are checked before money moves, so a send refused by a cap is never charged for. A limit refusal is a 429, not a 402, and it carries limit, usage and limits in the body, which is how you tell a plan cap apart from a per-key rate limit. A rate limit is worth retrying; a plan cap is not. See Errors and retries.
The Billing screen
Check the meters before you check the balance
What you've used shows one meter per plan limit, with any add-on capacity noted beside it. Meters turn amber at 70% and red at 90%. Sending stops at a limit rather than billing you more, so the meter is the early warning.Add capacity, or change tier
Add capacity sells one more of a single thing without moving up a tier. Change plan switches tier outright. Both can be billed monthly or yearly using the toggle.Top up the wallet if your plan bills from one
The wallet is a prepaid balance charged per use, shown with a top-up button and a set of preset amounts. GST is added on top of the amount you choose, the pay button states the total charge, and only the pre-tax figure lands in the balance.

- Payments
- Handled by Razorpay. Prices exclude GST unless stated.
- Free tier
- Enough to try things out, not to run a shop, a plan without an active subscription falls back to platform defaults rather than keeping a lapsed plan's markup.
- Checking the balance
GET /v1/credits, see the API reference.
A worked example
A store sends 3,000 order confirmations and 3,000 shipping updates a month to Indian numbers, plus one 5,000-contact marketing campaign, and answers about 800 customer replies in the Inbox.
- 6,000 utility messages at 1 credit = 6,000
- 5,000 marketing messages at 8 credits = 40,000
- 800 service replies at 0 credits = 0
The one campaign costs nearly seven times the entire month of transactional traffic. That is the whole reason cost is per category, and the reason a campaign is worth thinking about before launching.
