Skip to content

Billing

Programmatic access to your tenant's credit balance, transactions, invoices, per-call cost breakdowns, and spend alerts. The dashboard's Billing & Usage screen is built entirely on these endpoints.

Rymi bills per minute of connected call audio against a prepaid credit balance, charged in 30-second increments rounded up — a 0–30s call bills 30 seconds, 31–60s bills one minute, and so on. Failed calls (busy, no-answer) don't bill — only calls that connect and exchange audio.

Get Pricing Rates

http
GET /v1/billing/agent-roles

Returns per-role pricing rates. Same rates apply across Free and Enterprise; roles are runtime pricing choices. There are four roles: operator, specialist, executive, and concierge.

Response 200

json
{
  "roles": {
    "operator": {
      "rate_per_minute": 0.05,
      "rate_per_second": 0.00083333,
      "display_name": "Operator"
    },
    "specialist": { "rate_per_minute": 0.10, "rate_per_second": 0.00166667, "display_name": "Specialist" },
    "executive": { "rate_per_minute": 0.25, "rate_per_second": 0.00416667, "display_name": "Executive" },
    "concierge": { "rate_per_minute": 0.40, "rate_per_second": 0.00666667, "display_name": "Concierge" }
  }
}

Get Balance

http
GET /v1/billing/balance

Returns the tenant's current credit balance plus composition signals the dashboard uses to render the right headline format (single-role tenant, runway estimate, role range, etc.).

Response 200

json
{
  "tenant_id": "550e8400-...",
  "balance_seconds": 18000,
  "balance_usd": 15.0,
  "estimated_minutes_remaining": 300,
  "topup_minutes_remaining": 60,
  "roles": { "operator": 0.05, "specialist": 0.10, "executive": 0.25, "concierge": 0.40 },
  "is_active": true,
  "tone": "ok",
  "tenant_state": "has_calls",
  "primary_role": "specialist",
  "agent_roles_in_use": [],
  "recent_daily_spend_usd": 1.20,
  "runway_days_estimate": 12
}
FieldDescription
balance_secondsRemaining seconds in the active credit bucket at the operator rate. The active bucket is the included quota while any remains, then top-up credits
balance_usdThe active bucket in USD
estimated_minutes_remainingThe active bucket in whole minutes
topup_minutes_remainingTop-up bucket only, in minutes — purchased credit that survives the included quota reset
is_activeWhether the tenant can dispatch live calls (false when total balance ≤ 0)
toneUI hint — ok, low (under 30 min), or critical (under 5 min or inactive). Reflects total balance (included quota + top-up), so a draining included bucket doesn't false-alarm when top-up credit remains
tenant_stateno_agents, agents_no_calls, or has_calls
primary_roleMost-used role across the last 30 days, or null if no role accounts for >50% of recent calls
recent_daily_spend_usd7-day rolling daily-spend average (only set after ≥7 days of activity)
runway_days_estimatebalance_usd / recent_daily_spend_usd, only set when both are populated

List Transactions

http
GET /v1/billing/transactions

Per-tenant credit ledger — top-ups, monthly grants, refunds, and per-call deductions.

Query Parameters

ParameterTypeDefaultDescription
limitinteger50Max records (cap 200)
fromISO dateInclusive lower bound on created_at
toISO dateInclusive upper bound on created_at (extended to end of day)

Response 200

json
{
  "transactions": [
    {
      "id": "tx_...",
      "call_id": null,
      "amount_seconds": 36000,
      "amount_usd": 30.0,
      "transaction_type": "stripe_topup",
      "description": "Top-up via Stripe",
      "metadata": {},
      "created_at": "2026-04-01T10:00:00Z"
    }
  ]
}

Per-call deductions carry the call_id they were billed against; top-ups and grants have call_id: null.


List Invoices

http
GET /v1/billing/invoices

Cursor-paginated list of invoices for the tenant.

Query Parameters

ParameterTypeDefaultDescription
limitinteger25Max records (cap 100)
cursorstringResume token returned in next_cursor

Response 200

json
{
  "invoices": [
    { "id": "inv_...", "total_usd": 30.0, "status": "paid", "created_at": "..." }
  ],
  "next_cursor": null
}

Get Invoice

http
GET /v1/billing/invoices/:id

Returns the invoice plus its line items.

Response 200

json
{
  "invoice": { "id": "inv_...", "total_usd": 30.0, "status": "paid" },
  "items": [ { "description": "Top-up", "amount_usd": 30.0 } ]
}
StatusMeaning
404Invoice does not exist for this tenant

Per-Call Cost Breakdown

http
GET /v1/billing/calls

Lists recent calls with cost / margin metadata. Useful for reconciliation against your own records.

Query Parameters

ParameterTypeDefaultDescription
limitinteger50Max records (cap 200)
fromISO dateInclusive lower bound on started_at
toISO dateInclusive upper bound on started_at
agent_idstringFilter to a single agent

