Build with the NURA API
OpenAI-compatible inference for text, images, video and speech — one endpoint, many providers.
https://api.nuraix.com/v1
Localhttp://localhost:3000/v1
POST /v1/chat/completions
curl https://api.nuraix.com/v1/chat/completions \
-H "Authorization: Bearer $NURA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3-32b",
"messages": [
{ "role": "user", "content": "Hello, NURA!" }
]
}'
Your first request
The NURA API speaks the OpenAI wire format, so most OpenAI SDKs work by simply changing the base URL and key.
Base URL
Send all requests to https://api.nuraix.com/v1. When developing against a local node, use http://localhost:3000/v1.
Authentication
Authenticate with a bearer token: Authorization: Bearer <API_KEY>. Generate a key in the chat app at chat.nuraix.com.
Provider source
The optional header x-aix-source: official | workers picks first-party providers (official) or NURA GPU workers (workers). If omitted, it follows the platform default.
Make a chat completion
Send a minimal request and read the assistant reply from choices[0].message.content.
curl https://api.nuraix.com/v1/chat/completions \
-H "Authorization: Bearer $NURA_API_KEY" \
-H "Content-Type: application/json" \
-H "x-aix-source: official" \
-d '{
"model": "qwen3-32b",
"messages": [
{ "role": "user", "content": "Hello, NURA!" }
]
}'
const res = await fetch("https://api.nuraix.com/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${NURA_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model: "qwen3-32b",
messages: [{ role: "user", content: "Hello, NURA!" }]
})
});
const data = await res.json();
console.log(data.choices[0].message.content);
Chat Completions
Generate conversational and reasoning responses. Send a list of messages and stream tokens back over SSE.
| Parameter | Type | Description |
|---|---|---|
model Required | string | ID of the model to use. |
messages Required | array | The conversation so far. |
stream | boolean | Stream deltas over SSE. |
temperature | number | Sampling temperature. |
max_tokens | number | Maximum tokens to generate. |
reasoning_effort | string | Reasoning depth. |
enable_thinking | boolean | Qwen thinking phase. |
thinking_budget | number | Max tokens for thinking. |
enable_search | boolean | Alibaba web search. |
content (parts) | array | Multimodal image input. |
Streaming (SSE)
Set stream: true and read the response body incrementally, appending choices[0].delta.content.
curl -N https://api.nuraix.com/v1/chat/completions \
-H "Authorization: Bearer $NURA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5",
"messages": [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": "Explain DePIN in one sentence." }
],
"temperature": 0.7,
"max_tokens": 512,
"reasoning_effort": "medium",
"stream": true
}'
const res = await fetch("https://api.nuraix.com/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${NURA_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model: "qwen3-32b",
messages: [{ role: "user", content: "Write a haiku about GPUs." }],
stream: true
})
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop();
for (const line of lines) {
if (!line.startsWith("data: ")) continue;
const payload = line.slice(6).trim();
if (payload === "[DONE]") break;
const json = JSON.parse(payload);
const delta = json.choices[0].delta.content;
if (delta) process.stdout.write(delta);
}
}
Reasoning & web search
Reasoning models accept reasoning_effort. Alibaba Qwen adds enable_thinking, thinking_budget and enable_search.
curl https://api.nuraix.com/v1/chat/completions \
-H "Authorization: Bearer $NURA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3-32b",
"messages": [
{ "role": "user", "content": "What broke in AI news today?" }
],
"enable_thinking": true,
"thinking_budget": 2048,
"enable_search": true
}'
Image input (multimodal)
Pass images to vision models using content parts. Provide a public URL or a data: URI.
{
"model": "gpt-5",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "What is in this image?" },
{
"type": "image_url",
"image_url": { "url": "https://example.com/cat.jpg" }
}
]
}
]
}
Image Generation
Generate images from a text prompt, or edit an existing image (image-to-image).
| Parameter | Type | Description |
|---|---|---|
model Required | string | Image model. |
prompt Required | string | Text description. |
n | number | Number of images. |
response_format | string | Use b64_json. |
size | string | OpenAI-style pixel size. |
aspect_ratio | string | xAI grok-imagine ratio. |
image_url | string | Source for image-to-image. |
curl https://api.nuraix.com/v1/images/generations \
-H "Authorization: Bearer $NURA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image",
"prompt": "A neon data center on the moon, cinematic",
"n": 1,
"size": "1024x1024",
"response_format": "b64_json"
}'
const res = await fetch("https://api.nuraix.com/v1/images/generations", {
method: "POST",
headers: {
"Authorization": `Bearer ${NURA_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model: "grok-imagine",
prompt: "A koi pond, ukiyo-e woodblock print",
aspect_ratio: "16:9",
response_format: "b64_json"
// image_url: "https://example.com/ref.png" // image-to-image
})
});
const { data } = await res.json();
const pngBase64 = data[0].b64_json;
gpt-image, xAI grok-imagine, Venice / Flux, and Alibaba Qwen-Image / Wan (up to 2048²).Video Generation
Video generation is asynchronous: create a job, then poll for the result.
| Parameter | Type | Description |
|---|---|---|
model Required | string | Video model. |
prompt Required | string | Text description. |
image_url | string | Source image to animate. |
1Create the job
POST a prompt (optionally an image_url). The response returns a request_id and the provider.
curl https://api.nuraix.com/v1/videos/generations \
-H "Authorization: Bearer $NURA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "grok-imagine-video",
"prompt": "A drone shot gliding over a glowing city at night"
}'
# Response:
# { "request_id": "vid_abc123", "provider": "xai" }
2Poll for the result
Call GET /v1/videos/status with the provider and id until status is no longer processing.
async function generateVideo(prompt) {
const create = await fetch("https://api.nuraix.com/v1/videos/generations", {
method: "POST",
headers: {
"Authorization": `Bearer ${NURA_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ model: "grok-imagine-video", prompt })
});
const { request_id, provider } = await create.json();
// Poll until the job leaves "processing" (typically 40-60s)
while (true) {
await new Promise(r => setTimeout(r, 4000));
const url =
"https://api.nuraix.com/v1/videos/status" +
`?provider=${provider}&id=${request_id}`;
const res = await fetch(url, {
headers: { "Authorization": `Bearer ${NURA_API_KEY}` }
});
const job = await res.json();
if (job.status !== "processing") return job; // { status, url, b64 }
}
}
Text-to-Speech
Synthesize natural speech from text. The response returns a temporary url, inline b64 audio and its mime type.
| Parameter | Type | Description |
|---|---|---|
model Required | string | TTS model. |
text Required | string | The text to speak. |
voice | string | Voice name. |
instructions | string | Style instructions. |
language | string | Language hint. |
curl https://api.nuraix.com/v1/audio/speech \
-H "Authorization: Bearer $NURA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3-tts-flash",
"text": "Welcome to NURA, private inference for everyone.",
"voice": "Cherry",
"language": "en"
}'
# Response:
# { "url": "https://.../speech.mp3", "b64": "...", "mime": "audio/mpeg" }
const res = await fetch("https://api.nuraix.com/v1/audio/speech", {
method: "POST",
headers: {
"Authorization": `Bearer ${NURA_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model: "qwen3-tts-flash",
text: "The future of compute is decentralized.",
voice: "Ethan",
instructions: "Warm, upbeat narration"
})
});
const { url, b64, mime } = await res.json();
Cherry, Ethan, Serena, Chelsie and Dylan. Voice-clone models (qwen3-tts-vc) accept a short reference audio clip.Models
List every model currently available to your key.
Each entry reports its owned_by provider and a kind of chat, image, video or tts.
curl https://api.nuraix.com/v1/models \ -H "Authorization: Bearer $NURA_API_KEY"
{
"object": "list",
"data": [
{ "id": "qwen3-32b", "object": "model", "owned_by": "alibaba", "kind": "chat" },
{ "id": "gpt-image", "object": "model", "owned_by": "openai", "kind": "image" },
{ "id": "grok-imagine-video", "object": "model", "owned_by": "xai", "kind": "video" },
{ "id": "qwen3-tts-flash", "object": "model", "owned_by": "alibaba", "kind": "tts" }
]
}
Providers & Capabilities
Capabilities vary by provider and configured availability. A ✓ marks features described in this documentation.
| Provider | Text | Reasoning | Web search | Image | Video | TTS |
|---|---|---|---|---|---|---|
| OpenAI | ✓ | ✓ | ✗ | ✓ | ✗ | ✗ |
| Anthropic (Claude) | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ |
| xAI (Grok) | ✓ | ✓ | ✗ | ✓ | ✓ | ✗ |
| Venice | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ |
| Alibaba (Qwen / Qwen-Image / Wan / Qwen-TTS) | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ |
| DeepSeek | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ |
Notes & Cautions
A few things to keep in mind when building on the NURA API.
- Keep keys secret. API keys are secrets — never embed them in client-side code. Call the API from a server.
- You are billed per use. Requests are metered per token, image, second of video, or character of speech. See pricing.
- Stream long outputs. Streaming is strongly recommended for long completions.
- Video is asynchronous. Video jobs must be polled and can take about 40–60 seconds.
- Media URLs expire. Generated image, video and audio URLs are temporary — download promptly.
- Chat is not retained. Conversation data is not stored after inference.
- Rate limits apply. Back off and retry on
429responses. - Availability varies. Reachable models depend on the configured providers and online workers.
Need a hand? See pricing for costs, or ask the Assistant for help.