Account
Billing Read your credit balance, statement, holds and usage; set the low-balance warning; and buy credits through Stripe Checkout.
Billing endpoints cover your organization’s prepaid credits. How credits, holds and expiry work is explained in Billing .
All billing endpoints return {"data": ...}. Credit amounts are decimal strings with two places, such as "612.40".
Your current balance, broken down by source and by lot.
Permission: billing:read
available string
Credits you can spend now. Already excludes held.
held string
Credits reserved by jobs still running.
by_source object[]
Spendable credits totaled per source.
next_expiry string | null
When the soonest-expiring lot expires, or null if nothing expires.
next_expiry_amount string | null
Credits left in that lot.
lots object[]
Every unexpired lot with credits left, in spend order.
Request
curl
curl https://api.windpaint.ai/v1/billing/balance \
-H "Authorization: Bearer $WINDPAINT_API_KEY "
Response
200
{
"data" : {
"organization_id" : "c3a1e8f2-6b4d-4e0a-8f1c-2d7b9e5a1c33" ,
"available" : "612.40" ,
"held" : "4.00" ,
"by_source" : [
{ "source" : "signup" , "remaining" : "112.40" },
{ "source" : "topup" , "remaining" : "500.00" }
],
"next_expiry" : "2026-10-21T09:02:11.540118Z" ,
"next_expiry_amount" : "112.40" ,
"lots" : [
{
"id" : "0b6c3d2e-1f4a-4b5c-9d8e-7f6a5b4c3d2e" ,
"source" : "signup" ,
"amount" : "200.00" ,
"remaining" : "112.40" ,
"expires_at" : "2026-10-21T09:02:11.540118Z" ,
"reason" : "Launch signup credit" ,
"created_at" : "2026-09-21T09:02:11.540118Z"
},
{
"id" : "7e8f9a0b-1c2d-4e3f-8a5b-6c7d8e9f0a1b" ,
"source" : "topup" ,
"amount" : "500.00" ,
"remaining" : "500.00" ,
"expires_at" : "2027-10-02T16:45:30.118204Z" ,
"reason" : "Credit top-up" ,
"created_at" : "2026-10-02T16:45:30.118204Z"
}
]
}
}
Your statement: every movement of credits, newest first.
Permission: billing:read
project_id string
Only entries for this project (UUID). Grants and expiries have no project, so they’re excluded when you filter.
since string
ISO 8601 timestamp. Entries at or after this time.
until string
ISO 8601 timestamp. Entries before this time.
total integer
Entries matching your filters across all pages. Sits next to data.
Request
curl
curl "https://api.windpaint.ai/v1/billing/ledger?since=2026-10-01T00:00:00Z&limit=50" \
-H "Authorization: Bearer $WINDPAINT_API_KEY "
Response
200
{
"data" : [
{
"id" : "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" ,
"created_at" : "2026-10-04T15:12:40.336021Z" ,
"kind" : "hold" ,
"amount" : "-4.00" ,
"source" : "signup" ,
"grant_id" : "0b6c3d2e-1f4a-4b5c-9d8e-7f6a5b4c3d2e" ,
"project_id" : "5b0f6c1e-8d2a-4f3b-9e71-0c4d2a9b7e15" ,
"job_id" : "f1e2d3c4-b5a6-4978-8a6b-5c4d3e2f1a0b" ,
"workflow_run_id" : null ,
"description" : null
},
{
"id" : "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e" ,
"created_at" : "2026-10-02T16:45:30.118204Z" ,
"kind" : "grant" ,
"amount" : "500.00" ,
"source" : "topup" ,
"grant_id" : "7e8f9a0b-1c2d-4e3f-8a5b-6c7d8e9f0a1b" ,
"project_id" : null ,
"job_id" : null ,
"workflow_run_id" : null ,
"description" : "Credit top-up"
}
],
"total" : 37
}
Credit holds placed by generation jobs, newest first. Each job has one hold.
Permission: billing:read
status string
held (job still running), captured (job completed and was charged) or released (job failed, was flagged or canceled). Omit for all.
Request
curl
curl "https://api.windpaint.ai/v1/billing/holds?status=held" \
-H "Authorization: Bearer $WINDPAINT_API_KEY "
Response
200
{
"data" : [
{
"id" : "c3d4e5f6-a7b8-4c9d-8e0f-1a2b3c4d5e6f" ,
"job_id" : "f1e2d3c4-b5a6-4978-8a6b-5c4d3e2f1a0b" ,
"workflow_run_id" : null ,
"project_id" : "5b0f6c1e-8d2a-4f3b-9e71-0c4d2a9b7e15" ,
"status" : "held" ,
"amount" : "4.00" ,
"captured" : null ,
"created_at" : "2026-10-04T15:12:40.336021Z" ,
"settled_at" : null
}
]
}
Credits charged and jobs completed, per project per day (UTC), newest day first. Only completed jobs count. Not paginated.
Permission: billing:read
since string
ISO 8601 timestamp. Only jobs that finished at or after this time. Omit for all time.
Request
curl
curl "https://api.windpaint.ai/v1/billing/usage?since=2026-09-04T00:00:00Z" \
-H "Authorization: Bearer $WINDPAINT_API_KEY "
Response
200
{
"data" : [
{
"project_id" : "5b0f6c1e-8d2a-4f3b-9e71-0c4d2a9b7e15" ,
"day" : "2026-10-04" ,
"credits" : "16.32" ,
"jobs" : 14
},
{
"project_id" : "1d2c3b4a-5e6f-4a7b-8c9d-0e1f2a3b4c5d" ,
"day" : "2026-10-04" ,
"credits" : "0.80" ,
"jobs" : 10
}
]
}
Read the low-balance warning threshold.
Permission: billing:read
low_balance_threshold string | null
Warn when available drops below this. null means the warning is off.
low_balance_notified_at string | null
When the current warning fired. null means it’s armed (your balance is at or above the threshold, or no warning has fired yet).
Request
curl
curl https://api.windpaint.ai/v1/billing/settings \
-H "Authorization: Bearer $WINDPAINT_API_KEY "
Response
200
{
"data" : {
"low_balance_threshold" : "100.00" ,
"low_balance_notified_at" : null
}
}
Set or clear the low-balance threshold. When available falls below it, Windpaint emails the organization and fires the billing.credits_low webhook event once. Saving re-arms the warning and checks your current balance right away, so a threshold above your balance fires immediately.
Permission: billing:write
low_balance_threshold number | string | null required
Credits, zero or more. null turns the warning off.
Returns the settings after the change, in the same shape as GET /v1/billing/settings.
Request
curl
curl -X PUT https://api.windpaint.ai/v1/billing/settings \
-H "Authorization: Bearer $WINDPAINT_API_KEY " \
-H "Content-Type: application/json" \
-d '{"low_balance_threshold": 100}'
Response
200
{
"data" : {
"low_balance_threshold" : "100.00" ,
"low_balance_notified_at" : null
}
}
Errors: 422 for a negative threshold.
Current top-up price and limits. Read these instead of hardcoding them.
Permission: billing:read
usd_per_credit string
Price of one credit in US dollars.
expiry_days integer
Days bought credits stay usable after payment.
Request
curl
curl https://api.windpaint.ai/v1/billing/topups/quote \
-H "Authorization: Bearer $WINDPAINT_API_KEY "
Response
200
{
"data" : {
"usd_per_credit" : "0.05" ,
"min_credits" : 100 ,
"max_credits" : 100000 ,
"expiry_days" : 365 ,
"currency" : "usd"
}
}
Your top-ups, newest first, including pending and expired checkouts.
Permission: billing:read
Request
curl
curl "https://api.windpaint.ai/v1/billing/topups?limit=10" \
-H "Authorization: Bearer $WINDPAINT_API_KEY "
Response
200
{
"data" : [
{
"id" : "4d5e6f70-8192-4a3b-bc4d-5e6f708192a3" ,
"created_at" : "2026-10-02T16:44:58.902114Z" ,
"credits" : "500.00" ,
"amount_cents" : 2500 ,
"currency" : "usd" ,
"status" : "paid" ,
"paid_at" : "2026-10-02T16:45:30.118204Z"
}
]
}
Start a Stripe Checkout session to buy credits. Send the user to checkout_url. Credits are added when Stripe confirms payment; poll GET /v1/billing/topups or the balance to see it land.
Permission: billing:write
credits integer required
Credits to buy, between min_credits and max_credits from the quote (100 to 100,000 today).
success_url string
Where Stripe sends the user after paying. Defaults to the dashboard’s Billing page.
cancel_url string
Where Stripe sends the user if they cancel. Defaults to the dashboard’s Billing page.
Returns 201:
topup object
The new top-up, status: "pending". Same fields as in GET /v1/billing/topups.
checkout_url string
Stripe-hosted payment page.
Request
curl
curl -X POST https://api.windpaint.ai/v1/billing/topups \
-H "Authorization: Bearer $WINDPAINT_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"credits": 1000,
"success_url": "https://example.com/billing/done",
"cancel_url": "https://example.com/billing"
}'
Response
201
{
"data" : {
"topup" : {
"id" : "8e9f0a1b-2c3d-4e5f-8a7b-9c0d1e2f3a4b" ,
"created_at" : "2026-10-04T15:01:44.208311Z" ,
"credits" : "1000.00" ,
"amount_cents" : 5000 ,
"currency" : "usd" ,
"status" : "pending" ,
"paid_at" : null
},
"checkout_url" : "https://checkout.stripe.com/c/pay/cs_live_..."
}
}
422
{
"error" : {
"code" : "request.validation_failed" ,
"message" : "A top-up must be between 100 and 100000 credits." ,
"details" : { "credits" : 50 , "min" : 100 , "max" : 100000 },
"request_id" : "59630881.9f1b3d"
}
}
Errors: 422 for an amount outside the limits, 503 if the payment provider can’t start checkout (the top-up is recorded as expired; nothing is charged).