Documentation

From idea to API call.

Write your prompt. Keep the model decisions with us.

Your first request

Create an account and an API key, then send a request. The playground uses the same API with your signed-in account.

Environment variables
export MADEBYCUE_URL="http://localhost:3000"export MADEBYCUE_API_KEY="cue_YOUR_API_KEY"
Create a task · cURL
curl -X POST "$MADEBYCUE_URL/api/v1/tasks" \  -H "Authorization: Bearer $MADEBYCUE_API_KEY" \  -H "Content-Type: application/json" \  -H "Idempotency-Key: my-first-request-001" \  -d '{  "task": "image.generate",  "prompt": "An amber glass bottle on pale stone, soft morning light, room for a headline.",  "aspect_ratio": "16:9",  "reference_images": [    "https://your-site.com/bottle.jpg"  ]}'

New tasks return 202 Accepted. A retry with the same body and idempotency key returns the original task with 200 OK. Generation takes seconds to minutes: poll GET /api/v1/tasks/{id} until status is succeeded, failed, needs_input, or planned (dry runs only). Tasks survive disconnects; nothing is lost if you stop polling.

Response
{  "id": "task_…",  "request_id": "req_…",  "task": "image.generate",  "prompt": "An amber glass bottle on pale stone, soft morning light, room for a headline.",  "output_type": "image",  "status": "queued",  "classification": null,  "request": {    "task": "image.generate",    "prompt": "An amber glass bottle on pale stone, soft morning light, room for a headline.",    "aspect_ratio": "16:9",    "reference_images": [      "https://your-site.com/bottle.jpg"    ]  },  "outputs": [],  "cost": {    "currency": "USD",    "estimated": 0.5,    "charged": 0.5,    "credits_charged": 50  },  "message": "Queued for execution.",  "created_at": "2026-10-01T12:00:00.000Z",  "expires_at": "2026-10-02T12:00:00.000Z"}
JavaScript
// Run on your server; never expose the API key in browser code.const idempotencyKey = crypto.randomUUID(); // Keep this key for retries.const response = await fetch(process.env.MADEBYCUE_URL + "/api/v1/tasks", {  method: "POST",  headers: {    Authorization: "Bearer " + process.env.MADEBYCUE_API_KEY,    "Content-Type": "application/json",    "Idempotency-Key": idempotencyKey,  },  body: JSON.stringify({  "task": "image.generate",  "prompt": "An amber glass bottle on pale stone, soft morning light, room for a headline.",  "aspect_ratio": "16:9",  "reference_images": [    "https://your-site.com/bottle.jpg"  ]}),});const result = await response.json();if (!response.ok) throw new Error(result.error.message);console.log(result.id, result.request_id, result.cost);// Poll GET /api/v1/tasks/{id} until status is succeeded, failed, needs_input, or planned.

Authentication

Pass Authorization: Bearer [REDACTED]. Create and revoke keys in API keys. Keys are hashed at rest and new keys expire after 90 days. Keep them on your server. The playground uses a same-origin Better Auth session.

Every task and log is scoped to the authenticated account. A task ID or request ID alone does not grant access.

Create a task

POST /api/v1/tasks accepts JSON. Pick one of four tasks. There is no public model selector: the router chooses the execution backend.

FieldContract
taskRequired. "image.generate", "image.edit", "video.generate", or "video.edit".
promptRequired. Describe what to create or change, 3–10,000 characters. For video edits, put timing and scope here (“in the first 5 seconds…”).
reference_imagesUp to four HTTPS image URLs for visual guidance. Defaults to an empty list.
aspect_ratioimage.generate only. "1:1", "16:9", or "9:16". Defaults to "16:9". A composition hint, not a guaranteed canvas.
source_imageRequired for image.edit. The image to change. Edits preserve source dimensions.
source_videoRequired for video.edit. The video to change. Output length and aspect follow the source.
start_framevideo.generate only. An image that becomes the exact opening frame.
duration_secondsvideo.generate only. Integer, 1–30. Defaults to 5. A target length; the response reports actuals.
dry_runOptional. When true, runs planning only and returns the plan with status planned. No media, no charge.

Unknown fields are rejected, and so are fields that are meaningless for the chosen task: aspect_ratio on video tasks and duration_seconds on edits return 400 instead of being silently ignored. Send at most 20 KB of JSON. URLs must use HTTPS and a public hostname, with no username or password.

