Skip to content

Credits and limits

Every render costs credits, and the cost is calculated from your request before it runs — so it is never a surprise after the fact.

Two currencies#

Image and video credits are separate balances. A poster costs us milliseconds of CPU; a 4K minute costs minutes. One shared unit would either make posters absurdly expensive or make video effectively free.

Each balance has two buckets:

BucketWhere it comes fromExpiry
grantedYour plan’s monthly allowanceResets at the start of each period — use it or lose it
topupCredit packs you buyNever expires while your account is open
Granted credits are always spent first. That means the perishable currency burns down before the permanent one, so credits you paid for last as long as possible.

What a render costs#

Images are priced by output megapixels, in bands — the cost is dominated by painting a page, not by the pixels.

Output sizeCredits
Up to 2.5 MP (1080×1080, 1920×1080)1
Up to 9 MP (4K poster)2
Up to 20 MP4
Above 20 MP8
PDF1.5× the image rate

Video is priced per output second, scaled by resolution, frame rate and codec. Minimum 5 credits per video.

ExampleCredits
6-second reel, 1080p306
15-second story, 1080p3015
30-second ad, 1080p6060
30-second ad, 4K3090
Audio-only export (mp3/wav)1

The scale multiplier on stills counts towards megapixels — a 1080×1080 render at scale: 2 is 2160×2160, which is 4.7 MP and therefore 2 credits.

Check before you commit

POST /v1/render/estimate prices a render without running it, and costs nothing. Use it to show cost in your own UI, or to guard a bulk job before it starts.

Hold, settle, refund#

Credits move in three steps, and the order is deliberate.

  1. Hold — when a render is accepted, its cost is moved out of your balance. This is what stops a thousand queued renders against a balance of ten.
  2. Settle — on success, the hold becomes a spend. The balance already reflected it, so nothing further changes.
  3. Refund — on failure or cancellation, the exact credits are returned to the buckets they came from. A refunded grant is still a grant.

This means you are never charged for a render you did not receive, and no action is needed on your side.

Balance
GET /api/credits

{
  "credits": {
    "image": { "granted": 380, "topup": 500, "available": 880, "held": 2 },
    "video": { "granted": 96,  "topup": 250, "available": 346, "held": 15 }
  },
  "grants":    { "imageCredits": 500, "videoCredits": 150 },
  "periodEnd": "2026-09-01T00:00:00.000Z",
  "planCode":  "starter"
}

held is reserved by renders in flight. It has already been deducted from available — it is reported separately so you can explain a temporary dip to a user.

Every movement is recorded in an append-only ledger at GET /api/credits/history, including which render caused it.

Running out#

A render that cannot be afforded returns 402 before any work is done:

402
{
  "success": false,
  "message": "Not enough video credits: this render needs 15, the workspace has 4.",
  "code": "INSUFFICIENT_CREDITS",
  "required": 15,
  "available": 4,
  "creditKind": "video",
  "upgradeRequired": true,
  "upgradeUrl": "https://pixbix.app/dashboard/billing"
}

Do not retry a 402

It will fail identically until credits are added. Surface it to a human, or pause the job queue and alert. Subscribe to credits.low to get warned before you hit zero.

Plan limits#

Separate from credits, plans cap what a single render may ask for. These are checked before credits are held, so hitting one costs nothing.

LimitError code
Max video durationLIMIT_VIDEO_DURATION
Max video resolutionLIMIT_VIDEO_RESOLUTION
Max frame rateLIMIT_VIDEO_FPS
Max image dimensionLIMIT_IMAGE_SIZE
Max still scaleLIMIT_IMAGE_SCALE
Renders queued or running at onceLIMIT_QUEUE_DEPTH
Video rendering not on planFEATURE_VIDEOENABLED
Requests per minuteRATE_LIMIT_EXCEEDED

Concurrent renders is not in that table, and that is deliberate.Your plan’s concurrency is how many of your renders run at the same time — it is a speed limit, not a submission limit. Send a thousand renders on a plan that runs three at a time and all thousand are accepted; three run, the rest sit at queued with a stage telling you why, and each one starts the moment a slot frees. Nothing needs retrying.

LIMIT_QUEUE_DEPTH is the ceiling that does refuse, and only a runaway loop should ever meet it: it means the workspace already holds the most unfinished renders your plan will keep at once. Like the others it clears on its own as the queue drains, so a bulk job that hits it should back off rather than treat it as fatal.

Rendering for free#

Test keys (pk_test_) never consume credits, whatever the plan. They run the same pipeline and produce a real file, always watermarked.

Build, debug and load-test your integration on a test key. Switch to pk_live_ only when the output needs to be usable.