Generative AI API Documentation
The Prospolabs API gives you one endpoint and one auth flow for every frontier image and video generation model — Seedance, Kling V3 / O3, Veo 3.1, GPT Image 2, Nano Banana, and Seedream. Pay USD per generation, no tokens.
Authentication
All API requests require a Bearer token in the Authorization header. Generate API keys from your Dashboard. Keep your keys secret and never expose them in client-side code.
1Authorization: Bearer prsp-your-api-key
Quick Start
One endpoint, every model. Pass the model id and any model-specific parameters.
1curl -X POST https://api.prospolabs.com/v1/generate \2 -H "Authorization: Bearer prsp-your-api-key" \3 -H "Content-Type: application/json" \4 -d '{5 "model": "veo-3-1-lite",6 "mode": "text",7 "params": {8 "prompt": "A close-up of a hummingbird hovering near a sunlit flower, slow motion",9 "duration": "8s",10 "resolution": "720p",11 "aspect_ratio": "16:9",12 "generate_audio": true13 }14 }'
Generate Endpoint
/v1/generateRun any model in the catalog. Pass the model id (e.g. veo-3-1-lite, seedream-5-lite) and the model-specific parameters listed below.
Shared Request Body
| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Model id from the catalog. e.g. "veo-3-1-lite", "seedream-5-lite", "kling-v3". |
mode | string | No | Selects the input shape for multi-modal models. e.g. "text", "image", "reference" (video) or "generate", "edit" (image). Defaults to the model's first declared mode. |
params | object | Yes | Per-model parameters. Schema depends on the chosen model and mode — see the per-model sections below. |
webhook_url | string | No | Receive a callback when async generation completes. See Webhooks. |
async | boolean | No | Send true (or pass ?async=true) to skip the synchronous wait. Returns generation_id immediately. |
Response
| Field | Type | Required | Description |
|---|---|---|---|
generation_id | string | Yes | Unique identifier for the generation (gen_*). |
status | "queued" | "processing" | "completed" | "failed" | Yes | Current state of the generation. |
model | string | Yes | Model id used. |
mode | string | Yes | Mode used for this generation. |
output_url | string | null | Yes | URL of the generated image or video. Available for 7 days after generation; requests after that return HTTP 410 Gone (code: output_expired). Download anything you want to keep. |
cost_usd | number | Yes | Exact USD amount deducted from your balance for this generation. |
duration_ms | number | null | Yes | End-to-end processing time in milliseconds. |
Response Example
1{2 "generation_id": "gen_a1b2c3d4e5f6",3 "status": "completed",4 "model": "veo-3-1-lite",5 "mode": "text",6 "output_url": "https://cdn.prospolabs.com/results/gen_a1b2c3d4e5f6.mp4?token=...",7 "cost_usd": 0.40,8 "duration_ms": 284309}
Per-Model Parameters
Generate a clip from a text prompt.
Seedance 2.0 Fast — Text → Video
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Prompt. |
resolution | string | No | Resolution. One of: 480p, 720p. Default: 720p. |
duration | number | No | Duration. Range: 4–15 (s). Default: 5. |
aspect_ratio | string | No | Aspect ratio. One of: 16:9, 9:16, 1:1, 4:3, 3:4, 21:9. Default: 16:9. |
generate_audio | boolean | No | Generate audio. Default: true. |
seed | number | No | Seed. Range: 0–2147483647. |
Uploading Files
Any media param — image_url, image_urls, video_urls, audio_urls, mask_url — accepts either a public https:// URL or an opaque upload token minted by POST /v1/uploads/initiate. Use the token flow for large files (videos > 32 MB) or any private file you don't have a public URL for.
Two-step token flow
1. Initiate the upload — get back an opaque token and a PUT target on this domain.
1curl -X POST https://api.prospolabs.com/v1/uploads/initiate \2 -H "Authorization: Bearer $PROSPOLABS_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{"content_type":"video/mp4","file_name":"my-clip.mp4"}'56# Response:7# {8# "token": "pl-upload-3d756375a28d44cead027db57565f176",9# "upload_url": "/v1/uploads/proxy/pl-upload-3d756375a28d44cead027db57565f176",10# "content_type": "video/mp4"11# }
2. PUT the raw file bytes to upload_url. Use the same content type you initiated with.
1curl -X PUT "https://api.prospolabs.com/v1/uploads/proxy/pl-upload-3d756375a28d44cead027db57565f176" \2 -H "Authorization: Bearer $PROSPOLABS_API_KEY" \3 -H "Content-Type: video/mp4" \4 --data-binary @my-clip.mp456# Response: { "status": "uploaded", "bytes": 12345678 }
3. Use the token in any generate request. The server resolves it before dispatching the model.
1curl -X POST https://api.prospolabs.com/v1/generate \2 -H "Authorization: Bearer $PROSPOLABS_API_KEY" \3 -H "Content-Type: application/json" \4 -d '{5 "model": "seedance-2",6 "mode": "reference",7 "params": {8 "prompt": "animate the product on a beach at golden hour",9 "image_urls": ["pl-upload-3d756375a28d44cead027db57565f176"],10 "duration": 6,11 "resolution": "720p"12 }13 }'
Limits
- Images: JPEG / PNG / WebP, up to 30 MB per file.
- Videos: MP4 / MOV, up to 50 MB per file.
- Audio: MP3 / WAV, up to 15 MB per file.
- Token lifetime: 1 hour pre-PUT, 24 hours after upload completes. Tokens are single-account — only the API key that minted them can redeem them.
Sync vs Async API
Use the standard endpoint for synchronous processing, or pass ?async=true for asynchronous processing. Recommended for video generations longer than 5 seconds.
POST /v1/generateBlocks until processing completes. Best for image generation and short video clips.
Timeout: 180 seconds. For longer generations, use async mode.
Response
1{2 "generation_id": "gen_a1b2c3d4e5f6",3 "status": "completed",4 "model": "veo-3-1-lite",5 "mode": "text",6 "output_url": "https://cdn.prospolabs.com/results/gen_a1b2c3d4e5f6.mp4?token=...",7 "cost_usd": 0.40,8 "duration_ms": 284309}
POST /v1/generate?async=trueReturns a generation_id immediately with status queued. Poll GET /v1/generations/{generation_id} or use a webhook.
Initial Response
1{2 "generation_id": "gen_a1b2c3d4e5f6",3 "status": "queued",4 "model": "veo-3-1",5 "mode": "text",6 "created_at": "2026-05-02T14:32:15.000Z",7 "poll_url": "https://api.prospolabs.com/v1/generations/gen_a1b2c3d4e5f6"8}
Polling for Status
1// GET /v1/generations/{generation_id}23// queued:4{ "generation_id": "gen_...", "status": "queued", "model": "veo-3-1", "mode": "text" }56// processing:7{ "generation_id": "gen_...", "status": "processing", "model": "veo-3-1", "mode": "text" }89// completed:10{11 "generation_id": "gen_...",12 "status": "completed",13 "model": "veo-3-1",14 "mode": "text",15 "output_url": "https://cdn.prospolabs.com/results/gen_....mp4?token=...",16 "cost_usd": 3.22,17 "duration_ms": 4218018}1920// failed (auto-refunded):21{ "generation_id": "gen_...", "status": "failed", "model": "veo-3-1", "mode": "text" }
Alternatively, provide a webhook_url in the request body to receive a callback. See the Webhooks section.
Webhooks
Configure a webhook URL in your dashboard or pass it per-request via the webhook_url field.
Event Types
| Event | Description |
|---|---|
generation.completed | Generation completed successfully. Includes output_url and cost_usd. |
generation.failed | Generation failed. The corresponding cost has been refunded automatically. |
Payload Format
1{2 "event": "generation.completed",3 "generation_id": "gen_a1b2c3d4e5f6",4 "data": {5 "model": "veo-3-1",6 "mode": "text",7 "output_url": "https://cdn.prospolabs.com/results/gen_a1b2c3d4e5f6.mp4?token=...",8 "cost_usd": 3.22,9 "duration_ms": 4218010 },11 "timestamp": "2026-05-02T14:33:27.000Z"12}
Verifying Webhook Signatures
Every webhook includes an X-Prospo-Signature header containing an HMAC-SHA256 signature. Verify it against your webhook secret.
1import crypto from 'crypto';23function verifyWebhook(payload, signature, secret) {4 const expected = crypto5 .createHmac('sha256', secret)6 .update(payload)7 .digest('hex');8 return crypto.timingSafeEqual(9 Buffer.from(signature),10 Buffer.from(expected)11 );12}1314app.post('/api/webhook', (req, res) => {15 const signature = req.headers['x-prospo-signature'];16 const isValid = verifyWebhook(JSON.stringify(req.body), signature, process.env.WEBHOOK_SECRET);17 if (!isValid) return res.status(401).send('Invalid signature');1819 const { event, data } = req.body;20 if (event === 'generation.completed') {21 console.log('Output ready:', data.output_url, 'cost:', data.cost_usd);22 }23 res.status(200).send('OK');24});
Retry Policy
If your endpoint returns a non-2xx status code, we'll retry delivery with exponential backoff:
- 1First retry: 30 seconds after initial attempt
- 2Second retry: 2 minutes after first retry
- 3Third retry: 10 minutes after second retry
- 4Final retry: 1 hour after third retry
- 5After 4 failed attempts the webhook is marked as failed and surfaced in the dashboard
Check Balance
Returns your current USD credit balance. Useful for budget alerts, dashboards, or deciding whether to top up before a large batch run. Authenticates with the same Bearer token as any other endpoint.
/v1/balanceReturns { balance_usd, currency } for the authenticated user. No body, no query params.
Example
1curl https://api.prospolabs.com/v1/balance \2 -H "Authorization: Bearer $PROSPOLABS_API_KEY"34# Response:5# {6# "balance_usd": 12.345,7# "currency": "USD"8# }
Rate Limits
Default: 60 requests per minute. Monitor your usage via the response headers X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset.
Need higher rate limits, dedicated capacity, or SLA guarantees? Contact us with your expected volume and we'll work with you directly.
Contact us for higher limits →Error Handling
The API uses standard HTTP status codes. All error responses include a JSON body with a machine-readable code and human-readable message.
| Status | Name | Description |
|---|---|---|
| 400 | Bad Request | Invalid request body, unknown model id, unknown mode, or missing required field |
| 401 | Unauthorized | Missing or invalid API key / Bearer token |
| 403 | Forbidden | Insufficient balance or account suspended |
| 404 | Not Found | Generation not found (for polling endpoint) |
| 429 | Too Many Requests | Rate limit exceeded. Check X-RateLimit-* headers |
| 500 | Internal Server Error | Unexpected server error. Your balance is automatically refunded |
| 504 | Gateway Timeout | Provider unavailable or generation exceeded model timeout |
Error Response Example
1{2 "detail": "Insufficient balance. Please top up to continue."3}