Tasks are charged on acceptance: 50 credits for image tasks ($0.50), 300 for video generation ($3.00), 500 for video edits ($5.00). Failed tasks and needs_input tasks are refunded automatically. Dry runs are free.

Give each input a purpose

References guide the look or subject. Sources are assets to edit. The start frame anchors the opening of a new video. Use the prompt to explain the change you want.

Upload files in three steps using your session or API key: reserve with POST /api/media/request-upload (name, mime, size), PUT the bytes to the returned URL, then confirm with POST /api/media/confirm to get the /api/media/… URL for the task. One PNG/JPEG/WebP/MP4/ WebM up to 20 MB per upload; uploads are private to your account and expire after 24 hours. Linked public videos can be up to 200 MB; linked images up to 20 MB.

Edit an image
{  "task": "image.edit",  "prompt": "Keep the candle and replace the background with warm ivory.",  "source_image": "https://your-site.com/candle.jpg",  "reference_images": [    "https://your-site.com/mood.jpg"  ]}
Generate a video from a frame
{  "task": "video.generate",  "prompt": "A smooth camera move from the product detail to the full scene.",  "start_frame": "https://your-site.com/start.jpg",  "duration_seconds": 5}
Edit a video
{  "task": "video.edit",  "prompt": "Change the background to match the reference while preserving the product and camera movement.",  "source_video": "https://your-site.com/clip.mp4",  "reference_images": [    "https://your-site.com/background.jpg"  ]}

Read, download & delete

GET /api/v1/tasks/{id} returns a task, its submitted request, cost, and expiry. GET /api/v1/tasks returns your latest 30 unexpired tasks in data.

Read task
curl "$MADEBYCUE_URL/api/v1/tasks/task_YOUR_ID" \  -H "Authorization: Bearer $MADEBYCUE_API_KEY"

Succeeded tasks list outputs with download URLs: GET /api/v1/tasks/{id}/outputs/{n} serves the mirrored file with the same authentication. needs_input carries the planner’s question in message; submit a revised task with a new idempotency key.

DELETE /api/v1/tasks/{id} removes the task, its logs, its mirrored outputs, and its backend execution. Delete stops tracking, not spending: already-submitted work is not cancelled or refunded.

Request logs & costs

View Request logs for your requests, status, cost, and time. Select a request to view its submitted JSON. The request ID is returned in both the body and X-Request-Id.

GET /api/v1/logs?limit=20 lists your logs, summary totals, and next_cursor. Pass it as cursor to retrieve the next page. The page size is 1–50. GET /api/v1/logs/{request_id} returns one log with its request, response summary, and events.

cost.estimated is the quoted task price. cost.charged is the USD amount actually charged and cost.credits_charged the matching credit amount; 100 credits = $1. Both drop to zero when a failed task is refunded. Retries create a diagnostic log but no second task or charge.

Authenticated POST attempts are logged, including validation errors, conflicts, and account rate-limit errors. Unauthenticated requests and read requests are not stored. Invalid bodies are discarded; only a safe error summary is retained. Authorization headers, cookies, and API keys are never copied into request logs. Avoid including secrets in prompts or media URLs.

Gone after 24 hours

Tasks and logs stop being readable at their expires_at timestamp. Background cleanup runs every minute and deletes expired database rows, uploaded and mirrored media, and backend executions, including prompts, input URLs, responses, and event details. Actual removal happens on the next successful cleanup run. Idempotent retries do not extend the original task’s expiry.

Credit balances and payment records are separate and do not expire with request logs. Database backups follow the hosting provider’s separate retention policy; deleting active rows does not erase earlier backups.

Errors & retries

Send a unique Idempotency-Key for each new task, then reuse that key and the same body when retrying a failed connection. Keys are 1–128 printable non-space ASCII characters. The idempotency window is 24 hours; after that, the same key can create a new task. If omitted, the server generates a key and cannot deduplicate your retries.

StatusMeaning
400Invalid JSON, fields, or pagination cursor.
401Missing, revoked, expired, or invalid credentials.
402Insufficient credits for the task price. Top up in Billing.
403Untrusted browser origin, or no subscription on task creation.
404Task/log/output not found, not owned by you, or expired.
409Idempotency key already used with a different body.
413 / 415Request larger than 20 KB or not application/json.
429Rate limited. Each account can create 10 tasks/minute; each API key allows 60 requests/minute. Retry after 60 seconds.
500 / 503Temporary service or configuration error. Retry using the same idempotency key.