Skip to content

Billing & meters

Everything billable rates through one append-only usage_events stream onto one invoice. The meter registry is exactly nine meters, and no other meter names exist, and no outcome is ever a meter (outcomes are proof, never price):

Meter What it counts
telephony_minutes Connected voice minutes on platform telephony
stt_audio_seconds Speech-to-text audio processed
tts_characters Text-to-speech characters synthesized
llm_prompt_tokens LLM prompt tokens
llm_cached_prompt_tokens Cached prompt tokens
llm_completion_tokens LLM completion tokens
gpu_seconds GPU inference time
sms_segments Schema-reserved message segments; campaign SMS is unavailable
lookup_requests Compliance bureau lookups

Dial attempts are deliberately not a meter: per-attempt charges are rated from contact-attempt rows at invoicing time. Read your usage at GET /v1/usage/summary?period=2026-07 and GET /v1/usage/events; invoices at GET /v1/invoices; your plan at GET /v1/subscription.

BYO minutes are your carrier’s line, not ours

Section titled “BYO minutes are your carrier’s line, not ours”

Production telephony always runs on your own Twilio subaccount, so your carrier bills your minutes directly, so telephony_minutes is never metered on a BYO account. Your Vocapable invoice is the platform fee plus the non-telephony meters, and it additionally shows the telephony line you are not paying us. Platform telephony_minutes bill only paid platform test calls to your verified numbers. LLM tokens are bundled on the internal serving path and metered as a marked-up pass-through only when your agent’s route bursts to external providers.

The compliance floor is never a line item: AI disclosure, internal-DNC suppression, and the kill switches apply on every plan at no charge. On a configured live phone call, an opt-out phrase durably records the contact’s suppression before the call closes; browser and simulated test calls have no contact to suppress. Bureau scrub stages (lookup_requests) are a pass-through at small markup, and a tenant with a signed upstream-scrubbing attestation waives those stages and the pass-through with them, recorded per attempt so the invoice and the evidence export agree on what ran.

Set a spend cap with PUT /v1/billing/budget (billing:write) and read it back with GET /v1/billing/budget. The platform enforces it at launch and per dial batch, so there is no side door:

  • spend_cap_exceeded means the period’s cap is spent. The detail names the amount, the cap, the period start, and where the cap came from. Running campaigns are unaffected.
  • spend_state_unknown means the ledger holds chargeable usage on a meter your plan carries no rate for, so period-to-date spend cannot be established. Unknown spend state does not launch: price the meter or clear the cap.

The usage.threshold webhook event fires at 50%, 80%, and 100% of an included quantity or the spend cap, so wire it to your alerting rather than polling the summary.

GET /v1/billing/budget
curl https://api.vocapable.com/v1/billing/budget \
-H "Authorization: Bearer vcp_test_..."
{
"currency": "USD",
"balance_minor": 4900,
"spend_cap_minor": 250000,
"spend_cap_period": "month",
"low_balance_threshold_minor": 25000,
"period_spend_minor": 18240,
"unpriced_meters": []
}
PUT /v1/billing/budget
curl -X PUT https://api.vocapable.com/v1/billing/budget \
-H "Authorization: Bearer vcp_test_..." \
-H "Content-Type: application/json" \
-d '{
"spend_cap_minor": 500000,
"spend_cap_period": "month",
"low_balance_threshold_minor": 50000
}'

GET needs billing:read; PUT needs billing:write. spend_cap_period is day or month; any field sent as null clears that setting. unpriced_meters is what spend_state_unknown is about: while it is non-empty, period-to-date spend cannot be established and launches refuse.

Neither budget route emits RateLimit-* headers today. Honor 429 and Retry-After rather than keying your back-off on the headers alone.

POST /v1/subscription starts an eligible tenant’s production subscription. It takes the workload_class you declared and a term, creates the subscription, and redeems the sandbox credit against it; it does not promote the workspace to live:

