API
One credit balance powers the studio and the API — the same ledger, the same prices, two front doors. Keys are issued from your dashboard, shown once, and stored only as a hash.
Authentication
Authorization: Bearer sk_live_...
Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. A 429 also carries Retry-After.
Create a generation
Returns 202 immediately with the credits held and an ETA. Generation is asynchronous: poll the job, or cancel it. Pass an Idempotency-Key and a retried request will never produce a second billed job.
curl https://sedance.app/api/v1/generations \
-H "Authorization: Bearer $SEDANCE_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.5",
"prompt": "One continuous take through a night market, camera rising over the stalls",
"resolution": "1080p",
"duration_sec": 30,
"aspect_ratio": "16:9",
"confirm_cost": true
}'
{ "id": "gen_...", "status": "reserved", "credits_held": 7179, "eta_seconds": 210 }confirm_cost is required for jobs above the model’s confirmation threshold. Without it the call returns 400 confirmation_required and the exact price, so a client can prompt before spending.
Poll it
Match your poll interval to the job. A 30-second generation should start at 10s intervals, not 3s — polling a long job aggressively wastes quota and can trip provider rate limits.
curl https://sedance.app/api/v1/generations/gen_... \
-H "Authorization: Bearer $SEDANCE_API_KEY"
{
"id": "gen_...",
"status": "succeeded",
"output_url": "https://cdn.sedance.app/generations/gen_.../output.mp4",
"credits_charged": 7179,
"latency_ms": 214300
}Python
import os, time, requests
API = "https://sedance.app/api/v1"
headers = {"Authorization": f"Bearer {os.environ['SEDANCE_API_KEY']}"}
job = requests.post(f"{API}/generations", headers=headers, json={
"model": "seedance-2.5",
"prompt": "One continuous take through a night market",
"resolution": "1080p",
"duration_sec": 30,
"confirm_cost": True,
}).json()
while True:
time.sleep(10)
state = requests.get(f"{API}/generations/{job['id']}", headers=headers).json()
if state["status"] in ("succeeded", "failed", "rejected", "expired"):
break
print(state.get("output_url") or state["error"])TypeScript
const api = "https://sedance.app/api/v1";
const headers = {
Authorization: `Bearer ${process.env.SEDANCE_API_KEY}`,
"Content-Type": "application/json",
};
const created = await fetch(`${api}/generations`, {
method: "POST",
headers: { ...headers, "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({
model: "seedance-2.5",
prompt: "One continuous take through a night market",
resolution: "1080p",
duration_sec: 30,
confirm_cost: true,
}),
}).then((r) => r.json());
let job = created;
while (!["succeeded", "failed", "rejected", "expired"].includes(job.status)) {
await new Promise((r) => setTimeout(r, 10_000));
job = await fetch(`${api}/generations/${created.id}`, { headers }).then((r) => r.json());
}Other endpoints
GET /api/v1/generations— paginated list of your jobs.DELETE /api/v1/generations/:id— cancel a job that has not finished. Refunds in full.GET /api/v1/models— the registry: capabilities, plan gates, latency, and credit rates per resolution. Unverified vendor claims are listed separately, so you can decide what to trust.GET /api/v1/credits— balance, its breakdown, plan limits and today’s spend against the daily ceiling.
Errors
Always the same shape: { error: { type, code, message, docs_url } }. Switch on code — it is stable.
| 400 | parameter_invalid | The request does not match the model’s capabilities. Nothing is charged. |
| 400 | confirmation_required | Cost is above the confirmation threshold. Resend with confirm_cost: true. |
| 401 | unauthorized | Missing or invalid API key. |
| 402 | insufficient_credits | Balance is short. The shortfall is in error.meta. |
| 403 | duration_requires_upgrade | The plan does not cover this duration, resolution or model. |
| 409 | concurrency_limit | Too many generations already running for the plan. |
| 422 | moderation_rejected | A content check rejected the prompt, an asset or the output. Refunded. |
| 429 | rate_limited | Rate limit exceeded. Retry-After is set. |
| 503 | provider_unavailable | No healthy provider took the job. Refunded. |
Limits and price
- Concurrency follows your plan: 2 on Starter, 5 on Pro.
- Pay-as-you-go is $0.012 per credit, with volume tiers. Packs never expire — see pricing.
- 6 models are exposed. Never hardcode one: read
/api/v1/models, because this family ships fast and ids change.