Skip to content

Billing and credits

Download .md

Every send and call is paid from the workspace’s credit balance, and every price, preview and report is in credits; no answer carries a money amount. A send’s own cost is billed_credits on its status (SMS and calls; WhatsApp sends answer null), a campaign preview shows cost_credits before you start it, and GET /v1/campaigns/{id}/usage says what a campaign has cost.

Read the balance with GET /v1/balance (any key of the workspace):

Terminal window
curl https://api.omniocto.com/v1/balance \
-H "Authorization: Bearer $OMNI_OCTO_API_KEY"
{ "object": "balance",
"credits": 1000, "paid_credits": 800, "bonus_credits": 200,
"bonus_expires_at": "2026-11-01T00:00:00.000Z",
"pending_credits": 12.5, "available_credits": 987.5,
"suspended": false, "suspended_reason": null,
"tier": 2, "has_payment_method": true, "auto_recharge_disabled": false,
"plan": { "id": "…", "name": "…", "renews_at": "2026-11-01T00:00:00.000Z" },
"updated_at": "2026-10-17T10:00:00.000Z" }
  • credits is what the workspace holds.
  • paid_credits is the part you bought or were granted; it never expires.
  • bonus_credits is the part included with this billing period; it expires at bonus_expires_at, and is used first. Both parts are null when we could not read them just now; otherwise they add up to credits (both are 0 when credits is 0 or below).
  • pending_credits is this period’s usage that is not yet taken off credits.
  • available_credits is credits minus pending_credits (never below 0): what you can still spend now.
  • updated_at is when the balance was last read from the billing system: at most about 5 minutes ago, so reading it more often than that does not make it fresher. Every field: Balance.
whatprice
SMS to or from a US or Canada number on one of our numbers2 credits per segment
MMS (picture or video) to a US or Canada number4 credits per message
MMS to another +1 region (Puerto Rico, Jamaica, …)11.5 credits per message
SMS to the UK / Germany / anywhere else5.7 / 11.5 / 8.6 credits per segment
any text on a number you bring from your own carrier account0.1 credits per segment or message (your carrier bills the rest)

A segment is up to 160 plain characters, or 70 when the text has an emoji or another character outside the GSM alphabet; a longer text is split into segments. A reply someone sends to one of our numbers costs the same as a text to them. A send’s own cost is billed_credits on its status.

Prices, previews and reports are always in credits; no response carries a money amount. A sender’s mode says whose carrier account it is on: "managed" (one of ours) or "byo" (a Twilio, Telnyx or Vonage account you brought, which also bills you separately).

Each WhatsApp message sent from your own WhatsApp Business account (the usual case) costs 0.1 credits. Meta bills its own charges to you directly; our credit figure does not include them, so a WhatsApp send’s billed_credits is null.

A call’s cost so far is billed_credits on GET /v1/calls/{id}; it can still grow for a few minutes after the call ends (speech and the call’s analysis are billed as they finish). Per-minute prices are on Settings → Billing in the dashboard.

A call placed from a number on your own carrier account (a Twilio account you brought, or your own SIP carrier) is not charged our phone-line minute, because your carrier bills you for that minute. It costs a platform fee of 0.1 credits per started minute instead, shown in your usage as “Calls on your own carrier: platform fee”. A call nobody answers costs no fee. The rest of the call (speech, the AI model, the call connection and recording) is billed the same as on one of our numbers, and its minutes still count toward the workspace’s daily call-minute limit.

GET /v1/campaigns/{id}/usage says what a campaign has cost so far, by category, with its calls’ minutes or its messages. A preview’s cost_credits is the estimate before you start.

limits.spend_cap_credits (SMS and AI-call campaigns) caps what a campaign may spend. When the next call would not fit, the campaign pauses with paused_reason spend_cap and its untouched recipients stay queued. Calls under way always finish, so a campaign can end a few calls above its cap; for a small cap, set a low limits.max_concurrent_calls too. Raising the cap is a person’s act: an API key can set one or lower one, but raising or removing it on a started campaign is 403 spend_cap_raise_needs_person. Every rule: Limits and retries.

A send the balance cannot cover is 402 insufficient_credits with short_credits, and nothing is sent. A workspace without a card, or whose subscription has lapsed, is 402 billing_not_eligible (what it means). Add a card or credits in the dashboard under Settings → Billing.

What the credits went on, for any window, with any key of the workspace:

routeanswers
GET /v1/usagethe total and the groups: by category (default), UTC day and/or label, up to two (group_by=day,category)
GET /v1/usage/eventsone row per charge, newest first, paged (limit, after)
GET /v1/usage/exportthe same rows as one CSV file
Terminal window
curl "https://api.omniocto.com/v1/usage?group_by=day,category&from=2026-10-01" \
-H "Authorization: Bearer $OMNI_OCTO_API_KEY"
{ "object": "usage_report",
"from": "2026-10-01T00:00:00.000000Z", "to": "2026-10-29T06:00:00.000000Z",
"cycle_start": "2026-10-01T00:00:00.000000Z", "cycle_end": "2026-11-01T00:00:00.000000Z",
"category": null, "group_by": ["day", "category"],
"total_credits": 1234.5, "events": 812,
"groups": [
{ "day": "2026-10-18", "category": "phone", "label": null,
"credits": 96, "units": null, "unit": null, "events": 40 } ] }
  • The window. from is inclusive and to exclusive, each an ISO 8601 date (midnight UTC) or instant, at most 400 days apart. Without them the window is the current billing cycle (cycle_start) to now: the usage pending_credits on /v1/balance counts. A workspace with no billing period counts the last 30 days.
  • The same rows on all three. /v1/usage echoes the from and to it read. Pass that pair to /v1/usage/events and /v1/usage/export and they answer the same charges: the export’s row count equals events. To page through a fixed set, always pass from and to; a default window is worked out again on every page. A charge is recorded a moment before it is committed, so for a complete set for your books pass a to a few minutes in the past.
  • Categories. phone (call minutes, attempts, voicemails), recording (call connection and recording), speech (speech-to-text, text-to-speech, realtime voice), ai (AI model tokens), messaging (SMS, MMS and chat channel messages), whatsapp, email, numbers (number rental) and other. Filter with category=. The same words as a campaign’s usage.
  • Labels and units. label says what was charged (SMS outbound (US), AI Tokens (input)); new labels appear as we bill new things. units and unit (message, minute, 1k_tokens, …) are filled only when you group by label: 3 messages and 3 minutes are not 6 of anything.
  • Totals. Each group’s credits is rounded to 4 decimals, so the groups add up to total_credits give or take that rounding. A day with no usage has no group. More than 5,000 groups is 400 too_many_groups: narrow the window or group by less.
  • One charge to its conversation. Each row of /v1/usage/events carries conversation_id (read it with GET /v1/conversations/{id}), agent_id and campaign_id.
  • The export holds at most 250,000 rows; over that it is refused before any byte (400 export_too_large), never cut short. One export runs at a time per workspace (429 export_in_progress, retry after Retry-After). If the connection is cut mid-file the body is incomplete: compare the row count to events.

The get_usage MCP tool answers GET /v1/usage. Every field: UsageReport.