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.
Spend caps fail closed
Section titled “Spend caps fail closed”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_exceededmeans 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_unknownmeans 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.
Reading and setting the budget
Section titled “Reading and setting the 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": []}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.
Converting to production
Section titled “Converting to production”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:
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.
Extra concurrent sessions
Section titled “Extra concurrent sessions”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:
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. RefreshGET /v1/subscriptionshortly rather than assuming failure; because the quantity is absolute, re-sending the same number is safe.
Sandbox and production
Section titled “Sandbox and production”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.