API reference
Billing and usage
Prepaid credit in euro: balance, ledger, top-ups, auto-recharge, the payment portal, the billing preview and metered usage.
Rytiv bills from prepaid credit in euro. Usage is metered per machine and booked against the balance; at zero, machines are stopped (not deleted), nothing new starts and reads stay open. Top-ups and the auto-recharge rule are set in the console by an admin; the routes for them refuse a plain API key. See the guide Credit and prices.
Endpoints
Section titled “Endpoints”GET /v1/billing/credits: The credit account: balance, whether it is blocked at zero, the warning line and the auto-recharge ruleGET /v1/billing/ledger: The credit ledger: top-ups, usage bookings, grants, refunds and adjustments, newest firstPOST /v1/billing/topups: Starts a top-up and answers the payment page to open. The card is typed there; no card data crosses this APIPUT /v1/billing/auto-recharge: Sets the auto-recharge rule: when the balance falls belowthresholdCents, chargeamountCents, never more thancapCentsin totalPOST /v1/billing/portal: A link to the payment portal, where a saved card is changedGET /v1/billing/preview: What a period cost, line by line, from the metered usageGET /v1/usage: The metered usage events of the organization
GET /v1/billing/credits
Section titled “GET /v1/billing/credits”The credit account: balance, whether it is blocked at zero, the warning line and the auto-recharge rule.
Auth: API key with full access (a key with scopes cannot call this route). Every class of agent token may call it.
Example request
Section titled “Example request”curl -X GET "https://api.rytiv.app/v1/billing/credits" \ -H "Authorization: Bearer $RYTIV_TOKEN"Response
Section titled “Response”200 with the credit account:
{ "orgId": "<orgId>", "currency": "EUR", "prepaid": true, "balanceMicros": "<balanceMicros>", "balanceCents": -9007199254740991, "blocked": true, "blockedAt": "2026-10-21T09:00:00Z", "warned": true, "warnAtPercent": 0, "minTopupCents": 1, "priced": [ "<priced>" ], "autoRecharge": { "enabled": true, "thresholdCents": 0, "amountCents": 0, "capCents": 0, "pending": true, "failedAt": "2026-10-21T09:00:00Z", "hasPaymentMethod": true }}| Field | Type | Present | Description |
|---|---|---|---|
orgId |
string | always | The organization that owns it. |
currency |
"EUR" |
always | |
prepaid |
boolean | always | Whether the organization is on prepaid credit. |
balanceMicros |
string | always | The exact balance in micro-cents, as a decimal string. |
balanceCents |
integer | always | The balance in whole cents, rounded down. -9007199254740991 to 9007199254740991. |
blocked |
boolean | always | The balance reached zero: machines stopped, nothing new starts, reads stay open. |
blockedAt |
string (ISO 8601) or null | always | When that happened. |
warned |
boolean | always | The balance fell below the warning line. |
warnAtPercent |
integer | always | The warning line as a percentage of the reference top-up. 0 to 100. |
minTopupCents |
integer | always | The smallest top-up. at most 9007199254740991. |
priced |
array of string | always | The usage kinds that carry a price right now. |
autoRecharge |
object | always | The auto-recharge rule and its state. |
autoRecharge.enabled |
boolean | always | false creates the schedule paused. |
autoRecharge.thresholdCents |
integer | always | Charge when the balance falls below this. 0 to 9007199254740991. |
autoRecharge.amountCents |
integer | always | Whole cents. 0 to 9007199254740991. |
autoRecharge.capCents |
integer | always | Never charge more than this in total through the rule. 0 to 9007199254740991. |
autoRecharge.pending |
boolean | always | |
autoRecharge.failedAt |
string (ISO 8601) or null | always | |
autoRecharge.hasPaymentMethod |
boolean | always |
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
GET /v1/billing/ledger
Section titled “GET /v1/billing/ledger”The credit ledger: top-ups, usage bookings, grants, refunds and adjustments, newest first.
Auth: API key with full access (a key with scopes cannot call this route). Every class of agent token may call it.
Query parameters
Section titled “Query parameters”| Name | Description |
|---|---|
limit |
How many entries, at most. |
Example request
Section titled “Example request”curl -X GET "https://api.rytiv.app/v1/billing/ledger" \ -H "Authorization: Bearer $RYTIV_TOKEN"Response
Section titled “Response”200 with the ledger:
{ "orgId": "<orgId>", "currency": "EUR", "limit": 1, "entries": [ { "id": "<id>", "kind": "topup", "amountMicros": "<amountMicros>", "amountCents": -9007199254740991, "reference": "goodwill-2026-10", "windowFrom": "2026-10-21T09:00:00Z", "windowTo": "2026-10-21T09:00:00Z", "detail": "<detail>", "at": "2026-10-21T09:00:00Z" } ]}| Field | Type | Present | Description |
|---|---|---|---|
orgId |
string | always | The organization that owns it. |
currency |
"EUR" |
always | |
limit |
integer | always | at most 9007199254740991. |
entries |
array of object | always |
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
POST /v1/billing/topups
Section titled “POST /v1/billing/topups”Starts a top-up and answers the payment page to open. The card is typed there; no card data crosses this API.
Auth: API key with full access, and only through the console as an admin (a plain API key answers 403 with billing-console-only). Refused for every agent token (agent-token-credential).
Request body
Section titled “Request body”JSON, the shape CreditTopupRequest of the contract.
| Field | Type | Required | Description |
|---|---|---|---|
amountCents |
integer | required | Whole cents. at most 9007199254740991. |
Example request
Section titled “Example request”curl -X POST "https://api.rytiv.app/v1/billing/topups" \ -H "Authorization: Bearer $RYTIV_TOKEN" \ -H "Content-Type: application/json" \ -d '{"amountCents":1}'Response
Section titled “Response”201 with the top-up:
{ "topupId": "<topupId>", "amountCents": 1, "checkoutUrl": "<checkoutUrl>", "sessionId": "<sessionId>"}| Field | Type | Present | Description |
|---|---|---|---|
topupId |
string | always | |
amountCents |
integer | always | Whole cents. at most 9007199254740991. |
checkoutUrl |
string | always | The payment page to open. The card is typed there. |
sessionId |
string | always |
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 400 | bad-request |
The request is malformed or a field is out of range. error names every field; issues lists them. |
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | billing-console-only |
A billing change is made in the console by an admin, not with an API key. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
| 409 | not-prepaid |
The organization has no credit account; only org creation or an operator’s grant starts prepaid credit. |
PUT /v1/billing/auto-recharge
Section titled “PUT /v1/billing/auto-recharge”Sets the auto-recharge rule: when the balance falls below thresholdCents, charge amountCents, never more than capCents in total.
Auth: API key with full access, and only through the console as an admin (a plain API key answers 403 with billing-console-only). Refused for every agent token (agent-token-credential).
Request body
Section titled “Request body”JSON, the shape CreditAutoRechargeRequest of the contract.
| Field | Type | Required | Description |
|---|---|---|---|
enabled |
boolean | required | false creates the schedule paused. |
thresholdCents |
integer | optional | Charge when the balance falls below this. 0 to 9007199254740991, default 0. |
amountCents |
integer | optional | Whole cents. 0 to 9007199254740991, default 0. |
capCents |
integer | optional | Never charge more than this in total through the rule. 0 to 9007199254740991, default 0. |
Example request
Section titled “Example request”curl -X PUT "https://api.rytiv.app/v1/billing/auto-recharge" \ -H "Authorization: Bearer $RYTIV_TOKEN" \ -H "Content-Type: application/json" \ -d '{"enabled":true}'Response
Section titled “Response”200 with the credit account with the new rule:
{ "orgId": "<orgId>", "currency": "EUR", "prepaid": true, "balanceMicros": "<balanceMicros>", "balanceCents": -9007199254740991, "blocked": true, "blockedAt": "2026-10-21T09:00:00Z", "warned": true, "warnAtPercent": 0, "minTopupCents": 1, "priced": [ "<priced>" ], "autoRecharge": { "enabled": true, "thresholdCents": 0, "amountCents": 0, "capCents": 0, "pending": true, "failedAt": "2026-10-21T09:00:00Z", "hasPaymentMethod": true }}| Field | Type | Present | Description |
|---|---|---|---|
orgId |
string | always | The organization that owns it. |
currency |
"EUR" |
always | |
prepaid |
boolean | always | Whether the organization is on prepaid credit. |
balanceMicros |
string | always | The exact balance in micro-cents, as a decimal string. |
balanceCents |
integer | always | The balance in whole cents, rounded down. -9007199254740991 to 9007199254740991. |
blocked |
boolean | always | The balance reached zero: machines stopped, nothing new starts, reads stay open. |
blockedAt |
string (ISO 8601) or null | always | When that happened. |
warned |
boolean | always | The balance fell below the warning line. |
warnAtPercent |
integer | always | The warning line as a percentage of the reference top-up. 0 to 100. |
minTopupCents |
integer | always | The smallest top-up. at most 9007199254740991. |
priced |
array of string | always | The usage kinds that carry a price right now. |
autoRecharge |
object | always | The auto-recharge rule and its state. |
autoRecharge.enabled |
boolean | always | false creates the schedule paused. |
autoRecharge.thresholdCents |
integer | always | Charge when the balance falls below this. 0 to 9007199254740991. |
autoRecharge.amountCents |
integer | always | Whole cents. 0 to 9007199254740991. |
autoRecharge.capCents |
integer | always | Never charge more than this in total through the rule. 0 to 9007199254740991. |
autoRecharge.pending |
boolean | always | |
autoRecharge.failedAt |
string (ISO 8601) or null | always | |
autoRecharge.hasPaymentMethod |
boolean | always |
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 400 | bad-request |
The request is malformed or a field is out of range. error names every field; issues lists them. |
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | billing-console-only |
A billing change is made in the console by an admin, not with an API key. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
| 409 | not-prepaid |
The organization has no credit account; only org creation or an operator’s grant starts prepaid credit. |
POST /v1/billing/portal
Section titled “POST /v1/billing/portal”A link to the payment portal, where a saved card is changed.
Auth: API key with full access, and only through the console as an admin (a plain API key answers 403 with billing-console-only). Refused for every agent token (agent-token-credential).
Example request
Section titled “Example request”curl -X POST "https://api.rytiv.app/v1/billing/portal" \ -H "Authorization: Bearer $RYTIV_TOKEN"Response
Section titled “Response”200 with the link:
{ "url": "<url>"}| Field | Type | Present | Description |
|---|---|---|---|
url |
string | always |
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | billing-console-only |
A billing change is made in the console by an admin, not with an API key. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
| 409 | no-customer |
No payment relationship yet; a first top-up creates it. |
GET /v1/billing/preview
Section titled “GET /v1/billing/preview”What a period cost, line by line, from the metered usage.
Auth: API key with full access (a key with scopes cannot call this route). Every class of agent token may call it.
Query parameters
Section titled “Query parameters”| Name | Description |
|---|---|
from |
Start of the period (ISO 8601). |
to |
End of the period (ISO 8601). |
Example request
Section titled “Example request”curl -X GET "https://api.rytiv.app/v1/billing/preview" \ -H "Authorization: Bearer $RYTIV_TOKEN"Response
Section titled “Response”200 with the preview:
{ "orgId": "<orgId>", "currency": "EUR", "from": "2026-10-21T09:00:00Z", "to": "www.example.com", "lines": [ { "kind": "machine_running_seconds", "unit": "<unit>", "quantity": 0, "priced": true } ], "pricesDecided": true}| Field | Type | Present | Description |
|---|---|---|---|
orgId |
string | always | The organization that owns it. |
currency |
"EUR" |
always | |
from |
string (ISO 8601) | always | |
to |
string (ISO 8601) | always | Another hostname of the same app to redirect to, or null to clear the redirect. |
lines |
array of object | always | One line per usage kind: quantity, unit, and the amount where a price is set. |
total |
number | if set | The sum of the priced lines. at least 0. |
pricesDecided |
boolean | always | Whether this answer carries amounts. |
pricedFrom |
string (ISO 8601) | if set | |
unpricedReason |
no-price-list | no-credit-account | before-credit |
if set | If not, why: no-price-list, no-credit-account or before-credit. |
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
GET /v1/usage
Section titled “GET /v1/usage”The metered usage events of the organization.
Auth: API key with full access (a key with scopes cannot call this route). Every class of agent token may call it.
Query parameters
Section titled “Query parameters”| Name | Description |
|---|---|
from |
Start of the period (ISO 8601). |
to |
End of the period (ISO 8601). |
Example request
Section titled “Example request”curl -X GET "https://api.rytiv.app/v1/usage" \ -H "Authorization: Bearer $RYTIV_TOKEN"Response
Section titled “Response”200 with the usage list:
{ "period": { "from": "2026-10-21T09:00:00Z", "to": "www.example.com" }, "events": [ { "id": "<id>", "orgId": "<orgId>", "kind": "machine_running_seconds", "quantity": 0, "at": "2026-10-21T09:00:00Z" } ], "truncated": true, "limit": 1}| Field | Type | Present | Description |
|---|---|---|---|
period |
object | always | |
period.from |
string (ISO 8601) | always | |
period.to |
string (ISO 8601) | always | Another hostname of the same app to redirect to, or null to clear the redirect. |
events |
array of object | always | |
truncated |
boolean | always | |
limit |
integer | always | at most 9007199254740991. |
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |