Repository navigation
API Reference
Complete reference of all REST and WebSocket endpoints available in the 2DAI API.
- System Endpoints
- Settings API
- Generation API
- LLM API
- STT API
- TTS API
- CDN API
- OpenAI-Compatible API
- WebSocket API
- Type Definitions
- Error Codes
Public endpoints that don't require authentication.
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| GET | /health |
API health check | No |
| GET | /version |
API version info | No |
{
"status": "ok",
"timestamp": "2026-01-22T22:30:34.801Z",
"version": "1.12.0",
"environment": "local"
}| Field | Type | Description |
|---|---|---|
status |
string | Always "ok" when healthy |
timestamp |
string | ISO 8601 timestamp |
version |
string | API version |
environment |
string |
"live" or "development"
|
{
"version": "1.12.0",
"environment": "local"
}| Field | Type | Description |
|---|---|---|
version |
string | API version |
environment |
string | Environment name |
Account settings, rate limits, and usage statistics.
Base Path: /api/v1/settings
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/settings |
Get account status, rate limits, current usage |
| GET | /api/v1/settings/usage |
Usage statistics for date range |
| GET | /api/v1/settings/usage/recent |
Recent usage logs with filtering |
| GET | /api/v1/settings/rate-limits |
Current rate limit status |
Get account status, rate limits, and current usage.
{
"success": true,
"data": {
"status": "active",
"rateLimits": {
"image": {
"requestsPer15Min": 15,
"requestsPerDay": 100
},
"video": {
"requestsPer15Min": 5,
"requestsPerDay": 30
},
"llm": {
"requestsPer15Min": 30,
"requestsPerDay": 300,
"tokensPer15Min": 150000,
"tokensPerDay": 1500000,
"maxPromptLength": 90000
},
"cdn": {
"requestsPer15Min": 200,
"requestsPerDay": 5000
},
"stt": {
"requestsPer15Min": 15,
"requestsPerDay": 100
},
"tts": {
"requestsPer15Min": 10,
"requestsPerDay": 60
}
},
"currentUsage": {
"image": {
"current": {
"requestsPer15Min": 0,
"requestsPerDay": 0,
"tokensPer15Min": 0,
"tokensPerDay": 0
},
"remaining": {
"requestsPer15Min": 15,
"requestsPerDay": 100
},
"resetAt": {
"window15Min": "2026-02-06T22:45:00.000Z",
"daily": "2026-02-07T05:00:00.000Z"
}
},
"video": {
"current": {
"requestsPer15Min": 0,
"requestsPerDay": 0,
"tokensPer15Min": 0,
"tokensPerDay": 0
},
"remaining": {
"requestsPer15Min": 5,
"requestsPerDay": 30
},
"resetAt": {
"window15Min": "2026-02-06T22:45:00.000Z",
"daily": "2026-02-07T05:00:00.000Z"
}
},
"llm": {
"current": {
"requestsPer15Min": 0,
"requestsPerDay": 0,
"tokensPer15Min": 0,
"tokensPerDay": 0
},
"remaining": {
"requestsPer15Min": 30,
"requestsPerDay": 300
},
"resetAt": {
"window15Min": "2026-02-06T22:45:00.000Z",
"daily": "2026-02-07T05:00:00.000Z"
}
},
"cdn": {
"current": {
"requestsPer15Min": 0,
"requestsPerDay": 0,
"tokensPer15Min": 0,
"tokensPerDay": 0
},
"remaining": {
"requestsPer15Min": 200,
"requestsPerDay": 5000
},
"resetAt": {
"window15Min": "2026-02-06T22:45:00.000Z",
"daily": "2026-02-07T05:00:00.000Z"
}
},
"stt": {
"current": {
"requestsPer15Min": 0,
"requestsPerDay": 0,
"tokensPer15Min": 0,
"tokensPerDay": 0
},
"remaining": {
"requestsPer15Min": 15,
"requestsPerDay": 100
},
"resetAt": {
"window15Min": "2026-02-06T22:45:00.000Z",
"daily": "2026-02-07T05:00:00.000Z"
}
},
"tts": {
"current": {
"requestsPer15Min": 0,
"requestsPerDay": 0,
"tokensPer15Min": 0,
"tokensPerDay": 0
},
"remaining": {
"requestsPer15Min": 10,
"requestsPerDay": 60
},
"resetAt": {
"window15Min": "2026-02-06T22:45:00.000Z",
"daily": "2026-02-07T05:00:00.000Z"
}
}
}
}
}Note: Image, Video, and LLM use rate-based limits (
requestsPer15Min,requestsPerDay). CDN uses traditional rate-based limits (requestsPer15Min,requestsPerDay).
| Field | Type | Description |
|---|---|---|
success |
boolean | Request success status |
data.status |
string | Account status ("active") |
data.rateLimits |
object | Rate limit configuration per operation |
data.rateLimits.image.requestsPer15Min |
number | Image requests allowed per 15 minutes |
data.rateLimits.image.requestsPerDay |
number | Image requests allowed per day |
data.rateLimits.video.requestsPer15Min |
number | Video requests allowed per 15 minutes |
data.rateLimits.video.requestsPerDay |
number | Video requests allowed per day |
data.rateLimits.llm.requestsPer15Min |
number | LLM requests allowed per 15 minutes |
data.rateLimits.llm.requestsPerDay |
number | LLM requests allowed per day |
data.rateLimits.llm.tokensPer15Min |
number | LLM tokens allowed per 15 minutes |
data.rateLimits.llm.tokensPerDay |
number | LLM tokens allowed per day |
data.rateLimits.llm.maxPromptLength |
number | Maximum prompt length allowed |
data.rateLimits.cdn.requestsPer15Min |
number | CDN requests allowed per 15 minutes |
data.rateLimits.cdn.requestsPerDay |
number | CDN requests allowed per day |
data.rateLimits.stt.requestsPer15Min |
number | STT requests allowed per 15 minutes |
data.rateLimits.stt.requestsPerDay |
number | STT requests allowed per day |
data.rateLimits.tts.requestsPer15Min |
number | TTS requests allowed per 15 minutes |
data.rateLimits.tts.requestsPerDay |
number | TTS requests allowed per day |
data.currentUsage |
object | Current usage per operation |
data.currentUsage.*.current |
object | Current usage values |
data.currentUsage.*.remaining |
object | Remaining usage values |
data.currentUsage.*.resetAt |
object | Reset timestamps |
Usage statistics for a date range.
Query Parameters:
-
days- Number of days to include (default: 7)
{
"success": true,
"data": {
"period": {
"start": "2026-01-15T22:30:34.826Z",
"end": "2026-01-22T22:30:34.826Z",
"days": 7
},
"summary": {
"total": 243,
"byOperation": {
"image": 35,
"video": 8,
"llm": 13,
"cdn": 42
},
"totalTokens": 17129,
"successRate": 100
},
"daily": [
{
"date": "2026-01-22",
"total": 243,
"byOperation": {
"image": 35,
"video": 8,
"llm": 13,
"cdn": 42
},
"tokens": 17129
}
]
}
}| Field | Type | Description |
|---|---|---|
success |
boolean | Request success status |
data.period.start |
string | Period start timestamp (ISO 8601) |
data.period.end |
string | Period end timestamp (ISO 8601) |
data.period.days |
number | Number of days in period |
data.summary.total |
number | Total requests in period |
data.summary.byOperation |
object | Breakdown by operation type |
data.summary.byOperation.*.count |
number | Request count for operation |
data.summary.totalTokens |
number | Total LLM tokens used |
data.summary.successRate |
number | Success rate percentage |
data.daily |
array | Daily breakdown |
data.daily[].date |
string | Date (YYYY-MM-DD) |
data.daily[].total |
number | Total requests for day |
data.daily[].byOperation |
object | Operation breakdown for day |
data.daily[].tokens |
number | Tokens used for day |
Recent usage logs with filtering.
Query Parameters:
-
limit- Number of logs to return (default: 10) -
operation- Filter by operation type (image,video,llm,cdn,stt,tts)
{
"success": true,
"data": {
"count": 5,
"logs": [
{
"_id": "697296255e9a9d4a01171eb1",
"apiKey": "1f3827add11cc9a16cddfc1a88f3b6fa94c0b98140f4b7c7c20db7e6e742be17",
"operation": "image",
"timestamp": "2026-01-22T21:27:01.021Z",
"success": true,
"metadata": {
"type": "img2img",
"imageId": "91b2d374-60da-4961-9c63-57d74315f4ca",
"prompt": "add a blue border",
"seed": 1852839921,
"duration": 70500
}
},
{
"_id": "697295de5e9a9d4a01171eaf",
"apiKey": "1f3827add11cc9a16cddfc1a88f3b6fa94c0b98140f4b7c7c20db7e6e742be17",
"operation": "image",
"timestamp": "2026-01-22T21:25:50.514Z",
"success": true,
"metadata": {
"prompt": "a simple red circle on white background",
"style": "raw",
"width": 1024,
"height": 1024,
"seed": 753504967,
"duration": 66499
}
},
{
"_id": "6972959c5e9a9d4a01171ead",
"apiKey": "1f3827add11cc9a16cddfc1a88f3b6fa94c0b98140f4b7c7c20db7e6e742be17",
"operation": "openai_stream",
"timestamp": "2026-01-22T21:24:44.014Z",
"success": true,
"tokensUsed": 118,
"metadata": {
"model": "default",
"tokensUsed": 118,
"duration": 272
}
},
{
"_id": "6972959b5e9a9d4a01171eab",
"apiKey": "1f3827add11cc9a16cddfc1a88f3b6fa94c0b98140f4b7c7c20db7e6e742be17",
"operation": "openai_completion",
"timestamp": "2026-01-22T21:24:43.737Z",
"success": true,
"tokensUsed": 115,
"metadata": {
"model": "default",
"tokensUsed": 115,
"promptTokens": 111,
"completionTokens": 4,
"duration": 195
}
},
{
"_id": "6972959b5e9a9d4a01171ea9",
"apiKey": "1f3827add11cc9a16cddfc1a88f3b6fa94c0b98140f4b7c7c20db7e6e742be17",
"operation": "llm_stream",
"timestamp": "2026-01-22T21:24:43.538Z",
"success": true,
"tokensUsed": 118,
"metadata": {
"promptLength": 17,
"model": "2DAI-LLM",
"tokensUsed": 118,
"promptTokens": 112,
"completionTokens": 6,
"duration": 284
}
}
]
}
}| Field | Type | Description |
|---|---|---|
success |
boolean | Request success status |
data.count |
number | Number of logs returned |
data.logs |
array | Array of usage log entries |
data.logs[].operation |
string | Operation type (image, video, llm, cdn, stt, tts) |
data.logs[].timestamp |
string | Log timestamp (ISO 8601) |
data.logs[].success |
boolean | Whether operation succeeded |
data.logs[].tokensUsed |
number | Tokens used (LLM only) |
data.logs[].durationMs |
number | Operation duration in milliseconds |
data.logs[].metadata |
object | Operation-specific metadata |
Current rate limit status for all operations.
{
"success": true,
"data": [
{
"operation": "image",
"allowed": true,
"remaining15min": 15,
"remainingDaily": 100,
"current": {
"requestsPer15Min": 0,
"requestsPerDay": 0,
"tokensPer15Min": 0,
"tokensPerDay": 0
},
"limit": {
"requestsPer15Min": 15,
"requestsPerDay": 100
},
"resetAt": {
"window15Min": "2026-02-07T03:00:00.000Z",
"daily": "2026-02-07T05:00:00.000Z"
}
},
{
"operation": "video",
"allowed": true,
"remaining15min": 5,
"remainingDaily": 30,
"current": {
"requestsPer15Min": 0,
"requestsPerDay": 0,
"tokensPer15Min": 0,
"tokensPerDay": 0
},
"limit": {
"requestsPer15Min": 5,
"requestsPerDay": 30
},
"resetAt": {
"window15Min": "2026-02-07T03:00:00.000Z",
"daily": "2026-02-07T05:00:00.000Z"
}
},
{
"operation": "llm",
"allowed": true,
"remaining15min": 30,
"remainingDaily": 300,
"current": {
"requestsPer15Min": 0,
"requestsPerDay": 0,
"tokensPer15Min": 0,
"tokensPerDay": 0
},
"limit": {
"requestsPer15Min": 30,
"requestsPerDay": 300,
"tokensPer15Min": 150000,
"tokensPerDay": 1500000
},
"resetAt": {
"window15Min": "2026-02-07T03:00:00.000Z",
"daily": "2026-02-07T05:00:00.000Z"
}
},
{
"operation": "cdn",
"allowed": true,
"remaining15min": 200,
"remainingDaily": 5000,
"current": {
"requestsPer15Min": 0,
"requestsPerDay": 0,
"tokensPer15Min": 0,
"tokensPerDay": 0
},
"limit": {
"requestsPer15Min": 200,
"requestsPerDay": 5000
},
"resetAt": {
"window15Min": "2026-02-07T03:00:00.000Z",
"daily": "2026-02-07T05:00:00.000Z"
}
},
{
"operation": "stt",
"allowed": true,
"remaining15min": 15,
"remainingDaily": 100,
"current": {
"requestsPer15Min": 0,
"requestsPerDay": 0,
"tokensPer15Min": 0,
"tokensPerDay": 0
},
"limit": {
"requestsPer15Min": 15,
"requestsPerDay": 100
},
"resetAt": {
"window15Min": "2026-02-07T03:00:00.000Z",
"daily": "2026-02-07T05:00:00.000Z"
}
},
{
"operation": "tts",
"allowed": true,
"remaining15min": 10,
"remainingDaily": 60,
"current": {
"requestsPer15Min": 0,
"requestsPerDay": 0,
"tokensPer15Min": 0,
"tokensPerDay": 0
},
"limit": {
"requestsPer15Min": 10,
"requestsPerDay": 60
},
"resetAt": {
"window15Min": "2026-02-07T03:00:00.000Z",
"daily": "2026-02-07T05:00:00.000Z"
}
}
]
}| Field | Type | Description |
|---|---|---|
success |
boolean | Request success status |
data |
array | Array of rate limit status objects (ordered: image, video, llm, cdn, stt, tts) |
data[].operation |
string | Operation type: image, video, llm, cdn, stt, tts
|
data[].allowed |
boolean | Whether operation is allowed |
data[].remaining15min |
number | Remaining requests in 15-min window |
data[].remainingDaily |
number | Remaining requests in day |
data[].current |
object | Current usage values |
data[].limit |
object | Limit values |
data[].resetAt |
object | Reset timestamps |
Image and video generation endpoints.
Base Path: /api/v1/generation
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/generation/image |
Generate images (text2img) |
| POST | /api/v1/generation/image/edit |
Edit/transform images (img2img) |
| POST | /api/v1/generation/image/edit |
Dual-image editing (imgs2img) with imageId2
|
| POST | /api/v1/generation/image/upscale |
AI upscale images (img2ximg) |
| POST | /api/v1/generation/video |
Generate videos (img2vid) |
Note: The
urlfield in responses points to the CDN endpoint, which requires authentication.
Generate an image from a text prompt.
Request:
{
"prompt": "a futuristic city at sunset",
"style": "cine",
"format": "landscape"
}| Field | Type | Required | Description |
|---|---|---|---|
prompt |
string | Yes | Text description of the image |
style |
string | No | Style preset (see Styles) |
format |
string | No | Format preset (see Formats) |
negativePrompt |
string | No | What to avoid in the image |
seed |
number | No | Seed for reproducibility (0-2000000000) |
Response:
{
"success": true,
"data": {
"imageId": "55f8a56d-91de-4441-9f35-6a21fa26ecab",
"width": 1024,
"height": 1024,
"seed": 1050720317
}
}| Field | Type | Description |
|---|---|---|
success |
boolean | Request success status |
data.imageId |
string | Generated image CDN ID (UUID) |
data.width |
number | Image width in pixels |
data.height |
number | Image height in pixels |
data.seed |
number | Seed used for generation |
Note: Use the
imageIdwith the CDN endpoint to download:GET /api/v1/cdn/{imageId}.jpg
Edit an existing image (img2img).
Request:
{
"imageId": "f71f8d0d-488f-4b94-a260-06de434ae5ed",
"prompt": "add flying cars to the scene"
}| Field | Type | Required | Description |
|---|---|---|---|
imageId |
string | Yes | Source image CDN ID |
prompt |
string | Yes | Edit instructions |
negativePrompt |
string | No | What to avoid |
seed |
number | No | Seed for reproducibility |
Response:
{
"success": true,
"data": {
"imageId": "9cba3bf4-865f-4d2d-a0a2-92470fba2dc8",
"seed": 1904179547
}
}| Field | Type | Description |
|---|---|---|
success |
boolean | Request success status |
data.imageId |
string | Edited image CDN ID (UUID) |
data.seed |
number | Seed used for generation |
Edit images using two source images. Use this to merge, blend, or mix elements from two images together.
Request:
{
"imageId": "f71f8d0d-488f-4b94-a260-06de434ae5ed",
"imageId2": "9cba3bf4-865f-4d2d-a0a2-92470fba2dc8",
"prompt": "make an image with both subjects"
}| Field | Type | Required | Description |
|---|---|---|---|
imageId |
string | Yes | Image 1 (primary) - CDN ID of the main image |
imageId2 |
string | Yes | Image 2 (secondary) - CDN ID for dual-image mode |
prompt |
string | Yes | Instructions using "image 1" and "image 2" terminology |
negativePrompt |
string | No | What to avoid |
seed |
number | No | Seed for reproducibility |
width |
number | No | Output width (320-1344) |
height |
number | No | Output height (320-1344) |
Prompt Examples:
| Action | Prompt |
|---|---|
| Combine subjects | make an image with both subjects |
| Blend character | blend the character from image 2 into the scene of image 1 |
| Apply style | apply the style of image 2 to image 1 |
| Mix elements | mix elements from image 2 into image 1 |
| Combine | combine image 1 and image 2 into a seamless scene |
Response:
{
"success": true,
"data": {
"imageId": "1f1af23f-643b-43b8-8f5c-09fd10e6719a",
"seed": 666934679
}
}| Field | Type | Description |
|---|---|---|
success |
boolean | Request success status |
data.imageId |
string | Result image CDN ID (UUID) |
data.seed |
number | Seed used for generation |
AI upscale an image (2x, 3x, or 4x).
Request:
{
"imageId": "f71f8d0d-488f-4b94-a260-06de434ae5ed",
"factor": 2
}| Field | Type | Required | Description |
|---|---|---|---|
imageId |
string | Yes | Source image CDN ID |
factor |
number | No | Upscale factor: 2, 3, or 4 (default: 2) |
seed |
number | No | Seed for reproducibility |
Response:
{
"success": true,
"data": {
"imageId": "756cebda-9c82-40b5-96c3-23bb92b5c252",
"width": 2048,
"height": 2048,
"seed": 126568457
}
}| Field | Type | Description |
|---|---|---|
success |
boolean | Request success status |
data.imageId |
string | Upscaled image CDN ID (UUID) |
data.width |
number | Upscaled image width in pixels |
data.height |
number | Upscaled image height in pixels |
data.seed |
number | Seed used for upscaling |
Generate a video from an image.
Request:
{
"imageId": "f71f8d0d-488f-4b94-a260-06de434ae5ed",
"prompt": "the scene view (the camera) pans left, smooth motion",
"duration": 3,
"fps": 16
}| Field | Type | Required | Description |
|---|---|---|---|
imageId |
string | Yes | Source image CDN ID |
prompt |
string | No | Motion/animation prompt (e.g., "the scene view (the camera) pans left", "zoom in slowly") |
duration |
number | No | Duration in seconds: 1-10 (default: 5) |
fps |
number | No | Frames per second: 8-60 (default: 16) |
Response:
{
"success": true,
"data": {
"videoId": "4c14085e-02da-4186-a928-9c1e931383fe",
"duration": 2,
"fps": 8,
"seed": 1638417043
}
}| Field | Type | Description |
|---|---|---|
success |
boolean | Request success status |
data.videoId |
string | Generated video CDN ID (UUID) |
data.duration |
number | Video duration in seconds |
data.fps |
number | Video frames per second |
data.seed |
number | Seed used for generation |
Note: Use the
videoIdwith the CDN endpoint to download:GET /api/v1/cdn/{videoId}.mp4
Text generation endpoints.
Base Path: /api/v1/llm
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/llm/generate |
Non-streaming LLM text generation |
| POST | /api/v1/llm/generate/stream |
Streaming text generation (SSE) |
Generate text (non-streaming).
Request:
{
"prompt": "Explain quantum computing in simple terms",
"system": "You are a helpful assistant"
}| Field | Type | Required | Description |
|---|---|---|---|
prompt |
string | Yes | The prompt/question |
system |
string | No | System prompt for behavior |
memory |
string[] | No | Conversation history |
jsonFormat |
boolean | No | Enable JSON output |
jsonTemplate |
object | No | JSON structure template |
useMarkdown |
boolean | No | Enable markdown formatting |
imageId |
string | No | Image for vision analysis |
Response:
{
"success": true,
"data": {
"text": "Hello there. How's it goin?",
"tokensUsed": 132,
"promptTokens": 122,
"completionTokens": 10
}
}| Field | Type | Description |
|---|---|---|
success |
boolean | Request success status |
data.text |
string | Generated text response |
data.tokensUsed |
number | Total tokens used |
data.promptTokens |
number | Input/prompt tokens |
data.completionTokens |
number | Output/completion tokens |
data.json |
any | Parsed JSON (if jsonFormat: true) |
Generate text with streaming (Server-Sent Events).
Request:
{
"prompt": "Write a short poem about the moon"
}| Field | Type | Required | Description |
|---|---|---|---|
prompt |
string | Yes | The prompt/question |
system |
string | No | System prompt for behavior |
memory |
string[] | No | Conversation history |
useMarkdown |
boolean | No | Enable markdown formatting |
imageId |
string | No | Image for vision analysis |
Note:
jsonFormatis not supported with streaming - use non-streaming endpoint for JSON output.
Response (SSE):
data: {"chunk":"1.\n2.\n3."}
data: {"done":true,"tokensUsed":119,"promptTokens":112,"completionTokens":7}
data: [DONE]
Chunk Fields:
| Field | Type | Description |
|---|---|---|
chunk |
string | Text chunk (content events) |
done |
boolean |
true on final event |
response |
string | Full accumulated response (final event) |
tokensUsed |
number | Total tokens used (final event) |
promptTokens |
number | Input tokens (final event) |
completionTokens |
number | Output tokens (final event) |
Note: The stream ends with
data: [DONE]. The final chunk includes token counts.
Speech-to-text transcription endpoints.
Base Path: /api/v1/stt
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/stt/transcribe |
Non-streaming audio transcription |
| POST | /api/v1/stt/transcribe/stream |
Streaming transcription (SSE) |
Transcribe audio to text.
Request:
{
"audio": "<base64 encoded audio>",
"audioFormat": "wav",
"language": "en",
"prompt": "optional context hint"
}| Field | Type | Required | Description |
|---|---|---|---|
audio |
string | Yes | Base64 encoded audio data |
audioFormat |
string | Yes | Audio format: wav, mp3, aac, webm, ogg, m4a, flac
|
language |
string | No | Language code (auto-detected if omitted) |
prompt |
string | No | Context hint to improve accuracy |
Note: Maximum audio size is 5MB (calculated from base64 length).
Response:
{
"success": true,
"data": {
"text": "Hello, this is a test of the speech to text system.",
"language": "en"
}
}| Field | Type | Description |
|---|---|---|
success |
boolean | Request success status |
data.text |
string | Transcribed text |
data.language |
string | Detected or provided language |
Transcribe audio with streaming results.
Request: Same as /stt/transcribe.
Response (SSE):
data: {"chunk":"Hello, this is","language":"en"}
data: {"chunk":" a test of the speech","language":"en"}
data: {"done":true,"text":"Hello, this is a test of the speech to text system.","language":"en"}
data: [DONE]
Chunk Fields:
| Field | Type | Description |
|---|---|---|
chunk |
string | Transcribed text chunk (content events) |
language |
string | Detected language |
done |
boolean |
true on final event |
text |
string | Full transcribed text (final event) |
Text-to-speech synthesis endpoints.
Base Path: /api/v1/tts
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/tts/generate |
Non-streaming speech generation |
| POST | /api/v1/tts/generate/stream |
Streaming speech generation (SSE) |
Generate speech from text.
Request:
{
"text": "Hello, welcome to 2DAI!",
"voice": "paul",
"language": "en",
"speed": 1.0,
"outputFormat": "mp3",
"realtime": false
}| Field | Type | Required | Description |
|---|---|---|---|
text |
string | Yes | Text to synthesize (max 500 characters) |
voice |
string | Conditional | Voice model: paul, alice. Required if no referenceAudio
|
referenceAudio |
string | No | Base64 encoded reference audio for voice cloning (3+ seconds) |
referenceTranscript |
string | Conditional | Exact transcript of reference audio. Required with referenceAudio
|
language |
string | No | Language: auto, en, zh, ja, ko, de, fr, es, ru, pt, it (default: auto) |
speed |
number | No | Speed multiplier: 0.25 - 4.0 (default: 1.0) |
outputFormat |
string | No | Output format: mp3, opus, aac, flac, wav, pcm (default: wav) |
sampleRate |
number | No | Output sample rate in Hz |
realtime |
boolean | No | Use realtime mode for low-latency generation. Not compatible with voice cloning (referenceAudio) |
Response:
{
"success": true,
"data": {
"audio": "<base64 encoded audio>",
"format": "mp3",
"duration": 1.85,
"sampleRate": 24000,
"characterCount": 24,
"language": "en"
}
}| Field | Type | Description |
|---|---|---|
success |
boolean | Request success status |
data.audio |
string | Base64 encoded audio data |
data.cdnFileId |
string | CDN file ID (if audio exceeds threshold) |
data.format |
string | Output audio format |
data.duration |
number | Audio duration in seconds |
data.sampleRate |
number | Output sample rate in Hz |
data.characterCount |
number | Number of characters synthesized |
data.language |
string | Language used |
Generate speech with streaming audio chunks.
Request: Same as /tts/generate.
Response (SSE):
data: {"audio":"<base64 audio chunk>","text":"Hello, welcome","language":"en"}
data: {"audio":"<base64 audio chunk>","text":" to 2DAI!","language":"en"}
data: {"done":true,"format":"mp3","duration":1.85,"sampleRate":24000,"characterCount":24,"language":"en"}
data: [DONE]
Chunk Fields:
| Field | Type | Description |
|---|---|---|
audio |
string | Base64 encoded audio chunk (content events) |
text |
string | Text segment for this chunk |
language |
string | Language used |
done |
boolean |
true on final event |
format |
string | Output format (final event) |
duration |
number | Total duration in seconds (final event) |
sampleRate |
number | Sample rate in Hz (final event) |
characterCount |
number | Total characters (final event) |
Download and transform generated content.
Base Path: /api/v1/cdn
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/cdn/{id}.{format} |
Download/convert files |
Note: All CDN endpoints require authentication via
Authorization: Bearer <api_key>header.
Download generated content with optional resize and watermarking.
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | CDN file ID (UUID from generation response) |
format |
string | Yes | File extension: jpg, jpeg, png, gif, mp4
|
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
w |
number | No | Target width for resize (pixels) |
h |
number | No | Target height for resize (pixels) |
watermark |
string | No | Watermark image CDN ID |
position |
string | No | Watermark position (default: southeast) |
seek |
number | No | Video timestamp in ms for frame extraction |
Examples:
# Download image as JPEG
GET /api/v1/cdn/{imageId}.jpg
# Download video as MP4
GET /api/v1/cdn/{videoId}.mp4
# Download video as GIF
GET /api/v1/cdn/{videoId}.gif
# Download with watermark
GET /api/v1/cdn/{imageId}.jpg?watermark={watermarkId}&position=southeast
# Download with resize
GET /api/v1/cdn/{imageId}.jpg?w=256&h=256
# Extract video frame at 1.5 seconds
GET /api/v1/cdn/{videoId}.jpg?seek=1500Response: Binary file data with appropriate Content-Type header.
Response Headers:
| Header | Type | Description |
|---|---|---|
Content-Type |
string | MIME type: image/jpeg, image/png, image/gif, video/mp4
|
Cache-Control |
string | Cache directive (1 year) |
X-CDN-File-ID |
string | The requested file ID |
Note: The CDN supports format conversion. Request
.pngto get PNG,.jpgfor JPEG,.giffor GIF. Video frame extraction is supported via theseekparameter.
GET /api/v1/cdn/{imageId}.jpg
{
"contentType": "image/jpeg",
"size": 156703,
"statusCode": 200
}Notes: Content-Type: image/jpeg, Size: 156703 bytes
GET /api/v1/cdn/{imageId}.png
{
"contentType": "image/jpeg",
"size": 475325
}Notes: CDN returns original format: image/jpeg (format conversion not supported)
GET /api/v1/cdn/{imageId}.jpg?w=64&h=64
{
"contentType": "image/jpeg",
"size": 3467
}Notes: Resized image: 3467 bytes
GET /api/v1/cdn/{videoId}.mp4
{
"contentType": "video/mp4",
"size": 138811
}Notes: Video: 138811 bytes
GET /api/v1/cdn/{imageId}.jpg?seek=500
{
"contentType": "image/jpeg",
"size": 13133
}Notes: Frame at 500ms: 13133 bytes
Drop-in compatibility with OpenAI's API format.
Base Path: /v1
| Method | Endpoint | Description |
|---|---|---|
| GET | /v1/models |
Get available models |
| POST | /v1/chat/completions |
Chat completion (supports streaming) |
{
"object": "list",
"data": [
{
"id": "2DAI-LLM",
"object": "model",
"created": 1769121035,
"owned_by": "2DAI"
}
]
}| Field | Type | Description |
|---|---|---|
object |
string | Always "list"
|
data |
array | Array of available models |
data[].id |
string | Model identifier (2DAI-LLM) |
data[].object |
string | Always "model"
|
data[].created |
number | Unix timestamp of model creation |
data[].owned_by |
string | Model owner (2DAI) |
Request:
{
"model": "2DAI-LLM",
"messages": [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": "Hello!" }
],
"temperature": 0.7,
"max_tokens": 500
}| Field | Type | Required | Description |
|---|---|---|---|
model |
string | No | Model ID: 2DAI-LLM or default
|
messages |
array | Yes | Array of chat messages |
messages[].role |
string | Yes | Message role: system, user, assistant
|
messages[].content |
string | Yes | Message content |
stream |
boolean | No | Enable streaming (default: false) |
temperature |
number | No | Accepted but not applied |
max_tokens |
number | No | Accepted but not applied |
response_format |
object | No | Set { "type": "json_object" } for JSON mode |
Response:
{
"id": "chatcmpl-59193630-c1c7-43e5-90b4-f9b670854d9c",
"object": "chat.completion",
"created": 1769121035,
"model": "default",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello there.Zuschauer."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 111,
"completion_tokens": 6,
"total_tokens": 117
}
}| Field | Type | Description |
|---|---|---|
id |
string | Unique completion ID |
object |
string | Always "chat.completion"
|
created |
number | Unix timestamp |
model |
string | Model used (2DAI-LLM) |
choices |
array | Array of completion choices |
choices[].index |
number | Choice index (always 0) |
choices[].message.role |
string | Always "assistant"
|
choices[].message.content |
string | Generated response text |
choices[].finish_reason |
string |
"stop" or "length"
|
usage.prompt_tokens |
number | Input tokens used |
usage.completion_tokens |
number | Output tokens generated |
usage.total_tokens |
number | Total tokens used |
Note: Use model
"2DAI-LLM"or"default"for the request.
Request:
{
"model": "2DAI-LLM",
"messages": [{ "role": "user", "content": "Hi!" }],
"stream": true
}Response (SSE):
data: {"id":"chatcmpl-120f732f-cd8b-4d3c-9061-95363e65feef","object":"chat.completion.chunk","created":1769121035,"model":"default","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl-120f732f-cd8b-4d3c-9061-95363e65feef","object":"chat.completion.chunk","created":1769121035,"model":"default","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}
data: {"id":"chatcmpl-120f732f-cd8b-4d3c-9061-95363e65feef","object":"chat.completion.chunk","created":1769121035,"model":"default","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]}
data: {"id":"chatcmpl-120f732f-cd8b-4d3c-9061-95363e65feef","object":"chat.completion.chunk","created":1769121035,"model":"default","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":112,"completion_tokens":6,"total_tokens":118}}
data: [DONE]
Chunk Fields:
| Field | Type | Description |
|---|---|---|
id |
string | Completion ID (same for all chunks) |
object |
string | Always "chat.completion.chunk"
|
created |
number | Unix timestamp |
model |
string | Model used |
choices[].index |
number | Choice index |
choices[].delta.role |
string | Role (first chunk only) |
choices[].delta.content |
string | Text content (content chunks) |
choices[].finish_reason |
string |
"stop" on final chunk, else null
|
usage |
object | Token usage (final chunk only) |
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: '2dai_pk_your_key',
baseURL: 'https://api.2dai.io/v1'
});
// Works exactly like OpenAI API
const completion = await client.chat.completions.create({
model: 'default',
messages: [{ role: 'user', content: 'Hello!' }],
stream: true // Streaming supported
});
for await (const chunk of completion) {
process.stdout.write(chunk.choices[0]?.delta?.content || '');
}Note: Use model
"2dai-llm"or"default"for the request.
Request:
{
"model": "2DAI-LLM",
"messages": [{ "role": "user", "content": "Hi!" }],
"stream": true
}Response (SSE):
data: {"id":"chatcmpl-120f732f-cd8b-4d3c-9061-95363e65feef","object":"chat.completion.chunk","created":1769121035,"model":"default","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl-120f732f-cd8b-4d3c-9061-95363e65feef","object":"chat.completion.chunk","created":1769121035,"model":"default","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}
data: {"id":"chatcmpl-120f732f-cd8b-4d3c-9061-95363e65feef","object":"chat.completion.chunk","created":1769121035,"model":"default","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]}
data: {"id":"chatcmpl-120f732f-cd8b-4d3c-9061-95363e65feef","object":"chat.completion.chunk","created":1769121035,"model":"default","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":112,"completion_tokens":6,"total_tokens":118}}
data: [DONE]
Chunk Fields:
| Field | Type | Description |
|---|---|---|
id |
string | Completion ID (same for all chunks) |
object |
string | Always "chat.completion.chunk"
|
created |
number | Unix timestamp |
model |
string | Model used |
choices[].index |
number | Choice index |
choices[].delta.role |
string | Role (first chunk only) |
choices[].delta.content |
string | Text content (content chunks) |
choices[].finish_reason |
string |
"stop" on final chunk, else null
|
usage |
object | Token usage (final chunk only) |
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: '2dai_pk_your_key',
baseURL: 'https://api.2dai.io/v1'
});
// Works exactly like OpenAI API
const completion = await client.chat.completions.create({
model: 'default',
messages: [{ role: 'user', content: 'Hello!' }],
stream: true // Streaming supported
});
for await (const chunk of completion) {
process.stdout.write(chunk.choices[0]?.delta?.content || '');
}For detailed WebSocket documentation, see the dedicated WebSocket API page.
Connection: wss://api.2dai.io/ws/generation
Supported Operations:
-
generate_image- Text-to-image, img2img, or imgs2img (dual-image withimageId2) -
generate_video- Image-to-video -
generate_upscale- AI image upscale -
generate_llm- LLM text generation (supports streaming) -
generate_stt- Speech-to-text transcription (supports streaming) -
generate_tts- Text-to-speech synthesis (supports streaming)
Request:
{
"type": "generate_image",
"requestId": "req_1770076044100",
"data": {
"imageId": "f71f8d0d-488f-4b94-a260-06de434ae5ed",
"imageId2": "9cba3bf4-865f-4d2d-a0a2-92470fba2dc8",
"prompt": "blend elements from image 2 into the scene of image 1"
}
}Response:
{
"type": "generation_complete",
"requestId": "req_1770076044100",
"data": {
"result": {
"imageId": "91f613a7-5816-42a8-a6b4-543cecc09975",
"seed": 1338529555
}
}
}| Field | Type | Description |
|---|---|---|
type |
string | Always "generation_complete" on success |
requestId |
string | Matches the request ID sent |
data.result.imageId |
string | Result image CDN ID (UUID) |
data.result.seed |
number | Seed used for generation |
interface ImageGenerationOptions {
prompt: string;
style?: StylePreset | string;
format?: FormatPreset | string;
negativePrompt?: string;
seed?: number;
width?: number;
height?: number;
imageId2?: string; // Image 2 for dual-image mode (imgs2img)
watermark?: string;
watermarkPosition?: WatermarkPosition;
watermarkAsTiles?: boolean;
copyright?: string;
}interface VideoGenerationOptions {
imageId?: string;
imageBuffer?: Buffer;
prompt?: string; // Motion/animation prompt
duration?: number; // 1-10 seconds
fps?: number; // 8-60 fps
watermark?: string;
watermarkPosition?: WatermarkPosition;
}interface TextGenerationOptions {
prompt: string;
system?: string;
memory?: string[];
jsonFormat?: boolean;
jsonTemplate?: { [key: string]: string };
useRandomSeed?: boolean;
askKnowledge?: {
sources?: string[];
query?: string;
};
useMarkdown?: boolean;
imageId?: string; // For vision/image analysis
}interface UpscaleOptions {
factor?: number; // 2, 3, or 4 (default: 2)
seed?: number;
}type WatermarkPosition =
// Sharp gravity constants (recommended)
| 'center'
| 'northwest' | 'north' | 'northeast'
| 'west' | 'east'
| 'southwest' | 'south' | 'southeast'
// Human-readable alternatives
| 'top-left' | 'top-center' | 'top-right'
| 'middle-left' | 'middle-center' | 'middle-right'
| 'bottom-left' | 'bottom-center' | 'bottom-right';For Image, Video, and LLM operations:
interface ConcurrentUsage {
activeSlots: number; // Currently active operations
available: number; // Slots available
resetAt: {
window15Min: string | null;
};
}For CDN operations:
interface RateBasedUsage {
requestsPer15Min: number;
requestsPerDay: number;
resetAt: {
window15Min: string | null;
daily: string | null;
};
}| Code | Description |
|---|---|
INVALID_API_KEY |
Invalid or missing API key |
RATE_LIMIT_EXCEEDED |
Rate limit exceeded |
INVALID_REQUEST |
Malformed request body |
RESOURCE_NOT_FOUND |
Requested resource not found |
GENERATION_FAILED |
Generation failed |
INTERNAL_ERROR |
Internal server error |
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please try again later.",
"details": {
"operation": "image",
"resetAt": "2026-01-21T10:45:00.000Z"
}
}
}- Examples - Complete code examples
- Troubleshooting - Common issues and solutions
- WebSocket API - Real-time generation
← WebSocket API | Examples →