POST /v1/subscription
curl -X POST https://api.vocapable.com/v1/subscription \
-H "Authorization: Bearer vcp_test_..." \
-H "Content-Type: application/json" \
-d '{"workload_class": "sales", "term": "three_year"}'

The response names the plan, the term, the base price, the session counts, the period, and sandbox_credit_redeemed_minor. Watch sandbox_credit_unconfirmed: when it is present, the subscription exists and the credit redemption did not confirm, so the amount it names is still owed to you and support will apply it - the subscription is not rolled back for it.

workload_class is one of engage, workforce, sales - the class you declared during onboarding, which the screening floor validated. term is mtm or three_year; the term moves the AI-minute rate, never the base fee. A three_year order requires the current 3-Year Commitment Addendum to be accepted first (POST /v1/agreements/accept) - without it the purchase answers agreements_required, naming the outstanding document, and nothing is charged.

extra_sessions is optional (default 0): the quantity of the published extra-concurrent-session add-on to start with, an integer ≥ 0 - never a price, which the catalog owns. On a deployment where the add-on is not yet configured to bill, a non-zero quantity answers extra_sessions_not_purchasable and nothing is created.

The endpoint needs billing:write. It does not accept Idempotency-Key: the server commits one tenant-unique provisioning operation before it calls Stripe. If a provider outcome is unknown, it answers subscription_provisioning_pending and will not submit another order. Wait for the signed Stripe subscription webhook, then refresh GET /v1/subscription; do not change the plan and click again. Once the local mirror exists, another attempt answers subscription_exists.

GET /v1/subscription reports extra_sessions (the purchased add-on quantity) and total_sessions (plan.concurrency_limit + extra_sessions - the one entitlement number session admission enforces), and plan.term (mtm or three_year; null on operator-authored plans that predate the vocabulary).

Change the purchased quantity with PUT /v1/subscription/extra-sessions (billing:write). The body carries the absolute target, never a delta - setting 3 twice leaves you with 3 - so an ambiguous outcome cannot double a fee and retrying the same number is always safe:

PUT /v1/subscription/extra-sessions
curl -X PUT https://api.vocapable.com/v1/subscription/extra-sessions \
-H "Authorization: Bearer vcp_test_..." \
-H "Content-Type: application/json" \
-d '{"extra_sessions": 3}'

A definite success answers the full refreshed Subscription DTO. The refusals:

  • subscription_not_found (404) - no production subscription exists yet.
  • subscription_inactive (409) - the subscription is not in an active state; nothing changed.
  • subscription_unmanaged (409) - the subscription carries no Stripe reference (dev-seeded or externally provisioned), so there is no subscription item to change.
  • extra_sessions_not_purchasable (409) - the add-on has no configured price in this deployment.
  • extra_sessions_update_failed (502) - Stripe definitively refused the change; the local quantity is unchanged and the detail carries the refusal.
  • extra_sessions_update_unconfirmed (502) - Stripe did not answer, so the outcome is unknown, not failed: the change may still have applied. The local quantity stays unchanged until the signed subscription webhook reconciles it. Refresh GET /v1/subscription shortly rather than assuming failure; because the quantity is absolute, re-sending the same number is safe.

Entry is the $49 sandbox, a one-time account fee, credited in full against your first production invoice. It includes the full builder, free simulated vcp_test_ calls (which produce no billable usage, ever), and paid platform test calls to verified numbers with starter credit included. Production arms behind an executed Production Services Order, a plan keyed to your declared workload class, payment, and BYO carrier verification. When those persisted requirements are complete, the active owner requests staff review; only staff’s fresh-step-up, dual-control promotion makes the workspace live and permits the one-time live-key handoff.

Current published rates live on the pricing page, because the rate card is public so you can price a campaign before the first call, and this site does not duplicate numbers that page owns. Legal terms live at www.vocapable.com/legal.