Promoat.Partner API

Start here

Credits & pricing

Credits come from a weekly or monthly plan and are spent per use. 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 and the plan catalog.

Current price table: 2026-10-11. 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 come from a plan, with the same plans and prices as the Promoat app. Pick one on the Plans page of your dashboard and pay at checkout. The credits land within seconds.

Weekly$9.99/wk559 credits / week~7 videos / week
MonthlySave 30%$29.99/mo2,219 credits / month~30 videos / month
Monthly 3.6×Save 35%$99.99/mo7,999 credits / month~109 videos / month
  • Credits are added each time a plan renews, and they never expire. What you don't use rolls over.
  • The plan cards count a video as 73 credits, the price of a one-minute video. The price list below has what each video costs.
  • Credits you already have stay in your balance.
  • What a job costs in credits is the same on every plan. The price list below did not change.

For scale: one Monthly plan covers about 73 fifteen-second talking heads at 768P, or 73 fifteen-second scene videos.

Changing or cancelling a plan

Switch plans on the same Plans page. When a switch starts depends on its direction:

  • A bigger plan or a longer interval starts now. You pay the prorated difference for the rest of the period, and the credits for it are added straight away.
  • A smaller plan or a shorter interval starts at the end of the period. You keep your current plan until then.
  • Cancel in Manage subscription on the dashboard. Your plan runs to the end of the period, then stops. Your credits stay, and you can renew there before the period ends.
FromToStarts
WeeklyMonthlyNow, prorated
WeeklyMonthly 3.6×Now, prorated
MonthlyMonthly 3.6×Now, prorated
MonthlyWeeklyAt the end of the period
Monthly 3.6×WeeklyAt the end of the period
Monthly 3.6×MonthlyAt the end of the period

Manage subscription on the dashboard opens the Promoat billing portal: your plan, card, invoices and billing details. Plan changes and cancelling there follow the same rules.

Credit packs

Need more before your plan renews? Buy credits once. Packs are for subscribers only: they appear on the Plans page once you have a plan.

Small$12.99779 credits
Medium$24.991,499 credits

One-time purchase. Credits you buy never expire.

Embedded partners

The signed billing link (/partner/billing?client_id=…&sig=…) and POST /api/partner/v1/billing/checkout-session work as before. They sell credits once, with no plan.

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, by length

A video's price depends only on its length: the same at every resolution, in both scene modes and with or without scene photos. It includes the opening frame and the speech timing.

LengthVoiced (talking head or scenes)Silent scenes
5 s2118
10 s2421
15 s3027
20 s3330
30 s4438
45 s6556
60 s7365

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

Line kindWhat it is
generationThe video itself, by its length (the table above, less the lines below).
first_frameThe opening frame (12) when the job makes its own — dropped when you pass first_frame_url or first_frame_asset_id.
transcriptionTiming the speech (a few credits, voiced videos only).
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 15 + first_frame 12 + transcription 330
…with your own first framegeneration 15 + transcription 318
…with dynamic captionsgeneration 15 + first_frame 12 + transcription 3 + captions 1040
5 s talking head, 480Pgeneration 6 + first_frame 12 + transcription 321
15 s scenes, reference mode, 2 scene photosgeneration 15 + first_frame 12 + transcription 330
15 s scenes, text modegeneration 15 + first_frame 12 + transcription 330
15 s silent scenes (voice_mode none)generation 15 + first_frame 1227
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": 30, "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": 30, "price_table_version": "2026-10-11" }
GET  /jobs/…/status     → { "status": "running", "credits_consumed": null }
GET  /jobs/…/status     → { "status": "completed", "credits_consumed": 30 }
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": 30,
  "credits_balance": 40,
  "message": "…"
}

credits_required is the quote for this request. Add credits on the Plans page: subscribe, move to a bigger plan, or buy a credit pack. Then 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.