Qulture API
DocsAPI referencePlaygroundPricingConnectors
Sign in
Qulture API

The Qulture Studio API: AI video and images from your own app.

Build

  • Docs
  • API reference
  • Playground
  • Changelog

Account

  • Pricing
  • Console
  • Connectors

Qulture

  • Qulture Studio
  • Support
  • Terms
  • Privacy

© 2026 Qulture

Get started

  • Introduction
  • Quickstart
  • Authentication

Guides

  • Making videos
  • Images
  • Jobs & polling
  • Webhooks

Reference

  • Pricing & billing
  • Rate limits
  • Errors
  • API reference

More

  • Changelog
  • FAQ
Console & API keys PlaygroundAI ChatGPT & Claude (MCP)

Reference

API reference

Every endpoint, parameter and response.

Generated from the OpenAPI 3.1 spec — import it into Postman, Insomnia or any code generator. Base URL: https://qulture-webapi-staging-381114038302.us-central1.run.app. Fields marked * are required.

Account

Who the key belongs to and its API balance.

  • GET/api/v1/developer/me
  • GET/api/v1/studio/me

Check your API key

GET/api/v1/developer/meTry it →

Returns the key's owner, which key was used, who pays (payer) and the API balance (billing.balance_usd). The quickest way to test a key. credits and plan are the Studio plan (used by connector keys).

Request
curl https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/developer/me \
  -H "Authorization: Bearer $QULTURE_API_KEY"
Response 200
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": {
      "user": {
        "id": "172a9b77-06a8-491e-967c-8c245368de28",
        "username": "studiotest",
        "name": "Studio Test"
      },
      "credits": 6,
      "plan": "free",
      "key": {
        "id": "1a976eb1-46bf-44a6-b49a-6254abb5b4ad",
        "name": "My app",
        "prefix": "qk_live_ULnO"
      },
      "billing": {
        "balance_usd": 24.5,
        "currency": "usd"
      },
      "payer": "api_balance"
    }
  }
}

Errors: 401 Missing, invalid or revoked API key · 429 Rate limited: 60 requests/minute per key. All codes

Studio plan, credits and limits

GET/api/v1/studio/meTry it →

Studio plan credits, next refill, plan limits and the credit price list. These apply to connector (MCP) keys; API keys pay from the API balance (see GET /developer/me).

Request
curl https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/me \
  -H "Authorization: Bearer $QULTURE_API_KEY"

Errors: 401 Missing, invalid or revoked API key · 429 Rate limited: 60 requests/minute per key. All codes

Billing

Prices and your API balance. GET /developer/pricing is public; the other billing endpoints are used by the Console and need the signed-in dashboard session — they can't be called with an API key.

  • GET/api/v1/developer/pricing
  • GET/api/v1/developer/billing
  • GET/api/v1/developer/billing/ledger
  • POST/api/v1/developer/billing/checkout
  • PUT/api/v1/developer/billing/auto-recharge
  • POST/api/v1/developer/billing/portal

API prices

No key needed
GET/api/v1/developer/pricingTry it →

The pay-as-you-go price list in USD, top-up limits and the default concurrency limit. Public: no key needed.

Request
curl https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/developer/pricing \
  -H "Authorization: Bearer $QULTURE_API_KEY"
Response 200
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": {
      "currency": "usd",
      "prices": {
        "video_draft_per_second": 0.1,
        "video_standard_per_second": 0.18,
        "video_pro_per_second": 0.26,
        "audio_per_second": 0.02,
        "image_flash": 0.06,
        "image_pro": 0.12,
        "recap": 0.3,
        "story_assembly": 0.05,
        "edit_render_per_minute": 0.05,
        "enhance_per_minute": 0.05,
        "character": 0.1
      },
      "min_topup_usd": 5,
      "max_topup_usd": 5000,
      "topup_presets_usd": [
        10,
        25,
        100
      ],
      "default_concurrency": 20
    }
  }
}

Balance and billing settings

