Costs
Report what providers charged you, so Revenue can show margin.
costs.track
{
"customer_id": "user_123",
"provider": "openrouter",
"model": "anthropic/claude-sonnet-4.5",
"feature_id": "scripts",
"amount_usd": 0.01834,
"units": 5120,
"unit": "tokens",
"properties": { "script_id": "scr_9" },
"idempotency_key": "gen-abc123"
}| Field | Required | Notes |
|---|---|---|
provider | Yes | Lowercase, such as openrouter, fal, dataforseo, firecrawl, cloudinary |
amount_usd | No | What the provider charged, up to six decimals. Send it whenever the provider tells you. |
units, unit | No | With no amount, Revenue prices units with your rate cards. Without a matching card the row is stored as unpriced. |
customer_id | No | Without it the cost counts toward totals but not toward any customer's margin. |
feature_id | No | Ties the cost to a feature, which is what the pricing advisor needs. |
model, properties, timestamp | No | For your own breakdowns. |
{
"id": "6707f1c2a1",
"customer_id": "user_123",
"provider": "openrouter",
"model": "anthropic/claude-sonnet-4.5",
"feature_id": "scripts",
"amount_usd": 0.01834,
"units": 5120,
"unit": "tokens",
"pricing": "reported",
"properties": { "script_id": "scr_9" },
"occurred_at": "2026-10-10T18:00:00.000Z"
}pricing is reported (you sent the amount), rate_card (Revenue priced the units) or unpriced.
costs.batch_track
{ "costs": [ ...up to 500 bodies like the one above ] } returns { "tracked": 3, "amount_usd": 0.0412 }. Use it from a queue or at the end of a long job.
costs.list
{ "customer_id"?, "provider"?, "feature_id"?, "from"?, "to"?, "limit"?, "cursor"? }
costs.rates.list
{} returns every rate card in force, yours and the defaults:
{ "list": [{ "provider": "fal", "model": null, "unit": "seconds", "usd_per_unit": 0.0005, "source": "default" }] }