voepy

Usage, quota & audit

Four read-only endpoints answer the questions every operator asks: Who am I and how much credit is left? What are my limits and how close am I? Where did the money go? Who changed what?

All paths under /v1/. Authorization: Bearer <api-key> required. All money is in cents (USD). Timestamps are ISO-8601.

EndpointAnswersShape
GET /v1/accountWho am I, balance, limitssingle object
GET /v1/quotaLimits and live usage against themsingle object
GET /v1/usageEvery credit and debit, line by linepaginated list
GET /v1/auditWho did what, when, from wherepaginated list

Account snapshot

One call returns the tenant, the live balance, and the quota caps — the same three blocks you'd otherwise fetch separately.

GET /v1/account
{
  "tenant": {
    "id": "…",
    "name": "Yourco Voice",
    "slug": "yourco-voice",
    "status": "active",
    "currency": "USD",
    "metadata": {},
    "webhook_failover_url": "https://yourapp.com/voepy/failover",
    "company": { "legal_name": "Yourco, Inc.", "country": "US", "…": "…" },
    "email_verified_at": "2026-05-01T09:14:00.000Z",
    "created_at": "2026-05-01T09:00:00.000Z",
    "updated_at": "2026-05-12T14:00:00.000Z"
  },
  "balance": {
    "balance_cents": 12450,
    "credit_limit_cents": 0,
    "auto_recharge_threshold_cents": 1000,
    "auto_recharge_amount_cents": 5000,
    "updated_at": "2026-05-12T14:33:00.880Z"
  },
  "quota": {
    "daily_spend_cap_cents": 50000,
    "monthly_spend_cap_cents": 1000000,
    "concurrent_call_limit": 25,
    "concurrent_call_limit_inbound": 25,
    "messages_per_second": 1,
    "blocked_country_codes": [],
    "allowed_country_codes": ["US", "CA"],
    "blocked_prefixes": [],
    "max_destination_rate_cents": 50,
    "allow_caller_id_forwarding": false,
    "updated_at": "2026-05-10T00:00:00.000Z"
  }
}

status is pending_verification, active, suspended, or closed. New outbound calls are rejected unless the tenant is active.

The balance block:

FieldMeaning
balance_centsRemaining prepaid credit. Signed — can go negative if a credit limit is set.
credit_limit_centsHow far below zero you may go before calls are blocked. 0 for most tenants.
auto_recharge_threshold_centsRecharge fires at/under this; null if auto-recharge is off.
auto_recharge_amount_centsHow much each recharge adds; null if off.
updated_atLast time the balance moved.

Calls are blocked with 402 balance_insufficient once balance_cents + credit_limit_cents reaches zero. Fund the balance with a top-up — see Billing.

Quota

GET /v1/account returns the quota caps. GET /v1/quota returns the caps plus where you stand against them right now — today's spend, the month's spend, and how many calls are in flight. It reads live (no cache) and is the exact snapshot the pre-flight gates evaluate before every call, so the numbers you see are the numbers that decide whether the next call goes through.

GET /v1/quota
{
  "daily_spend_cap_cents": 50000,
  "daily_spent_cents": 11920,
  "monthly_spend_cap_cents": 1000000,
  "monthly_spent_cents": 384210,
  "concurrent_call_limit": 25,
  "in_flight_calls": 3,
  "max_destination_rate_cents": 50,
  "blocked_country_codes": [],
  "allowed_country_codes": ["US", "CA"],
  "blocked_prefixes": ["1900"],
  "allow_caller_id_forwarding": false,
  "balance_cents": 12450,
  "credit_limit_cents": 0,
  "tenant_status": "active",
  "as_of": "2026-05-12T14:33:01.000Z"
}

This is a flat object — live usage sits alongside the caps it counts against, not nested under them.

Caps

FieldGates
daily_spend_cap_centsMax rated spend per day. Resets on your tenant's daily boundary. Over it → 403 daily_spend_cap_exceeded.
monthly_spend_cap_centsMax rated spend per calendar month.
concurrent_call_limitMax simultaneous calls. Over it → 403 concurrent_call_cap_exceeded.
max_destination_rate_centsPer-minute rate ceiling for a destination. Pricier routes are refused before dialing.
allowed_country_codesIf non-empty, only these ISO-3166 country codes may be dialed. Empty = no allow-list.
blocked_country_codesDestinations in these countries are refused (403 country_blocked).
blocked_prefixesNumber prefixes on this list are refused (403 prefix_blocked).
allow_caller_id_forwardingWhen true, POST /v1/calls may set a from you don't own. Admin-opt-in after a STIR/SHAKEN review. See Calls.

Live usage

FieldMeaning
daily_spent_centsRated voice spend so far today, as a positive number. Compare to daily_spend_cap_cents.
monthly_spent_centsRated spend so far this month, positive. Compare to monthly_spend_cap_cents.
in_flight_callsCalls currently non-terminal (initiated, ringing, answered, bridged). Compare to concurrent_call_limit.
balance_centsLive credit, mirrored here so a single call tells you both "can I afford it" and "am I within caps".
credit_limit_centsSame as on the account balance.
tenant_statuspending_verification | active | suspended | closed.
as_ofWhen this snapshot was computed (UTC).

daily_spent_cents and monthly_spent_cents are derived from your usage ledger entries (the usage kind below). Poll this endpoint to back a spend gauge or to throttle your own dialer before you hit a hard cap.

Cap changes are admin-only. If you need a higher ceiling, contact support — you can't raise your own caps through the API.

Usage ledger

Every movement of money — top-ups, per-call charges, monthly number fees, activation fees, refunds, and manual adjustments — is one append-only row in your ledger. The ledger is the authoritative record of what you were charged and when; nothing is ever edited or deleted, only appended.

GET /v1/usage
{
  "count": 842,
  "next": "https://api.voepy.com/v1/usage?page=2",
  "previous": null,
  "results": [
    {
      "id": "…",
      "kind": "usage",
      "amount_cents": -12,
      "running_balance_cents": 12438,
      "reference_type": "call",
      "reference_id": "voepy_call_01HZABC…",
      "description": "Outbound call to +15558675309 (38s)",
      "metadata": { "duration_seconds": 38, "destination": "US" },
      "created_at": "2026-05-12T14:33:01.000Z"
    },
    {
      "id": "…",
      "kind": "topup",
      "amount_cents": 5000,
      "running_balance_cents": 12450,
      "reference_type": "payment",
      "reference_id": "pi_…",
      "description": "Card top-up",
      "metadata": {},
      "created_at": "2026-05-12T14:00:00.000Z"
    }
  ]
}

Entry fields

FieldMeaning
idOpaque entry id.
kindWhat kind of movement (see table below).
amount_centsSigned. Positive = credit (money added). Negative = debit (money spent).
running_balance_centsThe balance after this entry was applied — your audit trail of the balance over time.
reference_typeThe kind of thing that caused the entry, e.g. call, payment, phone_number. May be blank.
reference_idThe id of that thing — cross-reference to a Call, payment, etc. May be blank.
descriptionHuman-readable summary.
metadataFree-form JSON with entry-specific detail (duration, destination, …).
created_atWhen the entry was written.

Sign convention

amount_cents carries the sign: credits are positive, debits are negative. A $50 top-up is +5000; a 12¢ call charge is -12. Sum the column over a window and you get the net change to your balance; running_balance_cents lets you reconcile any single row against the balance at that instant. (Note the live spend figures in GET /v1/quota flip the sign on usage debits so they read as positive spend — same numbers, opposite sign.)

Entry kinds

kindWhat it isTypical sign
topupCustomer payment (card top-up).+
usagePer-call (and per-minute feature) voice charges.
nrcNon-recurring charge — one-off activation fee (new DID, lookup, etc.).
mrcMonthly recurring charge — a number's monthly fee.
refundMoney returned to your balance.+
adjustmentManual correction by an admin.±

These map directly to how you're billed — see Billing for what drives each charge.

Filtering & pagination

GET /v1/usage?kind=usage&page=2&page_size=100
ParamDefaultNotes
kindFilter to one kind: topup, usage, nrc, mrc, refund, adjustment.
page11-indexed page number.
page_size20Max 200.