Dashboard session only
GET/api/v1/developer/billingConsole →

**Dashboard session only; not callable with an API key** (an API key gets 403 developer_scope_denied). API balance, status, running generations vs. the concurrency limit, auto-recharge, lifetime totals, 30 days of spend and the latest 20 ledger entries.

Response 200
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": {
      "balance_usd": 24.5,
      "currency": "usd",
      "status": "active",
      "concurrency_limit": 20,
      "running": 1,
      "auto_recharge": {
        "enabled": true,
        "threshold_usd": 10,
        "amount_usd": 25,
        "has_payment_method": true,
        "card": {
          "brand": "visa",
          "last4": "4242"
        },
        "last_error": null
      },
      "low_balance_usd": 5,
      "owed_usd": 0,
      "frozen_usd": 0,
      "lifetime": {
        "topups_usd": 25,
        "spend_usd": 0.5,
        "refunds_usd": 0
      },
      "spend_30d": [
        {
          "date": "2026-10-29",
          "spend_usd": 0.5,
          "topups_usd": 25
        }
      ],
      "ledger": [
        {
          "id": "0b8a3c1e-5d2f-4b61-9a77-3e4c2f1d9a01",
          "kind": "charge",
          "amount_usd": -0.5,
          "balance_after_usd": 24.5,
          "reference": "job:3f0c…:charge",
          "job_id": "8d67563e-bbaf-4357-9380-04c2fe602203",
          "image_id": null,
          "key_id": "1a976eb1-46bf-44a6-b49a-6254abb5b4ad",
          "key_prefix": "qk_live_ULnO",
          "description": "Video · Draft · 5 s",
          "created_at": "2026-10-29T00:20:00Z"
        }
      ],
      "billing_enabled": true,
      "portal_available": true,
      "prices": {
        "video_draft_per_second": 0.1,
        "video_standard_per_second": 0.18,
        "video_pro_per_second": 0.26,
        "audio_per_second": 0.02,
        "image_flash": 0.06,
        "image_pro": 0.12,
        "recap": 0.3,
        "story_assembly": 0.05,
        "edit_render_per_minute": 0.05,
        "enhance_per_minute": 0.05,
        "character": 0.1
      }
    }
  }
}

Errors: 401 Missing, invalid or revoked API key · 403 Not allowed: scope, Studio disabled, or account suspended (`developer_account_suspended`, e.g. after a refunded or disputed top-up). All codes

Billing history

Dashboard session only
GET/api/v1/developer/billing/ledgerConsole →

**Dashboard session only; not callable with an API key** (an API key gets 403 developer_scope_denied). Every charge, top-up and adjustment on the API balance, newest first.

Parameters

NameInTypeDescription
limitqueryinteger
offsetqueryinteger
kindquerytopup | charge | refund | adjustment | promo | auto_recharge | stripe_refund | dispute | dispute_reversalOnly entries of this kind.
Response 200
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": {
      "items": [
        {
          "id": "0b8a3c1e-5d2f-4b61-9a77-3e4c2f1d9a01",
          "kind": "charge",
          "amount_usd": -0.5,
          "balance_after_usd": 24.5,
          "reference": "job:3f0c…:charge",
          "job_id": "8d67563e-bbaf-4357-9380-04c2fe602203",
          "image_id": null,
          "key_id": "1a976eb1-46bf-44a6-b49a-6254abb5b4ad",
          "key_prefix": "qk_live_ULnO",
          "description": "Video · Draft · 5 s",
          "created_at": "2026-10-29T00:20:00Z"
        }
      ],
      "total": 1
    }
  }
}

Errors: 401 Missing, invalid or revoked API key · 403 Not allowed: scope, Studio disabled, or account suspended (`developer_account_suspended`, e.g. after a refunded or disputed top-up). All codes

Add funds (Stripe Checkout)

Dashboard session only
POST/api/v1/developer/billing/checkoutConsole →

