Billing
How voepy charges you, and how you fund the account that gets charged.
All paths under
/v1/billing/.Authorization: Bearer <api-key>required.
How pricing works
Three things determine what you pay:
- Per-second voice charges — every answered call is rated after
hangup at carrier cost × your markup. The markup is fixed by your
plan (or a per-tenant override). Rated charges are debited from
your prepaid balance as
LedgerEntryrows. - Per-number monthly fee (MRC) — each provisioned DID has a monthly recurring charge. The first month is prorated; subsequent months are billed on the 1st.
- One-off activation fee (NRC) — debited up-front when you
order a new DID, lookup, or trigger another billable action like
gather,streaming,transcription, AMD.
Everything happens against your balance, which you fund via
top-ups. If the balance hits zero we reject new outbound calls
(402 balance_insufficient); calls already in flight finish
normally.
Read your balance
GET /v1/account
{
"tenant": { "id": "...", "name": "Yourco Voice" },
"balance": {
"amount_cents": 12450, // your remaining credit
"currency": "USD",
"credit_limit_cents": 0
}
}
For live spend and call counts use GET /v1/usage (filterable by
date range). Aggregated reports live under /v1/analytics/....
The funding flow
1. Create a Stripe SetupIntent POST /v1/billing/setup-intent
2. Confirm it in your frontend (Stripe.js / Elements)
3. Top up POST /v1/billing/topup
4. (Optional) Auto-recharge POST /v1/billing/auto-recharge
Stripe.js handles the card data; your server never touches it. The publishable Stripe key (
pk_…) is safe in the browser; the secret one (sk_…) lives only on our side — you never see it.
1 · Create a SetupIntent
POST /v1/billing/setup-intent
Response:
{
"client_secret": "seti_xxx_secret_yyy",
"setup_intent_id": "seti_xxx",
"stripe_customer_id": "cus_xxx"
}
Pass client_secret to Stripe Elements in your frontend. The user
enters their card; Stripe attaches it to our Stripe Customer and runs
SCA / 3DS if required.
2 · List saved payment methods
GET /v1/billing/payment-methods
[
{
"id": "pm_abc123",
"type": "card",
"card": {
"brand": "visa",
"last4": "4242",
"exp_month": 12,
"exp_year": 2028
},
"is_default": true
}
]
Set default: POST /v1/billing/payment-methods/{pm_id}.
Remove: DELETE /v1/billing/payment-methods/{pm_id}.
3 · Top up
POST /v1/billing/topup
Content-Type: application/json
Idempotency-Key: <uuid>
{
"amount_cents": 5000,
"payment_method_id": "pm_abc123"
}
payment_method_id is optional — omit to use the default. Response:
{
"payment_id": "...",
"status": "requires_action", // or "succeeded" if no 3DS
"client_secret": "pi_xxx_secret_yyy",
"amount_cents": 5000,
"currency": "USD"
}
If status == "requires_action", hand client_secret to
stripe.confirmCardPayment() in your frontend to clear 3DS. We
credit your balance when Stripe fires payment_intent.succeeded — no
extra call needed on your side.
// Frontend
const { error } = await stripe.confirmCardPayment(clientSecret);
if (error) showError(error.message);
else showSuccess("Top-up complete!");
Poll GET /v1/account (or listen for a future
balance.credited webhook) to confirm the balance bumped.
4 · Auto-recharge
Optional but recommended for production. We automatically top up when your balance drops below a threshold.
POST /v1/billing/auto-recharge
{
"threshold_cents": 1000, // recharge when balance ≤ $10
"amount_cents": 5000, // top up by $50
"payment_method_id": "pm_abc123"
}
We charge the saved card when the threshold is crossed and credit your balance. If the charge fails we email you and disable auto-recharge until you re-enable it.
Disable: DELETE /v1/billing/auto-recharge.
Plans (optional)
Plans bundle a markup tier, included voice minutes, and a monthly fee into a single SKU. You can run on the default markup with no plan, but attaching a plan locks in volume discounts.
List public plans
GET /v1/billing/plans
[
{
"slug": "starter",
"name": "Starter",
"monthly_fee_cents": 0,
"included_minutes": 0,
"markup_percent_bps": 4000,
"line_items": [
{ "kind": "voice_minute", "unit_amount_cents": 0, "unit_label": "minute", "is_metered": true },
{ "kind": "phone_number", "unit_amount_cents": 150, "unit_label": "number", "is_metered": false }
]
},
{
"slug": "growth",
"name": "Growth",
"monthly_fee_cents": 9900,
"included_minutes": 5000,
"markup_percent_bps": 3000,
"line_items": [ ... ]
}
]
Attach a plan
POST /v1/billing/subscription
{ "plan_slug": "growth" }
GET /v1/billing/subscription returns the current subscription; DELETE /v1/billing/subscription cancels it (the cancellation takes effect at
the end of the current billing period).
Payment history
GET /v1/billing/payments?status=succeeded&cursor=...&limit=50
Each row:
{
"id": "9f8c…",
"amount_cents": 5000,
"amount_refunded_cents": 0,
"currency": "USD",
"status": "succeeded", // pending | requires_action | succeeded | failed
"stripe_payment_intent_id": "pi_…",
"created_at": "2026-05-12T14:32:18.000Z"
}
Invoices
A monthly invoice is generated on the 1st covering MRC charges + overage minutes (anything past the plan-included quota). Top-ups and per-call rated charges are not re-billed on the invoice — they're already debited from your balance.
GET /v1/billing/invoices?status=paid&cursor=...&limit=50
Each row links to a Stripe-hosted PDF you can download or forward to your accounting team.
Refunds
Refunds are admin-initiated. Email support with the payment_id. The
refund credits back to the original card and we issue a balancing
ledger entry so your balance doesn't double-count.
Quotas
/v1/quota shows your hard limits — daily spend cap, concurrent
call cap, allow/deny country lists, and the auto-recharge config in
one place.
GET /v1/quota
{
"daily_spend_cap_cents": 50000,
"concurrent_call_cap": 25,
"countries_allowed": ["US", "CA"],
"countries_blocked": [],
"prefixes_blocked": [],
"allow_caller_id_forwarding": false
}
If you hit a cap, calls return 403 daily_spend_cap_exceeded or
403 concurrent_call_cap_exceeded. Daily caps reset at UTC midnight.
Per-tenant cap changes are admin-only — talk to support if you need a ceiling raised.
Next
- Phone numbers — buying numbers debits balance.
- Calls — the per-second charges you see on invoices.
- Error reference — codes for
402and403billing errors.