Entries come back newest-first. The envelope is page-number based: count is the total across all pages, next/previous are full URLs (or null at the ends), and results is the page. Walk pages by following next until it's null.

Audit log

The audit log records who changed your account configuration — membership, roles, API keys, quota, profiles, and the tenant itself. It exists for security and compliance: a tamper-evident, append-only trail of administrative actions.

GET /v1/audit
{
  "count": 137,
  "next": "https://api.voepy.com/v1/audit?page=2",
  "previous": null,
  "results": [
    {
      "id": "…",
      "action": "api_key.issued",
      "target_type": "api_key",
      "target_id": "…",
      "actor_email": "ops@yourco.com",
      "api_key_prefix": null,
      "before": null,
      "after": { "name": "CI deploy key", "scopes": ["calls:write"] },
      "ip": "203.0.113.7",
      "user_agent": "Mozilla/5.0 …",
      "created_at": "2026-05-12T14:32:18.000Z"
    },
    {
      "id": "…",
      "action": "member.role_changed",
      "target_type": "membership",
      "target_id": "…",
      "actor_email": "owner@yourco.com",
      "api_key_prefix": null,
      "before": { "role_slug": "member" },
      "after": { "role_slug": "admin" },
      "ip": "198.51.100.4",
      "user_agent": "Mozilla/5.0 …",
      "created_at": "2026-05-11T18:02:44.000Z"
    }
  ]
}

Entry fields

FieldMeaning
idOpaque entry id.
actionWhat happened, as a dotted constant (see below).
target_typeThe kind of resource acted on.
target_idThat resource's id (may be blank).
actor_emailThe user who performed the action, or null when the actor was an API key.
api_key_prefixThe key prefix that performed the action, or null when a user did it.
beforeSnapshot of the changed fields before the action (null on create).
afterSnapshot after (null on delete).
ipSource IP, or null if not captured.
user_agentClient user-agent string.
created_atWhen the action happened.

actor_email and api_key_prefix are mutually exclusive: exactly one identifies the actor, the other is null. The before/after pair gives you a field-level diff for any change.

Recorded actions

action values are dotted resource.verb constants. The full set currently emitted:

target_typeaction values
tenanttenant.signup, tenant.updated, tenant.created_by_admin, tenant.activated_via_verification, tenant.suspended_by_admin, tenant.suspended_unverified, tenant.auto_suspended, tenant.resumed_by_admin
membershipmember.invited, member.removed, member.role_changed
rolerole.created, role.updated, role.deleted
api_keyapi_key.issued, api_key.revoked
quotaquota.updated_by_admin
ledger_entryledger.adjustment_by_admin
tenant (profiles)inbound_profile.updated, outbound_profile.updated

See Team & roles for the membership and role actions in context.

Pagination

GET /v1/audit?page=2&page_size=50

Same page-number envelope as the usage ledger: page (default 1) and page_size (default 20, max 200), newest-first, with count/next/previous/results. The audit endpoint does not take field filters — page through and filter client-side, or narrow by following next.

Access is gated by the audit:read scope; issue keys (or assign roles) accordingly so only trusted operators can read the log.

Reconciling usage vs billing

The usage ledger and your Stripe billing answer different questions, and it's normal for them not to line up one-to-one:

  • The ledger is your prepaid balance's history. Top-ups, per-call usage charges, nrc/mrc fees, refunds, and adjustments all hit it. running_balance_cents on the newest row equals balance.balance_cents from GET /v1/account.
  • Stripe invoices cover MRC + overage minutes only. Top-ups and per-call rated charges are already debited from your balance, so they're not re-billed on the monthly invoice.

To verify a period: sum amount_cents for kind=usage over the window from GET /v1/usage — that's your rated voice spend — and it should match monthly_spent_cents from GET /v1/quota for the current month. To tie a single call's charge back to the call, match the ledger entry's reference_id to the Call.id. See Billing for how invoices and the balance relate.

Next

  • Billing — fund the balance these endpoints report on.
  • Team & roles — manage the members and keys the audit log tracks, and the scopes that gate these reads.
  • Error reference — the 402/403 codes the quota gates return.