Billing API reference
Updated
22 operations of the Fax for Agents API, from the OpenAPI document version 1.20.0, snapshot of 2026-11-13. The base URL is https://api.faxforagents.com/v1. This is one group of the full reference.
- A top-up session funds the live wallet with whole US dollars, 10 to 1000 per session.
- Auto top-up takes a threshold, an amount and a daily cap, and the card is saved at the first payment.
- The CSV of a usage export is read from a signed URL that takes no API key.
Operations
GET /v1/auto-topupsAuto top-up settingsPOST /v1/auto-topupsOpt in to auto top-up (threshold, amount, daily cap); the card is saved at the first paymentDELETE /v1/auto-topups/{auto_topup_id}Turn auto top-up offGET /v1/balanceAvailable and held balancePOST /v1/billing-portal-sessionsOpen the Stripe customer portal (cards, invoices, the subscription)GET /v1/billing-settingsBilling settings of the organizationPATCH /v1/billing-settingsChange the billing email or the low-balance thresholdGET /v1/budgetsSpending caps of this environmentPOST /v1/budgetsCreate a daily or monthly cap for the organization, a project or an agentPATCH /v1/budgets/{budget_id}Change a cap's limit or statusGET /v1/invoicesStripe invoices and receipts (hosted links)GET /v1/invoices/{invoice_id}One Stripe invoiceGET /v1/ledgerWallet transactions, newest firstGET /v1/subscriptionsSubscriptions and the workspace entitlementPOST /v1/subscriptions/checkoutOpen a hosted Checkout for the Agent workspace subscriptionGET /v1/topup-sessionsTop-up sessions, newest firstPOST /v1/topup-sessionsOpen a hosted Checkout to fund the live wallet (10 to 1000 USD)GET /v1/topup-sessions/{topup_session_id}Read a top-up sessionGET /v1/usageUsage rollups by day, direction, destination and projectPOST /v1/usage-exportsExport usage as CSV behind a signed downloadGET /v1/usage-exports/{export_id}Read a usage export (fresh link)GET /v1/usage-exports/{export_id}/contentThe CSV behind a signed URL (no API key)
How is money represented in the billing group?
As integers. Every amount is in micro-units of a US dollar, in fields that end in _micro. One dollar is 1000000. No field is a decimal number, so a client never rounds. The one exception in a request is amount_usd on a top-up session, which takes whole dollars.
The wallet is prepaid. GET /v1/balance returns two figures for the environment of the credential. available_micro is what a new send can use. held_micro is what queued and active faxes have reserved and not yet captured or released.
How do I fund the wallet?
POST /v1/topup-sessions opens a hosted Checkout page and returns its url. The amount is whole US dollars, 10 to 1000 per session, and it funds the live wallet. A person pays on that page. GET /v1/topup-sessions/{topup_session_id} reads the session with its status, and the list returns sessions newest first.
Auto top-up repeats that without a person. POST /v1/auto-topups takes three amounts. threshold_micro is the available balance below which a top-up starts. amount_micro is how much each one adds. daily_cap_micro is the most that can be added in one UTC day. The card is saved at the first payment, and the answer carries a setup_url for it. DELETE /v1/auto-topups/{auto_topup_id} turns it off.
What is a budget?
A budget is a spending cap. POST /v1/budgets creates a daily or monthly cap for the organization, a project or an agent. The answer shows limit_micro, spent_micro, remaining_micro and resets_at. PATCH /v1/budgets/{budget_id} changes the limit or the status. GET /v1/budgets lists the caps of the environment.
A budget is not a delegated policy. A policy decides whether a send needs a person. A budget stops spending once the cap is reached, whoever allowed the send.
Where are invoices, the ledger and the subscription?
GET /v1/ledger returns the wallet's transactions, newest first, a page at a time. GET /v1/invoices returns the payment provider's invoices and receipts with hosted links, and one invoice can be read by id.
POST /v1/billing-portal-sessions opens the customer portal for cards, invoices and the subscription. GET /v1/subscriptions returns subscriptions and the workspace entitlement. POST /v1/subscriptions/checkout opens a hosted Checkout for the Agent workspace subscription.
GET /v1/billing-settings and its PATCH hold the billing email and the low-balance threshold.
How do I read and export usage?
GET /v1/usage returns rollups between from and to. group_by chooses the grouping, by day, direction, destination or project, and project_id narrows it to one project. The answer has the items and the totals.
POST /v1/usage-exports writes the same data as CSV. Without dates it covers the last 30 days to today. The answer has a signed url. GET /v1/usage-exports/{export_id} returns a fresh link when the first has expired. The content route itself takes the signature in the address and no API key.
Which scopes and errors belong to billing?
Reads need billing:read. Everything that moves money or changes a setting needs billing:write. An agent key is never issued billing:write, so an agent cannot fund the wallet or raise its own cap.
Three statuses appear here more than elsewhere. 402 answers a call the wallet or the payment cannot cover. 409 answers a change that the state forbids. 503 answers while the payment provider is not available.
Each operation in detail
GET /v1/auto-topups
Auto top-up settings
Credential: an API key or a signed-in session. Scope: billing:read.
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object AutoTopup | yes |
Example
curl https://api.faxforagents.com/v1/auto-topups \
-H "Authorization: Bearer ffa_test_..."
POST /v1/auto-topups
Opt in to auto top-up (threshold, amount, daily cap); the card is saved at the first payment
Credential: an API key or a signed-in session. Scope: billing:write.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |
Request body application/json, required
| Field | Type | Required | Description |
|---|---|---|---|
amount_micro | integer | yes | Whole dollars, 10 to 1000 USD. |
daily_cap_micro | integer | yes | Never more than this per UTC day. |
threshold_micro | integer | yes | Top up when the available balance drops below this. |
Responses
| Status | Meaning |
|---|---|
201 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
402 | The prepaid balance does not cover the call: insufficient_balance. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
409 | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
503 | Something this call depends on is not available or not set up here, for example billing_unavailable or provider_unavailable. error.retryable says whether to send the same call again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
amount_micro | integer | yes | |
created_at | string | yes | |
daily_cap_micro | integer | yes | |
disabled_at | string or null | yes | |
environment | string (live, test) | yes | |
id | string | yes | |
last_attempt_at | string or null | yes | |
payment_method_saved | boolean | yes | |
setup_session_id | string or null | yes | |
setup_url | string or null | no | Where to save the card while status is pending_setup. |
status | string (pending_setup, active, disabled) | yes | |
threshold_micro | integer | yes | |
updated_at | string | yes |
Example
curl https://api.faxforagents.com/v1/auto-topups \
-X POST \
-H "Authorization: Bearer ffa_test_..." \
-H "Content-Type: application/json" \
-d '{"threshold_micro":0,"amount_micro":10000000,"daily_cap_micro":10000000}'
DELETE /v1/auto-topups/{auto_topup_id}
Turn auto top-up off
Credential: an API key or a signed-in session. Scope: billing:write.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
auto_topup_id | path | string | yes | |
Idempotency-Key | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
409 | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
deleted | boolean | no | |
id | string | yes |
Example
curl https://api.faxforagents.com/v1/auto-topups/AUTO_TOPUP_ID \
-X DELETE \
-H "Authorization: Bearer ffa_test_..."
GET /v1/balance
Available and held balance
Credential: an API key or a signed-in session. Scope: billing:read.
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
available_micro | integer | yes | |
currency | string | yes | |
environment | string (live, test) | yes | |
held_micro | integer | yes | |
top_up_url | string or null | no | The dashboard page where a person adds funds to the wallet. A key cannot top up. |
Example
curl https://api.faxforagents.com/v1/balance \
-H "Authorization: Bearer ffa_test_..."
POST /v1/billing-portal-sessions
Open the Stripe customer portal (cards, invoices, the subscription)
Credential: an API key or a signed-in session. Scope: billing:write.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |
Responses
| Status | Meaning |
|---|---|
201 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
402 | The prepaid balance does not cover the call: insufficient_balance. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
409 | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
503 | Something this call depends on is not available or not set up here, for example billing_unavailable or provider_unavailable. error.retryable says whether to send the same call again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
expires_at | string | yes | |
url | string | yes |
Example
curl https://api.faxforagents.com/v1/billing-portal-sessions \
-X POST \
-H "Authorization: Bearer ffa_test_..."
GET /v1/billing-settings
Billing settings of the organization
Credential: an API key or a signed-in session. Scope: billing:read.
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
billing_email | string or null | yes | |
disputed | boolean | yes | |
low_balance_active | boolean | yes | |
low_balance_threshold_micro | integer | yes | |
org_id | string | yes | |
stripe_customer | boolean | yes | |
workspace | boolean | yes |
Example
curl https://api.faxforagents.com/v1/billing-settings \
-H "Authorization: Bearer ffa_test_..."
PATCH /v1/billing-settings
Change the billing email or the low-balance threshold
Credential: an API key or a signed-in session. Scope: billing:write.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |
Request body application/json, required
| Field | Type | Required | Description |
|---|---|---|---|
billing_email | string (email) or null | no | |
low_balance_threshold_micro | integer or null | no |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
409 | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
billing_email | string or null | yes | |
disputed | boolean | yes | |
low_balance_active | boolean | yes | |
low_balance_threshold_micro | integer | yes | |
org_id | string | yes | |
stripe_customer | boolean | yes | |
workspace | boolean | yes |
Example
curl https://api.faxforagents.com/v1/billing-settings \
-X PATCH \
-H "Authorization: Bearer ffa_test_..." \
-H "Content-Type: application/json" \
-d '{}'
GET /v1/budgets
Spending caps of this environment
Credential: an API key or a signed-in session. Scope: billing:read.
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object Budget | yes |
Example
curl https://api.faxforagents.com/v1/budgets \
-H "Authorization: Bearer ffa_test_..."
POST /v1/budgets
Create a daily or monthly cap for the organization, a project or an agent
Credential: an API key or a signed-in session. Scope: billing:write.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |
Request body application/json, required
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | string or null | no | |
limit_micro | integer | yes | |
period | string (daily, monthly) | yes | |
project_id | string or null | no | |
scope | string (organization, project, agent) | no |
Responses
| Status | Meaning |
|---|---|
201 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
409 | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | string or null | yes | |
created_at | string | yes | |
environment | string (live, test) | yes | |
id | string | yes | |
limit_micro | integer | yes | |
period | string (daily, monthly) | yes | |
project_id | string or null | yes | |
remaining_micro | integer | yes | |
resets_at | string | yes | |
scope | string (organization, project, agent) | yes | |
spent_micro | integer | yes | |
status | string (active, disabled) | yes | |
updated_at | string | yes |
Example
curl https://api.faxforagents.com/v1/budgets \
-X POST \
-H "Authorization: Bearer ffa_test_..." \
-H "Content-Type: application/json" \
-d '{"period":"daily","limit_micro":0}'
PATCH /v1/budgets/{budget_id}
Change a cap's limit or status
Credential: an API key or a signed-in session. Scope: billing:write.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
budget_id | path | string | yes | |
Idempotency-Key | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |
Request body application/json, required
| Field | Type | Required | Description |
|---|---|---|---|
limit_micro | integer or null | no | |
status | string (active, disabled) or null | no |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
409 | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | string or null | yes | |
created_at | string | yes | |
environment | string (live, test) | yes | |
id | string | yes | |
limit_micro | integer | yes | |
period | string (daily, monthly) | yes | |
project_id | string or null | yes | |
remaining_micro | integer | yes | |
resets_at | string | yes | |
scope | string (organization, project, agent) | yes | |
spent_micro | integer | yes | |
status | string (active, disabled) | yes | |
updated_at | string | yes |
Example
curl https://api.faxforagents.com/v1/budgets/BUDGET_ID \
-X PATCH \
-H "Authorization: Bearer ffa_test_..." \
-H "Content-Type: application/json" \
-d '{}'
GET /v1/invoices
Stripe invoices and receipts (hosted links)
Credential: an API key or a signed-in session. Scope: billing:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
cursor | query | string or null | no | |
limit | query | integer | no | Default 20. |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
503 | Something this call depends on is not available or not set up here, for example billing_unavailable or provider_unavailable. error.retryable says whether to send the same call again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object Invoice | yes | |
next_cursor | string or null | no |
Example
curl https://api.faxforagents.com/v1/invoices \
-H "Authorization: Bearer ffa_test_..."
GET /v1/invoices/{invoice_id}
One Stripe invoice
Credential: an API key or a signed-in session. Scope: billing:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
invoice_id | path | string | yes |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
503 | Something this call depends on is not available or not set up here, for example billing_unavailable or provider_unavailable. error.retryable says whether to send the same call again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
amount_due_micro | integer | yes | |
amount_paid_micro | integer | yes | |
created_at | string or null | yes | |
currency | string | yes | |
hosted_invoice_url | string or null | yes | |
id | string | yes | |
invoice_pdf | string or null | yes | |
number | string or null | yes | |
status | string or null | yes | |
subscription_id | string or null | yes |
Example
curl https://api.faxforagents.com/v1/invoices/INVOICE_ID \
-H "Authorization: Bearer ffa_test_..."
GET /v1/ledger
Wallet transactions, newest first
Credential: an API key or a signed-in session. Scope: billing:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
cursor | query | string or null | no | |
limit | query | integer | no | Default 50. |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object LedgerEntry | yes | |
next_cursor | string or null | no |
Example
curl https://api.faxforagents.com/v1/ledger \
-H "Authorization: Bearer ffa_test_..."
GET /v1/subscriptions
Subscriptions and the workspace entitlement
Credential: an API key or a signed-in session. Scope: billing:read.
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object Subscription | yes | |
next_cursor | string or null | no | |
workspace | boolean | yes |
Example
curl https://api.faxforagents.com/v1/subscriptions \
-H "Authorization: Bearer ffa_test_..."
POST /v1/subscriptions/checkout
Open a hosted Checkout for the Agent workspace subscription
Credential: an API key or a signed-in session. Scope: billing:write.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |
Responses
| Status | Meaning |
|---|---|
201 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
402 | The prepaid balance does not cover the call: insufficient_balance. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
409 | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
503 | Something this call depends on is not available or not set up here, for example billing_unavailable or provider_unavailable. error.retryable says whether to send the same call again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
product | string | yes | |
stripe_session_id | string | yes | |
url | string | yes |
Example
curl https://api.faxforagents.com/v1/subscriptions/checkout \
-X POST \
-H "Authorization: Bearer ffa_test_..."
GET /v1/topup-sessions
Top-up sessions, newest first
Credential: an API key or a signed-in session. Scope: billing:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
cursor | query | string or null | no | |
limit | query | integer | no | Default 50. |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object TopupSession | yes | |
next_cursor | string or null | no |
Example
curl https://api.faxforagents.com/v1/topup-sessions \
-H "Authorization: Bearer ffa_test_..."
POST /v1/topup-sessions
Open a hosted Checkout to fund the live wallet (10 to 1000 USD)
Credential: an API key or a signed-in session. Scope: billing:write.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |
Request body application/json, required
| Field | Type | Required | Description |
|---|---|---|---|
amount_usd | integer | yes | Whole US dollars, 10 to 1000 per session. |
Responses
| Status | Meaning |
|---|---|
201 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
402 | The prepaid balance does not cover the call: insufficient_balance. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
409 | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
503 | Something this call depends on is not available or not set up here, for example billing_unavailable or provider_unavailable. error.retryable says whether to send the same call again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
amount_micro | integer | yes | |
auto_topup_id | string or null | yes | |
completed_at | string or null | yes | |
created_at | string | yes | |
currency | string | yes | |
environment | string (live, test) | yes | |
error | string or null | yes | |
expires_at | string or null | yes | |
id | string | yes | |
kind | string (manual, auto, setup) | yes | |
status | string (open, completed, expired, canceled, failed) | yes | |
stripe_payment_intent_id | string or null | yes | |
stripe_session_id | string or null | yes | |
url | string or null | no | The hosted Checkout page while the session is open. |
Example
curl https://api.faxforagents.com/v1/topup-sessions \
-X POST \
-H "Authorization: Bearer ffa_test_..." \
-H "Content-Type: application/json" \
-d '{"amount_usd":10}'
GET /v1/topup-sessions/{topup_session_id}
Read a top-up session
Credential: an API key or a signed-in session. Scope: billing:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
topup_session_id | path | string | yes |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
amount_micro | integer | yes | |
auto_topup_id | string or null | yes | |
completed_at | string or null | yes | |
created_at | string | yes | |
currency | string | yes | |
environment | string (live, test) | yes | |
error | string or null | yes | |
expires_at | string or null | yes | |
id | string | yes | |
kind | string (manual, auto, setup) | yes | |
status | string (open, completed, expired, canceled, failed) | yes | |
stripe_payment_intent_id | string or null | yes | |
stripe_session_id | string or null | yes | |
url | string or null | no | The hosted Checkout page while the session is open. |
Example
curl https://api.faxforagents.com/v1/topup-sessions/TOPUP_SESSION_ID \
-H "Authorization: Bearer ffa_test_..."
GET /v1/usage
Usage rollups by day, direction, destination and project
Credential: an API key or a signed-in session. Scope: billing:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
from | query | string or null | no | |
to | query | string or null | no | |
group_by | query | string | no | Comma-separated subset. Default "day,direction,route,project". |
project_id | query | string or null | no |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
currency | string | yes | |
environment | string (live, test) | yes | |
from | string | yes | |
group_by | array of string | yes | |
items | array of object UsageItem | yes | |
to | string | yes | |
totals | object | yes |
Example
curl https://api.faxforagents.com/v1/usage \
-H "Authorization: Bearer ffa_test_..."
POST /v1/usage-exports
Export usage as CSV behind a signed download
Credential: an API key or a signed-in session. Scope: billing:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
Idempotency-Key | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |
Request body application/json, required
| Field | Type | Required | Description |
|---|---|---|---|
from | string or null | no | ISO date; default 30 days ago. |
to | string or null | no | ISO date; default today. |
Responses
| Status | Meaning |
|---|---|
201 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
409 | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
content_type | string | yes | |
created_at | string | yes | |
environment | string (live, test) | yes | |
expires_at | string | yes | |
id | string | yes | |
params | object | yes | |
row_count | integer | yes | |
status | string (ready, expired) | yes | |
url | string or null | yes |
Example
curl https://api.faxforagents.com/v1/usage-exports \
-X POST \
-H "Authorization: Bearer ffa_test_..." \
-H "Content-Type: application/json" \
-d '{}'
GET /v1/usage-exports/{export_id}
Read a usage export (fresh link)
Credential: an API key or a signed-in session. Scope: billing:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
export_id | path | string | yes |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
401 | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
403 | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
429 | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
content_type | string | yes | |
created_at | string | yes | |
environment | string (live, test) | yes | |
expires_at | string | yes | |
id | string | yes | |
params | object | yes | |
row_count | integer | yes | |
status | string (ready, expired) | yes | |
url | string or null | yes |
Example
curl https://api.faxforagents.com/v1/usage-exports/EXPORT_ID \
-H "Authorization: Bearer ffa_test_..."
GET /v1/usage-exports/{export_id}/content
The CSV behind a signed URL (no API key)
Credential: the signed URL as it was given.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
export_id | path | string | yes | |
exp | query | string or null | no | |
sig | query | string or null | no |
Responses
| Status | Meaning |
|---|---|
200 | Successful Response |
404 | not_found: no such resource for this credential. A resource of another organization answers the same. |
422 | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
Example
curl https://api.faxforagents.com/v1/usage-exports/EXPORT_ID/content