API reference
Base URL https://edengen.ai/v1. JSON in, JSON out. OpenAPI: /v1/openapi.json.
Authentication
Send Authorization: Bearer tk_…. A key acts as its creator inside one workspace. GET /v1/models and GET /v1/tools work without a key.
Endpoints
| Method | Path | What it does |
|---|---|---|
GET | /v1/models | List models with pricing |
GET | /v1/models/{id} | One model |
POST | /v1/estimate | Price a run without spending |
GET | /v1/aliases | List workspace model aliases |
POST | /v1/aliases | Create or change a model alias (owners) |
DELETE | /v1/aliases/{name} | Delete a model alias (owners) |
POST | /v1/takes/{id}/finish | Render the final of an approved draft |
GET | /v1/budgets | Monthly budgets per tag, with this month's spend |
POST | /v1/budgets | Set a monthly budget for a tag (owners) |
DELETE | /v1/budgets | Remove a tag budget (owners) |
GET | /v1/exports | Delivery targets: buckets and OTLP endpoints |
POST | /v1/exports | Add a bucket or OTLP target (owners) |
PATCH | /v1/exports/{id} | Pause or resume a target |
DELETE | /v1/exports/{id} | Remove a target |
POST | /v1/exports/{id}/test | Send your latest take to a target now |
POST | /v1/images/generations | OpenAI-compatible: generate images and wait for them |
POST | /v1/videos | OpenAI-compatible: start a video |
GET | /v1/videos | OpenAI-compatible: list videos |
GET | /v1/videos/{id} | OpenAI-compatible: video status |
DELETE | /v1/videos/{id} | OpenAI-compatible: delete a video |
GET | /v1/videos/{id}/content | OpenAI-compatible: download the MP4 |
POST | /v1/videos/{id}/remix | OpenAI-compatible: remix with a new prompt |
POST | /v1/takes | Create takes |
GET | /v1/takes | List takes, newest first |
GET | /v1/takes/{id} | Get a take |
GET | /v1/takes/{id}/content | Download the file |
POST | /v1/assets | Upload a reference: multipart field file, raw body with X-Filename, or JSON {url} / {take_id} |
GET | /v1/assets | Recent assets |
GET | /v1/assets/{id} | One asset with a fresh signed url |
POST | /v1/uploads | One-time signed PUT URL for a large file (30 min, no API key needed to PUT) |
GET | /v1/elements | Saved characters, products, locations, styles |
POST | /v1/elements | Save reference images as an element |
GET | /v1/elements/{id} | One element |
GET | /v1/projects | Projects with cap, spent and remaining |
POST | /v1/projects | Create a project |
GET | /v1/account | Balance, key limits, live providers |
GET | /v1/usage | Spend for re-billing |
Creating takes
| Field | Type | Notes |
|---|---|---|
model | string | Required. From GET /v1/models. |
prompt | string | Required, 5 to 4000 characters. |
resolution | string | Defaults to the model's default. |
duration | integer | Seconds, video only, one of the model's durations. |
aspect_ratio | string | Video 16:9, 9:16, 21:9, 1:1. Image 16:9, 21:9, 2:3, 1:1, 4:5. |
count | 1, 2 or 4 | Returns a list when above 1. |
project_id | uuid | Defaults to the key's project, then the newest project. |
webhook_url | https URL | Gets take.completed or take.failed. See Webhooks. |
metadata | object | Up to 4 KB, echoed back on the take. |
Headers
| Header | Effect |
|---|---|
Idempotency-Key | Repeat the request with the same key and you get the same takes, charged once. Use it for every retry. |
Prefer: wait=60 | Holds the response until the takes finish, up to 60 s. Without it you get the take queued and poll. |
The take object
{
"id": "lgmog4x1",
"object": "take",
"status": "succeeded", // queued | processing | succeeded | failed
"model": "nano-banana-2.1",
"version": "2.1 (pinned)",
"cost_usd": 0.053,
"refunded": false,
"error": null,
"output": {
"url": "https://edengen.ai/v1/takes/lgmog4x1/content",
"mime_type": "image/png",
"filename": "lgmog4x1_nano-banana-2.1_1K.png"
},
"simulated": false,
"source": "api", // app | api | mcp
"metadata": { "shot": "12A" },
"created_at": "2026-10-18T09:54:11.882Z",
"completed_at": "2026-10-18T09:54:20.804Z",
"timings": { "total_s": 8.9 }
}Model aliases
Give a model and its settings a name your pipelines hardcode, then send that name as model. Change the alias and every key, agent and pipeline follows without a deploy. Settings sent with a request win over the alias. Owners manage aliases in Settings or here.
curl -X POST https://edengen.ai/v1/aliases -H "Authorization: Bearer $TAKES_API_KEY" -H "Content-Type: application/json" \
-d '{"name": "hero-video", "model": "seedance-2.5", "resolution": "1080p", "duration": 10, "aspect_ratio": "21:9"}'
curl -X POST https://edengen.ai/v1/takes -H "Authorization: Bearer $TAKES_API_KEY" -H "Content-Type: application/json" \
-d '{"model": "hero-video", "prompt": "Slow push in on a lighthouse in a storm, no music"}'Budgets by tag
Cap spend per client, campaign or environment. Tag takes with tags or the X-Takes-Tags header, then set a monthly budget for a tag. A take whose tags match is refused with 429 tag_budget before anything is charged when it would pass the budget. Budgets reset on the first of the month (UTC) and count net of refunds.
curl -X POST https://edengen.ai/v1/budgets -H "Authorization: Bearer $TAKES_API_KEY" -H "Content-Type: application/json" \
-d '{"key": "client", "value": "acme", "cap_usd": 500}'Delivery and observability
Add an S3-compatible bucket (AWS S3, Cloudflare R2, Backblaze, Google Cloud Storage interoperability) and every finished take is copied there as prefix/project/take-id_model_resolution.ext with a JSON sidecar of the prompt, model, cost and tags. Add an OTLP/HTTP endpoint and each take arrives as one span with its model, provider, cost, project and tags, refunds included. Deliveries retry with backoff; Settings shows the count and the last error. Secrets are encrypted and never returned.
curl -X POST https://edengen.ai/v1/exports -H "Authorization: Bearer $TAKES_API_KEY" -H "Content-Type: application/json" \
-d '{"kind": "s3", "name": "R2 renders", "endpoint": "https://<account>.r2.cloudflarestorage.com", "bucket": "renders",
"access_key_id": "...", "secret_access_key": "..."}'Draft, then finish
Render low-cost drafts, approve one, then POST /v1/takes/{id}/finish. The final keeps the prompt and framing, moves to the stronger sibling (Seedance 2.0 Mini to Seedance 2.0, Veo 3.1 Fast to Veo 3.1, Nano Banana 2.1 to Pro) at 1080p or 2K, and passes the draft as a reference so the composition holds. Name model or resolution in the body to choose yourself. A repeated call returns the same final and charges once. Agents use the takes_finish tool, which asks above your threshold.
Errors
{ "error": { "type": "budget_error", "code": "over_cap", "message": "Spot would go over its $3 cap ($1.19 spent)..." } }| Status | code | Meaning |
|---|---|---|
| 400 | invalid_request_error codes | Bad model, resolution, duration, format or body. |
| 401 | missing_api_key, invalid_api_key | No key, wrong key, or revoked. |
| 402 | insufficient_balance | The run costs more than the balance. Nothing charged. |
| 403 | forbidden | Producers cannot change caps, top up or create keys. |
| 404 | take_not_found, project_not_found, model_not_found | Not in this workspace. |
| 409 | over_cap, not_ready | Would pass the project cap, or the file is not ready. |
| 422 | idempotency_mismatch | The Idempotency-Key was already used with a different body. |
| 429 | rate_limited, key_cap, tag_budget | Over the key's requests per minute (see Retry-After), its monthly cap, or a tag budget. |
| 503 | overloaded | The service is shedding load. Nothing was charged. Retry after the Retry-After seconds. |
Rate limits
Each key allows 120 requests per minute by default. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining. There is no starting concurrency limit on renders.
Usage for re-billing
curl "https://edengen.ai/v1/usage?from=2026-10-01&to=2026-11-01&group_by=project" -H "Authorization: Bearer $TAKES_API_KEY"