**Dashboard session only; not callable with an API key** (an API key gets 403 developer_scope_denied). Starts a Stripe Checkout payment for amount_usd (between min_topup_usd and max_topup_usd). Redirect the user to url; they come back to the Console with ?topup=success or ?topup=cancelled. The card is saved for auto-recharge. Funds are added when Stripe confirms the payment.

Body (JSON)

FieldTypeDescription
amount_usd *number
return_urlstring
Response 200
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": {
      "url": "https://checkout.stripe.com/c/pay/cs_…",
      "session_id": "cs_…"
    }
  }
}

Errors: 400 Amount out of range · 401 Missing, invalid or revoked API key · 403 Not allowed: scope, Studio disabled, or account suspended (`developer_account_suspended`, e.g. after a refunded or disputed top-up). All codes

Auto-recharge settings

Dashboard session only
PUT/api/v1/developer/billing/auto-rechargeConsole →

**Dashboard session only; not callable with an API key** (an API key gets 403 developer_scope_denied). When the balance falls below threshold_usd, charge the saved card amount_usd. Enabling needs a saved card (make one top-up first). Returns the billing object.

Body (JSON)

FieldTypeDescription
enabled *boolean
threshold_usd *number
amount_usd *number
Response 200
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": {
      "balance_usd": 24.5,
      "currency": "usd",
      "status": "active",
      "concurrency_limit": 20,
      "running": 1,
      "auto_recharge": {
        "enabled": true,
        "threshold_usd": 10,
        "amount_usd": 25,
        "has_payment_method": true,
        "card": {
          "brand": "visa",
          "last4": "4242"
        },
        "last_error": null
      },
      "low_balance_usd": 5,
      "owed_usd": 0,
      "frozen_usd": 0,
      "lifetime": {
        "topups_usd": 25,
        "spend_usd": 0.5,
        "refunds_usd": 0
      },
      "spend_30d": [
        {
          "date": "2026-10-29",
          "spend_usd": 0.5,
          "topups_usd": 25
        }
      ],
      "ledger": [
        {
          "id": "0b8a3c1e-5d2f-4b61-9a77-3e4c2f1d9a01",
          "kind": "charge",
          "amount_usd": -0.5,
          "balance_after_usd": 24.5,
          "reference": "job:3f0c…:charge",
          "job_id": "8d67563e-bbaf-4357-9380-04c2fe602203",
          "image_id": null,
          "key_id": "1a976eb1-46bf-44a6-b49a-6254abb5b4ad",
          "key_prefix": "qk_live_ULnO",
          "description": "Video · Draft · 5 s",
          "created_at": "2026-10-29T00:20:00Z"
        }
      ],
      "billing_enabled": true,
      "portal_available": true,
      "prices": {
        "video_draft_per_second": 0.1,
        "video_standard_per_second": 0.18,
        "video_pro_per_second": 0.26,
        "audio_per_second": 0.02,
        "image_flash": 0.06,
        "image_pro": 0.12,
        "recap": 0.3,
        "story_assembly": 0.05,
        "edit_render_per_minute": 0.05,
        "enhance_per_minute": 0.05,
        "character": 0.1
      }
    }
  }
}

Errors: 400 Amount out of range · 401 Missing, invalid or revoked API key · 403 Not allowed: scope, Studio disabled, or account suspended (`developer_account_suspended`, e.g. after a refunded or disputed top-up) · 409 No saved card. All codes

Payment methods and receipts

Dashboard session only
POST/api/v1/developer/billing/portalConsole →

**Dashboard session only; not callable with an API key** (an API key gets 403 developer_scope_denied). Opens the Stripe customer portal (saved cards, receipts). Redirect the user to url.

Body (JSON)

FieldTypeDescription
return_urlstring
Response 200
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": {
      "url": "https://billing.stripe.com/p/session/…"
    }
  }
}

Errors: 401 Missing, invalid or revoked API key · 403 Not allowed: scope, Studio disabled, or account suspended (`developer_account_suspended`, e.g. after a refunded or disputed top-up). All codes

