Billing
Prepaid credits: what your balance means, where credits come from, how jobs spend them, and how to top up and watch your balance.
Windpaint is prepaid. Your organization holds a balance of credits, every job spends from it, and you add more by buying a top-up. One credit costs $0.05 when you buy it. Check your balance with one call:
{
"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"
}
]
}
}
Credit amounts are decimal strings with two places, such as "0.08". Parse them as decimals, not floats.
Available and held
availableis what you can spend right now.heldis reserved by jobs that are still running. It’s already subtracted fromavailable.
When you submit a job, Windpaint places a hold for its credits_estimate. If available can’t cover it, the submit fails with 402 billing.insufficient_credits and nothing is created. When the job finishes:
| Job ends as | What happens to the hold |
|---|---|
completed | Captured. The credits are spent. |
failed, nsfw, canceled | Released in full. Failed jobs are free. |
Product runs work a little differently. Starting a run checks available against the run’s estimate (and returns 402 if it’s short) but reserves nothing. Each step places its own hold when it starts, so a run can fail partway if your balance is spent elsewhere in the meantime. See Products.
Prices are per output at a resolution tier and are fixed when you submit. See Pricing, and read current prices from GET /v1/generation/models rather than hardcoding them.
Where credits come from
Credits arrive in lots. Each lot has a source and, usually, an expiry. lots in the balance response lists every lot that still has credits; by_source totals them.
| Source | How you get it | Expires |
|---|---|---|
signup | Granted when your account is approved off the waitlist (200 credits). | 30 days after grant |
topup | Bought through Stripe Checkout. | 365 days after payment |
promo | Granted by Windpaint, for example in a promotion. | Set per grant |
plan | Granted for a plan Windpaint has set up for your organization. | End of the plan period |
refund | Granted by Windpaint support to correct a problem. | Set per grant |
adjustment | A manual correction by Windpaint support. | Set per grant |
An expired lot stops being spendable the moment it expires. A background sweep then zeroes it and writes an expire entry to your statement. If a job’s hold is released after the lot it came from has expired, those credits expire too; they don’t come back.
Spend order
Holds draw from your lots in this order:
- The lot that expires soonest.
- Among lots with the same expiry, the oldest.
- Lots that never expire, last.
So signup credits are used before top-up credits, and credits close to expiring are used first.
Buying credits
A top-up is a one-time purchase through Stripe Checkout. The minimum is 100 credits (5,000) per top-up. Bought credits expire 365 days after payment.
In the dashboard, go to Settings → Billing and choose Buy credits. Pick a preset (500, 1,000, 2,500 or 5,000 credits) or enter an amount, and pay on the Stripe page. You’re sent back to the Billing page when payment completes.
Buying credits needs the owner or admin role.
Receipts
Stripe emails a receipt to the address used at checkout. Windpaint doesn’t issue invoices. Your top-up history is on Settings → Billing and at GET /v1/billing/topups.
Low-balance warning
Set a threshold, and Windpaint warns you once when available drops below it:
Or set it on Settings → Billing under Low-balance warning. When your balance crosses below the threshold:
- Windpaint sends an email. By default it goes to every active member of the organization; you can narrow the recipients under Settings → Notifications.
- A
billing.credits_lowevent goes to any account webhook subscribed to it, withavailableandthresholdin itsdata.
The warning fires once per crossing. It re-arms when your balance is back at or above the threshold (after a top-up, for example), and changing the threshold also re-arms it. Send {"low_balance_threshold": null} to turn the warning off.
Statement and usage
Every movement of credits is an entry in your statement, newest first:
curl "https://api.windpaint.ai/v1/billing/ledger?limit=50" \
-H "Authorization: Bearer $WINDPAINT_API_KEY"
Entry kind | Meaning | Sign |
|---|---|---|
grant | A lot was added (signup, top-up, promo and so on). | positive |
hold | A job reserved credits from this lot. Stays as the charge if the job completes. | negative |
release | A held amount came back because the job failed, was flagged or was canceled. | positive |
expire | Credits expired. | negative |
debit | A manual correction by Windpaint support. | negative |
A completed job shows as a hold with no matching release. A job that drew from two lots has one entry per lot. Filter by project_id, since and until to reconcile a project or a period.
For totals, GET /v1/billing/usage returns credits spent and job count per project per day. The dashboard shows the same data on Settings → Usage (7, 30 or 90 days) and the statement on Settings → Billing.
Active holds are on Settings → Billing and at GET /v1/billing/holds?status=held.
What isn’t available
- Self-serve plans or subscriptions. Billing is prepaid top-ups only.
- Invoices. You get Stripe’s payment receipt for each top-up.
- Auto top-up. Top up manually, and use the low-balance warning to know when.
- Spending limits per project or per key. Credits are org-wide; any key with
generation:writecan spend the whole balance. - Refunds through the dashboard. Contact support.