Skip to content

Check your balance

Sending WhatsApp messages uses credits. How many credits a message uses depends on its category (marketing, utility, authentication or service). GET /balance tells you how many credits you have left and how many you used this month.

Any API key can call it: it needs only the read scope.

Terminal window
curl https://api.sanadwa.com/v1/balance \
-H "Authorization: Bearer $SANADWA_API_KEY"
{
"success": true,
"data": {
"billing_type": "prepaid",
"available_credits": 1450,
"paid_credits_remaining": 1200,
"free_credits_remaining": 250,
"unlimited": false,
"unlimited_until": null,
"usage_this_month": {
"period_start": "2026-11-01",
"credits_used": 830,
"marketing": 700,
"utility": 100,
"authentication": 30,
"service": 0
},
"as_of": "2026-11-11T08:00:00.000Z"
}
}
Field Meaning
billing_type prepaid: you buy credits in advance. postpaid: your usage is invoiced.
available_credits Credits you can spend now: paid plus free credits, minus credits held for messages that are being sent right now. null on a postpaid account.
paid_credits_remaining Credits you bought and have not used yet. null on a postpaid account.
free_credits_remaining Free credits left this month.
unlimited true while a subscription covers your sending. Messages then use no credits.
unlimited_until When that subscription period ends. null when unlimited is false.
usage_this_month Credits used since the first day of this month (UTC): the total in credits_used, and the part for each message category. period_start is that first day.
as_of When the balance was computed.

On a prepaid account, sending stops when available_credits is not enough:

  • A single message answers 402 PREPAID_CREDIT_CAP_REACHED.
  • Creating a campaign answers 402 insufficient_credits, and nothing is created.
  • A campaign that is already sending pauses with pause_reason insufficient_credits. See When credits run out. If the balance cannot be checked at that moment, it pauses with balance_check_failed instead.

Call GET /balance on a schedule, for example once an hour, and alert your team when available_credits falls below a level you choose. Skip the check when unlimited is true or billing_type is postpaid.

const LOW_CREDITS = 500; // choose your own level
async function checkCredits() {
const res = await fetch("https://api.sanadwa.com/v1/balance", {
headers: { Authorization: `Bearer ${process.env.SANADWA_API_KEY}` },
});
if (!res.ok) throw new Error(`GET /balance failed with HTTP ${res.status}`);
const { data } = await res.json();
if (data.billing_type === "postpaid" || data.unlimited) return;
if (data.available_credits < LOW_CREDITS) {
await notifyTeam(`Only ${data.available_credits} SanadWA credits left. Buy credits in the console.`);
}
}

You do not need to check the balance before each send or each campaign. The API checks it itself and refuses the request with 402 if your credits are not enough; nothing is sent then.

Code HTTP What to do
balance_lookup_failed 500 The balance could not be read. Retry after a few seconds. The API never reports a balance it could not read.

The usual authentication and rate-limit errors also apply; see Errors.