Catalog

Templates, camera-move presets, voices and pricing.

  • GET/api/v1/studio/catalog
  • GET/api/v1/studio/templates
  • GET/api/v1/studio/presets
  • GET/api/v1/studio/voices

Public catalog and pricing

No key needed
GET/api/v1/studio/catalogTry it →

Templates, presets, Studio plans and the Studio credit price list. Public: no key needed. API prices in USD are at GET /developer/pricing.

Request
curl https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/catalog \
  -H "Authorization: Bearer $QULTURE_API_KEY"

List templates

GET/api/v1/studio/templatesTry it →

Ready-made video ideas. Each lists the inputs it needs (photo, text…), its defaults and credit cost.

Request
curl https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/templates \
  -H "Authorization: Bearer $QULTURE_API_KEY"

Errors: 401 Missing, invalid or revoked API key · 429 Rate limited: 60 requests/minute per key. All codes

List camera moves and effects

GET/api/v1/studio/presetsTry it →

Camera-move presets (dolly in, orbit, whip pan…), effects and styles. Pass a preset id as preset_id when you create a job.

Parameters

NameInTypeDescription
categoryquerystringFilter by category id, e.g. classic, dynamic, effects.
modequerytext_to_video | photo_to_video | template | transition | reference | character | talking_photo | sound_sync | describe | animateOnly presets that work with this mode.
Request
curl https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/presets \
  -H "Authorization: Bearer $QULTURE_API_KEY"

Errors: 401 Missing, invalid or revoked API key · 429 Rate limited: 60 requests/minute per key. All codes

List voices

GET/api/v1/studio/voicesTry it →

Voices for talking_photo jobs (voice + speech_text).

Request
curl https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/voices \
  -H "Authorization: Bearer $QULTURE_API_KEY"

Errors: 401 Missing, invalid or revoked API key · 429 Rate limited: 60 requests/minute per key. All codes

Uploads

Upload photos (and short audio/video) to use as inputs.

  • POST/api/v1/studio/uploads

Upload a photo

POST/api/v1/studio/uploadsTry it →

Multipart upload. Images: JPEG, PNG, WebP or HEIC up to 10 MB (normalised to JPEG). kind=audio (≤ 15 s) and kind=video (≤ 15 s, ≤ 50 MB) are accepted too. Use the returned key in image_keys (or a template's image input). If has_face is true, send consent: true with the job.

Body (multipart/form-data)

FieldTypeDescription
file *string
kindimage | audio | video Default image.
Response 200
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": {
      "key": "studio/inputs/172a9b77-…/a4095776-….jpg",
      "url": "https://media.joinqulture.com/studio/inputs/…",
      "width": 1080,
      "height": 1350,
      "has_face": true,
      "kind": "image"
    }
  }
}

Errors: 400 Bad request · 401 Missing, invalid or revoked API key · 413 File too large · 415 Unsupported file · 429 Rate limited: 60 requests/minute per key. All codes

Videos

Create and follow video jobs.

  • POST/api/v1/studio/jobs
  • GET/api/v1/studio/jobs
  • GET/api/v1/studio/jobs/{id}
  • DELETE/api/v1/studio/jobs/{id}
  • POST/api/v1/studio/jobs/{id}/regenerate
  • POST/api/v1/studio/jobs/{id}/extend
  • POST/api/v1/studio/jobs/{id}/upgrade

Create a video

Paid from API balance
POST/api/v1/studio/jobsTry it →

