Promoat.Partner API

Start here

Credits & pricing

Everything is pay-per-use in prepaid credits. Instant calls charge once; video jobs reserve their quote up front, and the quote is a ceiling. Every number on this page is computed from the live price table.

Current price table: 2026-09-30. Every quote, estimate, and video response carries it as price_table_version, so you can tell which prices a number was computed with.

Buying credits

Credits are prepaid from the billing page in your dashboard. The default purchase is one pack:

$19.991,499 credits on the current tier
  • If you start a checkout without choosing an amount, you buy the $19.99 pack. You can still pick a larger amount.
  • How many credits $19.99 buys depends on your account's purchase tier: 1,499 on the current tier, and 1,738 on the earlier tier that older accounts keep. Checkout shows your exact number before you pay.
  • What a job costs in credits is the same on every tier — only the price you pay per credit differs.

For scale: one pack covers about 11 fifteen-second talking heads at 768P, or 11 fifteen-second scene videos.

Price list

Flat-rate operations (charged instantly):

OperationCredits
POST /charactersfree
POST /characters/{id}/regenerate4
POST /images/first-frame4
POST /voices — clonefree for your first clone (once per account), 30 after that
POST /voices/{id}/reclonefree if the old voice expired, 30 if it still works
POST /voices — library (studio) voicefree
POST /tts10 per started 1,000 characters (min 10)
POST /videos/estimate, POST /videos/scene-plan, status polls, listsfree
Dynamic captions add-on (talking head)10

Video generation, per second of output

ResolutionTalking headScenes — reference modeScenes — text mode
480P5 / s5 / s2.5 / s
768P8 / s8 / s4 / s
1080P16 / s16 / s8 / s

768P is the default. A video's quote is a list of lines; each has a kind:

Line kindWhat it is
generationBilled seconds × the per-second rate above.
first_frameOne image (4) when the job makes its own opening frame — dropped when you pass first_frame_url or first_frame_asset_id.
reference_allowanceScenes in reference mode: a small per-clip amount that grows with the number of scene photos.
transcriptionTiming the speech (about 1 credit per 20 s of audio).
ttsScript mode only: speech for your script, at the /tts price.
captionsThe dynamic captions add-on (10).
productA fix-sound swap (0).

Worked examples

RequestLinesTotal
15 s talking head, 768P, your audiogeneration 120 + first_frame 4 + transcription 1125
…with your own first framegeneration 120 + transcription 1121
…with dynamic captionsgeneration 120 + first_frame 4 + transcription 1 + captions 10135
5 s talking head, 480Pgeneration 25 + first_frame 4 + transcription 130
15 s scenes, reference mode, 2 scene photosgeneration 120 + first_frame 4 + reference_allowance 6 + transcription 1131
15 s scenes, text modegeneration 60 + transcription 161
15 s silent scenes (voice_mode none)generation 120 + first_frame 4124
TTS, 600 characters—10

Edits are priced the same way — see Video edits.

Billed seconds

  • Audio under 1 s is rejected (AUDIO_TOO_SHORT).
  • Anything from 1 to 5 s is billed as 5 s.
  • Voiced videos are capped at 59.5 s of audio (AUDIO_TOO_LONG); scripts at 4,000 characters. Silent scenes run 5–60 s (target_seconds).

Know the price before you fire

POST /videos/estimate takes the exact same body as POST /videos and returns the credits that call would reserve (it does not need character_id and checks no ids), your live balance, and the lines. It is free and has no side effects. Estimate equals reserve for the same body.

Try itPOST/api/partner/v1/videos/estimatefree
Add your API key in the sidebar to enable this.

Lock the price: expected_credits

Send the quoted number back as expected_credits on POST /videos(and on edits). If the server's quote is higher than that, nothing is queued or charged:

409 Conflict
{ "error": "QUOTE_MISMATCH", "error_code": "QUOTE_MISMATCH", "code": "quote_mismatch",
  "credits_quoted": 125, "message": "…" }

Two billing styles

Instant endpoints charge once, immediately

/characters, /characters/{id}/regenerate, /voices, /tts, and /images/first-frame do the work inside the request and return credits_charged. If the work fails, the charge is refunded.

Video jobs reserve a ceiling, then settle

/videos and the edit endpoints reserve the quote before the job starts and return credits_reserved. The quote is a hard ceiling: you are charged min(actual, reserved) — never more than you were quoted. A failed job is refunded once. A job that goes quiet for 75 minutes is failed with STALE_TIMEOUT and refunded.

The reserve → settle lifecycle (15 s talking head, 768P)
POST /videos            → 200 { "credits_reserved": 125, "price_table_version": "2026-09-30" }
GET  /jobs/…/status     → { "status": "running", "credits_consumed": null }
GET  /jobs/…/status     → { "status": "completed", "credits_consumed": 125 }
Script mode: headroom you can get back

With voice_id + script the speech does not exist yet, so the video lines are quoted on an estimated length (words ÷ 138 per minute, plus 10% headroom; 35% for non-Latin scripts; at most 59.5 s) plus the tts line. The job measures the real speech and charges the lower of the reserve and the real price — the difference goes back to your balance.

Reading a job's cost

credits_consumed on a job is null while queued/running, the actual charge once completed, and 0 on failed (refunded; a recorded partial charge shows instead, if any).

Safe retries: idempotency keys

Send an Idempotency-Key header (1–255 visible ASCII characters) or a client_request_id (uuid) in the body. Optional on /videos, required on the edit endpoints (unless dry_run). Retrying the same body with the same key returns the original job with duplicate: true — nothing is charged twice. Details in Errors & limits.

When you can't afford a call

Every paid endpoint checks your balance first and returns 402 without doing (or charging) anything:

402 Payment Required
{
  "error": "INSUFFICIENT_CREDITS",
  "error_code": "INSUFFICIENT_CREDITS",
  "credits_required": 131,
  "credits_balance": 40,
  "message": "…"
}

credits_required is the quote for this request. Top up via the billing page (default: the $19.99 pack) and retry.

Watching your balance

GET /usage/summary is free and returns the live balance plus job counts for any date range — details in Usage & history.

Try itGET/api/partner/v1/usage/summaryfree
Add your API key in the sidebar to enable this.