Developer Documentation
Everything needed to integrate model discovery, pricing quotes, language/image/video generation, and async video polling.
Base URL: https://studio.pahlavan.co.uk
Quickstart
1. Create an API key in Dashboard -> APIs.
2. Call GET /api/v1/models and pick a model id.
3. Optional: call POST /api/v1/quotes to preflight cost.
4. Call POST /api/v1/generations for language, image, or video.
5. For OpenAI-style streaming chat, call POST /api/v1/chat/completions.
6. For async video, poll GET /api/v1/videos/generations/:id until terminal status.
Authentication
Authorization: Bearer sp_live_...
Required for write endpoints: /api/v1/quotes, /api/v1/generations, /api/v1/chat/completions, /api/v1/videos/generations, and video status polling, plus storage endpoints.
Public endpoints: GET /api/health, GET /api/v1/models.
Models
Discover enabled models and input requirements.
GET /api/v1/models?type=language&limit=50&q=glm
Query params: type (language | image | video), q, limit (1..200).
Response model fields use provider-style naming: id, object, owned_by, name, type, pricing, requirements, provider_capabilities.
Null/empty fields are omitted from responses.
Quotes
Estimate cost and affordability before generation.
POST /api/v1/quotes
{
"model": "<model-id>",
"type": "language",
"inputTokens": 1000,
"outputTokens": 500
}Use type with one of language, image, video.
Returns estimated charge plus account and API-key limit checks.
Unified Generation
One endpoint for language, image, and video.
POST /api/v1/generations
{
"model": "<model-id>",
"type": "language",
"messages": [{ "role": "user", "content": "Summarize this in 3 bullets" }],
"settings": { "max_tokens": 300 },
"models": ["<fallback-model-id-1>", "<fallback-model-id-2>"]
}Optional models lets you define a fallback chain for the same request (language models only).
For image requests, response includes output_urls as an array.
You can switch image delivery to signed storage URLs via Storage using settings.saveToStorage.
For video requests, default is async (202 accepted) with status_url. Use "async": false only when you explicitly need sync behavior.
OpenAI Chat
OpenAI-style chat completions with optional SSE streaming.
POST /api/v1/chat/completions
{
"model": "<llm-model-id>",
"messages": [{ "role": "user", "content": "Write a launch tweet" }],
"stream": true,
"stream_options": { "include_usage": true },
"models": ["<fallback-model-id-1>", "<fallback-model-id-2>"]
}Streaming responses are SSE chunks and end with data: [DONE].
Video Status
Poll video jobs until completion.
Create: POST /api/v1/generations with type: "video" or POST /api/v1/videos/generations.
Poll: GET /api/v1/videos/generations/:id.
Terminal statuses: succeeded, failed.
Storage
R2-backed per-user/org storage with API-key auth and signed retrieval URLs.
POST /api/v1/storage/presign
{
"filename": "result.png",
"content_type": "image/png",
"bytes": 204800,
"path": "website-a/assets"
}Upload to the returned upload_url, then finalize:
POST /api/v1/storage/commit
{
"key": "user/user_123/website-a/assets/2026/02/26/abc-result.png"
}To fetch a private file URL for download/view:
POST /api/v1/storage/sign-url
{
"key": "user/user_123/website-a/assets/2026/02/26/abc-result.png"
}Retrieval URLs are signed and temporary.
To mirror generated image URLs automatically, pass saveToStorage: true and optional storagePath in generation/chat request settings.
Billing Fields
estimated_charge_cents / final_charge_cents are wallet-settled amounts.
estimated_charge_usd / final_charge_usd are derived from settled cents.
metered_estimated_charge_usd / metered_final_charge_usd expose exact metered cost before cent rounding/carry.
Errors
{
"error": "Human readable message",
"details": {
"code": "MACHINE_READABLE_CODE",
"details": {}
}
}Typical codes: MODEL_NOT_FOUND, MODEL_INPUT_REQUIRED, INSUFFICIENT_BALANCE, API_KEY_SPEND_LIMIT_EXCEEDED, UPSTREAM_REQUEST_FAILED.
Examples
Ready-to-run snippets for common integration paths.
curl "https://studio.pahlavan.co.uk/api/v1/models?type=language&limit=50&q=glm"