Starts a video job and charges its price to your API balance (duration × the tier's price per second; cost_usd on the job). The response is the job (usually queued); follow it with GET /jobs/{id} or pass webhook_url to be called when it finishes. You're charged when a generation is submitted and finishes processing, whatever its outcome. Requests rejected before processing (invalid input, insufficient balance, limits) are never charged: not enough balance → 402 insufficient_balance (no job is created).

Parameters

NameInTypeDescription
X-Qulture-Request-IDheaderstringAny unique string. Retrying with the same value never creates (or charges) twice.

Body (JSON)

FieldTypeDescription
mode *text_to_video | photo_to_video | template | transition | reference | character | talking_photo | sound_sync | describe | animateWhat kind of video to make.
promptstringWhat should happen. Required for text_to_video.
tierdraft | standard | proQuality tier, priced per second. Draft is cheapest.
duration5 | 10Seconds. Billed per second. Default 5.
aspect9:16 | 1:1 | 4:5 | 16:9 Default 9:16.
preset_idstringCamera move / effect id from GET /presets.
template_idstringTemplate id from GET /templates (mode template).
inputsobjectTemplate inputs by key: upload keys for photos, strings for text.
image_keysstring[]Upload keys (photo_to_video, reference, transition = [first, last]).
soundbooleanGenerate sound. Default false.
consentbooleanRequired when a photo shows a person: you confirm you have their permission. Default false.
character_idstring
voicestringVoice id (talking_photo).
speech_textstringWhat the photo says (talking_photo).
audio_keystringUploaded audio (sound_sync).
webhook_urlstringhttps URL Qulture POSTs a signed event to when the job finishes. API keys only.
Request
curl -X POST https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/jobs \
  -H "Authorization: Bearer $QULTURE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "mode": "text_to_video",
  "prompt": "A neon-lit street market at night, slow camera push in",
  "tier": "draft",
  "duration": 5,
  "aspect": "9:16"
}'

More examples: Photo to video with a camera move, Template — open them in the playground.

Response 201
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": {
      "id": "8d67563e-bbaf-4357-9380-04c2fe602203",
      "template_id": null,
      "template_name": null,
      "mode": "text_to_video",
      "status": "queued",
      "progress": 0,
      "stage_label": "In the queue",
      "queue_position": 1,
      "duration_s": 5,
      "quality": "standard",
      "sound": false,
      "credits_charged": 0,
      "billing": "api_balance",
      "cost_usd": 0.5,
      "charged_usd": 0.5,
      "video_url": null,
      "download_url": null,
      "thumbnail_url": null,
      "watermarked": false,
      "caption": null,
      "hashtags": [],
      "fail_reason": null,
      "block_category": null,
      "posted_media_id": null,
      "prompt": "A neon-lit street market at night, slow camera push in",
      "inputs": {},
      "created_at": "2026-10-29T00:20:00Z",
      "finished_at": null,
      "expires_at": null,
      "kind": "video",
      "tier": "draft",
      "aspect": "9:16",
      "preset_id": null,
      "character_id": null,
      "parent_job_id": null,
      "story_id": null,
      "shot_id": null,
      "avatar_user_ids": [],
      "needs_approval": false,
      "post_status": ""
    }
  }
}

Errors: 400 Bad request · 401 Missing, invalid or revoked API key · 402 Not enough API balance (`insufficient_balance`; connector keys: `studio_insufficient_credits`). Nothing is created or charged. · 403 Not allowed: scope, Studio disabled, or account suspended (`developer_account_suspended`, e.g. after a refunded or disputed top-up) · 422 Blocked by safety checks, or consent needed · 429 Rate limited (`rate_limited`: 60 requests/minute, or 200 generations/hour per API key — 20 for connector keys) or too many generations running at once for the account (`concurrency_limit`, 20) · 503 Busy — try again shortly. All codes

List your videos

GET/api/v1/studio/jobsTry it →

Parameters

NameInTypeDescription
cursorquerystringnext_cursor from the previous page.
limitqueryinteger
Request
curl https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/jobs \
  -H "Authorization: Bearer $QULTURE_API_KEY"

Errors: 401 Missing, invalid or revoked API key · 429 Rate limited: 60 requests/minute per key. All codes

Get a video

GET/api/v1/studio/jobs/{id}Try it →

Status, progress and — once ready — signed video_url / download_url (valid for 1 hour; fetch the job again for fresh links). Poll every 5 s.

