Docs

Get started

Credits

One balance, shared by the desktop and the API. What spends it, what never does, and what comes back.

Credits are the only unit of spend. One balance per account, and both the desktop and the API draw on it.

Nothing here is charged per user, per project or per seat.

#What a credit does

You spend credits on generations. What one costs depends on what you asked for — a longer video costs more than a shorter one, a denser mesh more than a rough one — and the cost is known before the job runs, not after (or, for a model charged what the job cost, the most it can be — below): the submit's answer carries credits_charged and credits_remaining before a single frame has rendered.

The price rule for an address is published with its contract. GET /v1/models/<address>/openapi.json carries it as x-auray-price, and the ## Price section of /v1/models/<address>/llms.txt says the same thing in a sentence. Neither needs a key.

#A quote that is a hold

Most catalogue models — every one priced by a band or by the token — are charged what the job cost. Their x-auray-price says metered: true, and the quote is a hold: the submit takes the most the request can cost (credits_quoted), the job settles to what it actually cost — never more than the quote — and the rest comes back on its own. A settled read of the job (GET /v1/jobs/{id} with settled: true) says what it finally cost in credits_charged. In the app, Generate says up to for these models, and the job's receipt shows what it holds until it settles, then what it cost. Every other address, ours included, says metered: false: its quote is the charge.

#What never spends

  • Reading anything. Listing models, reading a job, polling a status, listing webhook endpoints.
  • A refused request. Anything caught before inference — wrong scope, malformed body, no credits, ceiling reached — costs nothing.
  • A failed job. If it starts and then fails, the charge is reversed automatically.
  • A cancelled job. What hadn't been made yet comes back — per product, in the settlement table. A catalogue model's job is the exception: it cannot be stopped once it starts. In the desktop its button says Stop watching, which is what it does — the job finishes and is charged for what it delivers.
  • Downloading what you made. Asking for a job's signed asset URLs costs no credits; it counts the files' size, in whole megabytes, against the egress rate-limit bucket — a daily allowance that depends on your plan, reported in the answer as megabytes_charged — which is why the download route is separate from the status poll. The bucket counts the signing, once per call, not the fetch: a signed link can be fetched again until it expires, and asking for the links again counts the size again.

#Monthly grants

PlanPer monthCredits
Free$050
Pro$502,000
Max$1507,000
Ultimate$50025,000

Credits arrive every month. On a monthly plan they come with each payment; on a plan paid by the year you pay once, and they arrive every month of that year, from the day you pay. The numbers above are read from the same table the wallet itself reads; they cannot drift from what you are charged.

#What a month's credits make

An estimate, counted from the same price rules the submit charges by and from what each plan can run — images in the largest batch one job makes, a clip at the cheapest price, a song of a minute. Every plan that runs Photos, Video, Music or 3D runs the whole of it. Only those four are counted; every other model's address publishes its own price rule, as above. The same lines sit under every paid plan on Pricing.

PlanExampleCredits eachEstimate a month
FreeBatches of 4 images at 1K7About 7
5-second clips5About 10
60-second songs17About 2
Textured 3D models13About 3
ProBatches of 4 images at 1K7About 285
5-second clips5About 400
60-second songs17About 117
Textured 3D models13About 153
MaxBatches of 4 images at 1K7About 1,000
5-second clips5About 1,400
60-second songs17About 411
Textured 3D models13About 538
UltimateBatches of 4 images at 1K7About 3,571
5-second clips5About 5,000
60-second songs17About 1,470
Textured 3D models13About 1,923

#Passes

A pass is unlimited use of one model for a day or a week from payment, one job at a time, without spending credits. Where one is on sale, it is bought once in the app and never renews; buying it again adds its time after the one you hold. Each pass works where it says — the app, the API, MCP — and covers the jobs it lists; a job it does not cover is treated as if you held no pass. A pass for a catalogue model runs that model on any plan, Free included.