Response 200

json
{
  "calls": [
    {
      "id": "call_...",
      "started_at": "2026-04-01T10:00:00Z",
      "agent_id": "agent_...",
      "agent_name": "Support Bot",
      "agent_role": "specialist",
      "duration_seconds": 145,
      "customer_revenue": 0.29,
      "provider_cost": 0.07,
      "gross_margin": 0.22
    }
  ]
}

Export CSV

http
GET /v1/billing/export.csv

Downloads up to 5,000 calls as CSV. Filterable by date range, agent, and call status.

Query Parameters

ParameterTypeDescription
fromISO dateInclusive lower bound on started_at
toISO dateInclusive upper bound on started_at
agent_idstringFilter to a single agent
statusstringFilter by call status (completed, failed, …)

Returns text/csv with header row:

call_id,started_at,agent_id,agent_role,duration_seconds,customer_revenue_usd,provider_cost_usd,gross_margin_usd

Spend Alerts

http
GET /v1/billing/alerts
PUT /v1/billing/alerts

Configure threshold-based spend alerts.

PUT Request Body

FieldTypeDescription
thresholds_usdnumber[]Spend thresholds in USD (max 10)
low_balance_pctinteger (0–100)Alert when remaining balance ≤ this percent of last top-up
email_enabledbooleanWhether to email the alert

GET Response 200

json
{ "thresholds_usd": [50, 100], "low_balance_pct": 20, "email_enabled": true }

Tenants that have never saved preferences get the defaults shown above.

PUT Response 200

json
{ "ok": true }

Spend-Velocity Alerts

http
GET /v1/billing/spend-alerts
POST /v1/billing/spend-alerts/:id/acknowledge

Returns un-acknowledged spend-velocity alerts (Phase 2B safety net) and the most recent ten acknowledged ones, plus an endpoint to dismiss a banner.

GET Response 200

json
{
  "unacknowledged": [
    { "id": "alert_...", "alert_type": "spend_velocity", "severity": "critical", "amount_usd": 12.5, "threshold_usd": 10.0 }
  ],
  "recent": []
}

Acknowledging returns { "id": "...", "acknowledged_at": "..." }, or 404 if the alert doesn't exist, was already acknowledged, or belongs to another tenant.


Estimate

http
POST /v1/billing/estimate

Estimates cost for a given role / duration. Used by the studio's call-planner.

Request Body

FieldTypeDescription
tierstringoperator, specialist, executive, or concierge (default operator)
duration_secondsnumberOptional; when provided, est_for_duration_usd is included in the response

Response 200

json
{
  "tier": "specialist",
  "low_usd_per_min": 0.10,
  "high_usd_per_min": 0.10,
  "est_for_duration_usd": 0.2417
}

Usage Summary

http
GET /v1/billing/usage-summary

Lane-aware usage summary across the three metered surfaces: voice runtime (in minutes — the customer-facing unit), Studio AI units, and post-call intelligence units. This is what the dashboard's usage cards render, and what the SDKs' billing.usage_summary() returns.

Response 200

json
{
  "voice_runtime": { "remaining_minutes": 300, "status": "ok" },
  "studio_ai": {
    "used_units": 12,
    "included_units": 100,
    "quota_percent": 12,
    "status": "ok",
    "overage_enabled": false
  },
  "post_call_intelligence": {
    "status": "quota",
    "used_units": 4,
    "included_units": 50,
    "quota_percent": 8
  }
}

Plan & Billing State

http
GET /v1/billing/plan
POST /v1/billing/checkout/start

The dashboard uses these to read the current plan state and start prepaid top-up checkout.

GET /billing/plan Response 200

json
{
  "plan_id": "free",
  "plan": { "id": "free", "display_name": "Free", "monthly_credit_cents": 100, "byok_allowed": false },
  "monthly_credit_remaining_cents": 80,
  "monthly_credit_resets_at": "2026-05-01T00:00:00Z",
  "topup_balance_cents": 1500,
  "extra_usage_enabled": true,
  "plan_active_since": "2026-04-01T00:00:00Z",
  "preferred_gateway": "stripe",
  "preferred_currency": "USD",
  "usd_to_inr_rate": 84.0,
  "billing_mode": "prepaid_only"
}

billing_mode is currently prepaid_only in the MVP: included plan quota runs first, then prepaid wallet balance covers extra usage when enabled.

POST /billing/checkout/start Body

FieldTypeRequiredDescription
pack_usdnumberyesDollar value to add to the prepaid wallet
billing_countrystringnoISO country code used for gateway selection
tax_idstringnoTax identifier used for gateway selection
save_cardbooleannoRegister the card for auto-recharge when supported

Returns a Razorpay order payload for India-region checkout or a Stripe Checkout URL when Stripe checkout is enabled for the tenant region.

Errors

StatusMeaning
503Gateway not configured (missing Stripe / Razorpay env)