Parameters

NameInTypeDescription
id *pathstringJob id
Request
curl https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/jobs/JOB_ID \
  -H "Authorization: Bearer $QULTURE_API_KEY"
Response 200
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": {
      "id": "8d67563e-bbaf-4357-9380-04c2fe602203",
      "template_id": null,
      "template_name": null,
      "mode": "text_to_video",
      "status": "ready",
      "progress": 1,
      "stage_label": "Ready",
      "queue_position": null,
      "duration_s": 5,
      "quality": "standard",
      "sound": false,
      "credits_charged": 0,
      "billing": "api_balance",
      "cost_usd": 0.5,
      "charged_usd": 0.5,
      "video_url": "https://media.joinqulture.com/studio/out/…/marked.mp4?X-Amz-Signature=…",
      "download_url": "https://media.joinqulture.com/studio/out/…/marked.mp4?…&response-content-disposition=attachment",
      "thumbnail_url": "https://media.joinqulture.com/studio/out/…/thumb.jpg?…",
      "watermarked": false,
      "caption": "Night market glow ✨",
      "hashtags": [
        "#MadeWithQulture"
      ],
      "fail_reason": null,
      "block_category": null,
      "posted_media_id": null,
      "prompt": "A neon-lit street market at night, slow camera push in",
      "inputs": {},
      "created_at": "2026-10-29T00:20:00Z",
      "finished_at": "2026-10-29T00:21:10Z",
      "expires_at": null,
      "kind": "video",
      "tier": "draft",
      "aspect": "9:16",
      "preset_id": null,
      "character_id": null,
      "parent_job_id": null,
      "story_id": null,
      "shot_id": null,
      "avatar_user_ids": [],
      "needs_approval": false,
      "post_status": ""
    }
  }
}

Errors: 401 Missing, invalid or revoked API key · 404 Not found · 429 Rate limited: 60 requests/minute per key. All codes

Delete a video

DELETE/api/v1/studio/jobs/{id}Try it →

Deletes the creation and its files. Jobs still in progress return 409 studio_job_not_ready.

Parameters

NameInTypeDescription
id *pathstringJob id
Request
curl -X DELETE https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/jobs/JOB_ID \
  -H "Authorization: Bearer $QULTURE_API_KEY"
Response 200
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": null
  }
}

Errors: 401 Missing, invalid or revoked API key · 404 Not found · 409 Not ready yet · 429 Rate limited: 60 requests/minute per key. All codes

Regenerate

Paid from API balance
POST/api/v1/studio/jobs/{id}/regenerateTry it →

Same inputs, new seed. A new job, charged again. Accepts an optional JSON body with webhook_url.

Parameters

NameInTypeDescription
id *pathstringJob id

Body (JSON)

FieldTypeDescription
webhook_urlstringhttps URL Qulture POSTs a signed event to when the job finishes. API keys only.
Request
curl -X POST https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/jobs/JOB_ID/regenerate \
  -H "Authorization: Bearer $QULTURE_API_KEY"

Errors: 401 Missing, invalid or revoked API key · 402 Not enough API balance (`insufficient_balance`; connector keys: `studio_insufficient_credits`). Nothing is created or charged. · 403 Not allowed: scope, Studio disabled, or account suspended (`developer_account_suspended`, e.g. after a refunded or disputed top-up) · 404 Not found · 422 Blocked by safety checks, or consent needed · 429 Rate limited (`rate_limited`: 60 requests/minute, or 200 generations/hour per API key — 20 for connector keys) or too many generations running at once for the account (`concurrency_limit`, 20). All codes

Extend a video

Paid from API balance
POST/api/v1/studio/jobs/{id}/extendTry it →

Continues a ready video with a new prompt. Returns a new job with parent_job_id set.

Parameters

NameInTypeDescription
id *pathstringJob id

Body (JSON)