GET /v1/me lists them in passes: which model, until when, where each works (doors), what it covers (covers, and covers_lines in words), whether a job of it is running, and whether your plan runs its jobs (runs_on_plan). A job a pass paid for costs nothing, and two answers say so — the submit's answer on queue.auray.run (credits_charged: 0) and GET /v1/jobs/{id}:

"coverage": { "by": "pass", "pass": "seedance-2-5" }

The submit's answer on queue.auray.run also says when a pass of yours for the model did not pay for a job it charged — {"by": null, "miss": {"pass": "video", "why": "door"}}, why being door (the pass does not work the way the job was sent) or shape (it does not cover a job like this one). A run on auray.run, and MCP's run_model, answers the job's output, which says neither: read GET /v1/jobs/{id} with its request_id to see what paid.

A pass takes a job at a time. Through the API and MCP, a second job the pass covers, sent before the first finishes, is refused 429 pass_busy with a Retry-After, and nothing is charged; in the app it waits its turn. A job the pass does not cover is not held back by it. Send X-Auray-Covered-Only: 1 with a submit to run it only if a pass or a promotion pays for it: a job neither pays for is refused 409 not_covered, uncharged — or, where your plan runs the model only through a pass, refused as the plan refuses it (model_not_in_plan, pass_does_not_cover).

#Ceilings

A key can carry its own monthly cap, separate from the balance. Once that key has spent it in a calendar month (UTC), it stops generating until the next month begins, and every other key keeps working.

Worth setting on anything you do not fully control.

#Watching the balance

curl https://api.auray.ai/v1/me \
  -H "Authorization: Bearer $AURAY_API_KEY"
200 OK
{
  "object": "account",
  "id": "86e97633-…",
  "plan": "ultimate",
  "credits": { "balance": 38807, "monthly_allowance": 5000, "period": "2026-09" },
  "key": { "id": "55oy2jFo5cmq", "scopes": ["jobs:read", "assets:read", "photo:write"], "credit_ceiling": 500, "credits_spent_period": 332 },
  "request_id": "961dd3b6-59b4-4e26-bb8b-e4c28f1cbf96"
}
Spend over the period, by product, by origin and by key
curl https://api.auray.ai/v1/usage \
  -H "Authorization: Bearer $AURAY_API_KEY"
200 OK, abridged
{
  "object": "usage",
  "period": "2026-09",
  "credits": { "balance": 38807, "monthly_allowance": 5000, "spent_this_period": 572, "refunded_this_period": 24, "net_this_period": 548 },
  "by_product": [
    { "product": "photo", "origin": "api", "spent": 364, "refunded": 0, "jobs": 91, "net": 364 },
    { "product": "photo", "origin": "app", "spent": 22, "refunded": 0, "jobs": 4, "net": 22 },
    { "product": "chat", "origin": "api", "spent": 30, "refunded": 24, "jobs": 3, "net": 6 }
  ],
  "keys": [
    { "object": "api_key", "id": "…", "key_id": "55oy2jFo5cmq", "name": "…", "credit_ceiling": 500, "credits_spent_period": 332, "last_used_at": "…", "revoked_at": null }
  ],
  "keys_truncated": false,
  "request_id": "…"
}

origin tells the desktop's spend (app) apart from your code's (api); both are the same balance. keys lists your secret keys, most recently used first, up to a hundred of them; keys_truncated is true when you hold more.

When the balance cannot cover a request, it is refused with insufficient_credits before anything runs, and the body says how many were needed.

#Rate limits are a separate thing

Running out of credits and going too fast are different refusals, and they look different on purpose.

Five buckets — read, write, generate, interactive (chat and language-model calls) and egress — refill continuously, and every response reports where you stand in both RateLimit-* and X-RateLimit-* headers. Hitting one answers 429 with a Retry-After; it is about pace, not about money, and waiting fixes it.

See Errors for both families in full.

Start typing to search every page of the documentation.

Up arrow Down arrow to moveEnter to openEscape to close