Models
Live rates and capabilities are on
GET /v1/models, under this model’s image_pricing block.
Rate card
Multiply by
count for a multi-image request — every image in a request shares the same output size, so the same tier and rate apply to each one.
How the tier is decided
The tier is decided by your output pixels —width × height, after any server-side snapping — not by which size preset name you sent:
- Pass a
sizepreset (e.g.2k_1_1) or explicitwidth/height, and the platform resolves the output pixel count and matches it against the boundary above. - Omit
sizeentirely and the platform defaults to1_5k_1_1(1472×1472 = 2,166,784 px) —standardtier, at 6.5 credits. - Every
1_5k_*preset isstandardtier. The largest,1_5k_3_2(or its1_5k_2_3mirror) at 1824×1216 = 2,217,984 px, is still under the boundary — every ratio at1_5k_*follows. - Every
2k_*and4k_*preset is above the boundary by pixel count.2k_1_1alone is 2048×2048 = 4,194,304 px, well past it — every ratio at2k_*and4k_*follows. - During the current migration, a small number of request shapes still settle on the previous flat per-image rate rather than the tier above. Where that happens the charge is lower than the rate card, never higher, and it is disappearing as the migration completes — so treat the card as the ceiling. If you need the exact figure for a specific request, call
POST /v1/images/estimateand readestimated_cost.amountandbreakdown.size_tierback; the estimate is authoritative for that request and always matches what the generation bills. - Custom
width/heightsnap to the nearest multiple of 32 before the tier check runs — the boundary compares against the snapped pixel count, not the number your ownwidth × heightarithmetic gives you. Both sides always snap to a multiple of 32, so every reachable output is a multiple of 1024 — the boundary itself (2,360,000) is never landed on exactly. The largest reachablestandardoutput is 2,359,296 px; the smallest reachablelargeoutput is 2,365,440 px. - This snap can flip your expected tier near the edge. A
1552×1520request computes to 2,359,040 px by hand (under the boundary — you’d budgetstandard), but snaps to 1568×1536 = 2,408,448 px and billslarge. A1537×1537request computes to 2,362,369 px by hand (over the boundary), but snaps to 1536×1536 = 2,359,296 px and billsstandard. If you’re computing custom dimensions close to the boundary, snap each side to a multiple of 32 yourself before comparing against 2,360,000, or callPOST /v1/images/estimateand readsize_tierback rather than predicting it. - Free: reference images (
reference_image_urls,subjects[],context_images,character_id) and prompt enhancement (enhance_prompt: true). Neither changes which tier you land in, and neither adds a line to the price.
The exact-price guarantee
POST /v1/images/estimatereturns the exact pricePOST /v1/imageswill charge for the identical request body — there is no ceiling-vs-actual gap to reconcile for images.
estimated_cost.breakdown.size_tier(on the estimate) andcost.breakdown.size_tier(on the generation response) name the tier your request billed at —"standard"or"large". It’s a string, not a credit amount — don’t add it to reproduceamount. When your team has a negotiated discount, the breakdown also carriesdiscount_factor: a multiplier already folded intobase, not a separate credit amount, so don’t add that either —basealone equalsamount.- Because the price depends only on your request — output size,
count, and any team discount — and never on post-generation metering, the estimate is exact on every request shape: plain,subjects[], andcontext_imagesalike. - Machine-readable per-tier rates are always available at
GET /v1/modelsunderimage_pricing.tiers[]— read them live rather than hard-coding the numbers above.
How billing works
Admitting the generation places a hold for the full price and reduces your available balance immediately. That hold is also the final charge — nothing about an image’s price depends on what happens after dispatch, so there’s no later reconciliation step the way there is for token-metered video.cost.refunded: true (with amount: 0) is set on a failed generation, meaning the full charge was refunded; if part of a count > 1 batch fails, the difference for the images that didn’t deliver is refunded automatically. A cancelled generation’s hold is released the same way, but the response doesn’t yet reflect that: cost.amount still shows the originally-held amount and refunded is not set — key off the generation’s status field (cancelled), not cost.refunded, to detect a cancellation.
Rates can change
Image rates are DB-driven and may change without anAurous-Version bump — the same mutability asymmetry documented for LLM pricing. Always read the current per-tier rate from GET /v1/models rather than hard-coding the numbers above. Each charged image snapshots the rate in force when it was created — including on an idempotent replay — so the amount you were quoted is the amount you pay.