FieldTypeDescription
prompt *string
duration *5 | 10
tierdraft | standard | proQuality tier, priced per second. Draft is cheapest.
webhook_urlstringhttps URL Qulture POSTs a signed event to when the job finishes. API keys only.
Request
curl -X POST https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/jobs/JOB_ID/extend \
  -H "Authorization: Bearer $QULTURE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "prompt": "The camera rises above the market",
  "duration": 5,
  "tier": "draft"
}'

Errors: 400 Bad request · 401 Missing, invalid or revoked API key · 402 Not enough API balance (`insufficient_balance`; connector keys: `studio_insufficient_credits`). Nothing is created or charged. · 403 Not allowed: scope, Studio disabled, or account suspended (`developer_account_suspended`, e.g. after a refunded or disputed top-up) · 404 Not found · 409 Not ready yet · 429 Rate limited (`rate_limited`: 60 requests/minute, or 200 generations/hour per API key — 20 for connector keys) or too many generations running at once for the account (`concurrency_limit`, 20). All codes

Upgrade a Draft

Paid from API balance
POST/api/v1/studio/jobs/{id}/upgradeTry it →

Re-renders a Draft with the same shot plan and seed at a higher tier. A new job, charged at the new tier's price.

Parameters

NameInTypeDescription
id *pathstringJob id

Body (JSON)

FieldTypeDescription
tier *standard | pro
webhook_urlstringhttps URL Qulture POSTs a signed event to when the job finishes. API keys only.
Request
curl -X POST https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/jobs/JOB_ID/upgrade \
  -H "Authorization: Bearer $QULTURE_API_KEY"

Errors: 401 Missing, invalid or revoked API key · 402 Not enough API balance (`insufficient_balance`; connector keys: `studio_insufficient_credits`). Nothing is created or charged. · 403 Not allowed: scope, Studio disabled, or account suspended (`developer_account_suspended`, e.g. after a refunded or disputed top-up) · 404 Not found · 409 Not ready yet · 429 Rate limited (`rate_limited`: 60 requests/minute, or 200 generations/hour per API key — 20 for connector keys) or too many generations running at once for the account (`concurrency_limit`, 20). All codes

Images

Create images and turn them into videos.

  • POST/api/v1/studio/images
  • GET/api/v1/studio/images
  • GET/api/v1/studio/images/{id}
  • POST/api/v1/studio/images/{id}/animate

Create an image

Paid from API balance
POST/api/v1/studio/imagesTry it →

Generates an image from a prompt (optionally guided by uploaded image_keys). Follow it with GET /images/{id} or webhook_url.

Parameters

NameInTypeDescription
X-Qulture-Request-IDheaderstringAny unique string. Retrying with the same value never creates (or charges) twice.

Body (JSON)

FieldTypeDescription
prompt *string
qualityflash | pro Default flash.
aspect9:16 | 1:1 | 4:5 | 16:9 Default 9:16.
image_keysstring[]Optional reference photos (upload keys).
webhook_urlstringhttps URL Qulture POSTs a signed event to when the job finishes. API keys only.
Request
curl -X POST https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/images \
  -H "Authorization: Bearer $QULTURE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "prompt": "Poster of a rooftop party at golden hour",
  "quality": "flash",
  "aspect": "9:16"
}'
Response 201
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": {
      "id": "4b1f0f1e-9a52-4c43-8d0f-3f7d8f8f2a10",
      "prompt": "Poster of a rooftop party at golden hour",
      "status": "queued",
      "image_url": null,
      "width": null,
      "height": null,
      "billing": "api_balance",
      "cost_usd": 0.06,
      "charged_usd": 0.06,
      "created_at": "2026-10-29T00:20:00Z"
    }
  }
}

Errors: 400 Bad request · 401 Missing, invalid or revoked API key · 402 Not enough API balance (`insufficient_balance`; connector keys: `studio_insufficient_credits`). Nothing is created or charged. · 403 Not allowed: scope, Studio disabled, or account suspended (`developer_account_suspended`, e.g. after a refunded or disputed top-up) · 422 Blocked by safety checks, or consent needed · 429 Rate limited (`rate_limited`: 60 requests/minute, or 200 generations/hour per API key — 20 for connector keys) or too many generations running at once for the account (`concurrency_limit`, 20). All codes

List your images

GET/api/v1/studio/imagesTry it →

Parameters

NameInTypeDescription
cursorquerystring
Request
curl https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/images \
  -H "Authorization: Bearer $QULTURE_API_KEY"

Errors: 401 Missing, invalid or revoked API key · 429 Rate limited: 60 requests/minute per key. All codes

Get an image

GET/api/v1/studio/images/{id}Try it →

Parameters

NameInTypeDescription
id *pathstringImage id
Request
curl https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/images/IMAGE_ID \
  -H "Authorization: Bearer $QULTURE_API_KEY"
Response 200
{
  "success": true,
  "message": "OK",
  "data": {
    "success": true,
    "message": "OK",
    "data": {
      "id": "4b1f0f1e-9a52-4c43-8d0f-3f7d8f8f2a10",
      "prompt": "Poster of a rooftop party at golden hour",
      "status": "ready",
      "image_url": "https://media.joinqulture.com/…/image.jpg?…",
      "width": 1080,
      "height": 1920,
      "billing": "api_balance",
      "cost_usd": 0.06,
      "charged_usd": 0.06,
      "created_at": "2026-10-29T00:20:00Z"
    }
  }
}

Errors: 401 Missing, invalid or revoked API key · 404 Not found · 429 Rate limited: 60 requests/minute per key. All codes

Turn an image into a video

Paid from API balance
POST/api/v1/studio/images/{id}/animateTry it →

Creates a photo_to_video job from a ready image. Same body as POST /jobs without image inputs.

Parameters

NameInTypeDescription
id *pathstringImage id

Body (JSON)

FieldTypeDescription
mode *text_to_video | photo_to_video | template | transition | reference | character | talking_photo | sound_sync | describe | animateWhat kind of video to make.
promptstringWhat should happen. Required for text_to_video.
tierdraft | standard | proQuality tier, priced per second. Draft is cheapest.
duration5 | 10Seconds. Billed per second. Default 5.
aspect9:16 | 1:1 | 4:5 | 16:9 Default 9:16.
preset_idstringCamera move / effect id from GET /presets.
template_idstringTemplate id from GET /templates (mode template).
inputsobjectTemplate inputs by key: upload keys for photos, strings for text.
image_keysstring[]Upload keys (photo_to_video, reference, transition = [first, last]).
soundbooleanGenerate sound. Default false.
consentbooleanRequired when a photo shows a person: you confirm you have their permission. Default false.
character_idstring
voicestringVoice id (talking_photo).
speech_textstringWhat the photo says (talking_photo).
audio_keystringUploaded audio (sound_sync).
webhook_urlstringhttps URL Qulture POSTs a signed event to when the job finishes. API keys only.
Request
curl -X POST https://qulture-webapi-staging-381114038302.us-central1.run.app/api/v1/studio/images/IMAGE_ID/animate \
  -H "Authorization: Bearer $QULTURE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "mode": "photo_to_video",
  "prompt": "Slow orbit around the poster",
  "tier": "draft",
  "duration": 5
}'

Errors: 400 Bad request · 401 Missing, invalid or revoked API key · 402 Not enough API balance (`insufficient_balance`; connector keys: `studio_insufficient_credits`). Nothing is created or charged. · 403 Not allowed: scope, Studio disabled, or account suspended (`developer_account_suspended`, e.g. after a refunded or disputed top-up) · 404 Not found · 409 Not ready yet · 429 Rate limited (`rate_limited`: 60 requests/minute, or 200 generations/hour per API key — 20 for connector keys) or too many generations running at once for the account (`concurrency_limit`, 20). All codes

← PreviousErrorsNext →Changelog

On this page

  • Account
  • Billing
  • Catalog
  • Uploads
  • Videos
  • Images