Xenition API documentation

Build with Xenition: OpenAI-compatible chat, embeddings, images, speech, transcription and video, plus decks, diagrams, documents and 3D through one API. Pay only for calls that succeed.

Introduction

The Xenition API gives your code everything Xenition does: chat and reasoning, embeddings, images, speech, transcription, video, 3D models, decks, diagrams, documents, writing tools and more. It uses one key and one bill, and every response follows one format.

It speaks the OpenAI format. If you already use an OpenAI SDK, change the base_url, use a Xenition key and a Xenition model name, and your code works.

  • Pay as you go. Calls draw from your Xenition credits. You pay only for calls that succeed.
  • A failed call is never charged. This includes an error, a timeout, an empty answer, or a stream that breaks.
  • Free to start. Free accounts can make 10 calls (2 per service), paid from the 25,000 one-time credits of the free plan.
  • One format. OpenAI-compatible endpoints, plus /runs for everything OpenAI has no endpoint for.
Base URLhttps://api.xenition.com/api/v1
AuthAuthorization: Bearer xk_live_…
FormatJSON in, JSON out (audio endpoints return audio bytes)
Keysxenition.com → Developers

Quickstart

1. Create a key

Sign in to Xenition, open Developers in the left sidebar (/app/developers), and create a key. Copy it: it is shown only once. Keep it on your server and never in a browser or mobile app.

2. Make your first call

Set XENITION_API_KEY in your environment and run one of the examples on the right. Use the official OpenAI SDK (pip install openai or npm install openai) or plain HTTP.

3. Check the cost

Every successful response reports what it cost you in usage.cost (USD). The X-Xenition-Credits-Remaining header shows your balance after the call.

Example

curl -X POST https://api.xenition.com/api/v1/chat/completions \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"xenition","messages":[{"role":"user","content":"Hello!"}]}'

Response

{
  "id": "chatcmpl-8f2c…",
  "object": "chat.completion",
  "created": 1790726400,
  "model": "xenition",
  "choices": [{
    "index": 0,
    "message": { "role": "assistant", "content": "Hello! How can I help?" },
    "finish_reason": "stop"
  }],
  "usage": { "prompt_tokens": 9, "completion_tokens": 7, "total_tokens": 16, "cost": 0.000021 }
}

Authentication

Send your key as a bearer token on every request: Authorization: Bearer xk_live_…. Keys start with xk_live_, so secret scanners can recognise one committed by mistake. Revoke a leaked key at once from the Developers page.

A key can be limited to scopes. If no scopes are chosen, the key can use everything.

ScopeAllows
chat/chat/completions
embeddings/embeddings
images/images/generations
audio/audio/speech, /audio/transcriptions
videos/videos
runs/runs
tools/tools

Never put a key in client-side code. Call Xenition from your server and pass the result to your app.

Models

You always use a Xenition model name. What runs behind a name is managed by Xenition and improves over time without changes to your code. model is optional: each endpoint has a default.

ModelUse forEndpoint
xenitionGeneral purpose (default)chat/completions
xenition-fastLowest latency and costchat/completions
xenition-proDeeper reasoningchat/completions
xenition-codeWriting and editing codechat/completions
xenition-embedEmbeddings (default)embeddings
xenition-imageText to image (default)images/generations
xenition-videoText to video (default)videos
xenition-voiceText to speech (default)audio/speech
xenition-transcribeSpeech to text (default)audio/transcriptions

GET /models lists them with current per-token prices. Any other model name returns 400 invalid_request_error with param: "model".

Example

curl https://api.xenition.com/api/v1/models \
  -H "Authorization: Bearer $XENITION_API_KEY"

Connect over MCP

Xenition is also a remote MCP server, so any assistant that speaks the Model Context Protocol — ChatGPT, Claude, Claude Code, VS Code, Cursor and Microsoft 365 Copilot — can use your workspace directly: create and edit documents, decks, sheets, boards, forms and 3D models, build and deploy apps, run automations, and answer questions from your own files.

Unlike the REST API above, MCP needs no API key. Users sign in with their Xenition account, and the assistant acts only on that user's own workspace.

Endpoints

Both are remote Streamable HTTP endpoints. Point an MCP client at the URL — there is nothing to install or host.

URLWhat it exposes
https://api.xenition.com/mcpEverything: the full workspace and AI image, video and voice tools. Use this everywhere.
https://api.xenition.com/mcp/workspaceThe same workspace without AI media generation. This is the address listed in the Claude connector directory, which does not accept connectors that generate media with AI.

Same account, same sign-in and the same credits on both URLs. Most users only ever need the first one.

Authentication

Sign-in uses OAuth 2.1 with PKCE, discovered automatically from the server (RFC 8414 / 9728), so clients that support Client ID Metadata Documents or Dynamic Client Registration connect with nothing to configure. The first time a tool touches your workspace, the client opens a Xenition sign-in page. Utility tools — calculators, converters and the form and template catalogues — work before you sign in; anything that reads or writes your own content asks you to connect first.

Verify the connection

Listing the tools needs no key, so you can check the server from a terminal. Send a tools/list request to either URL:

Example

curl -X POST https://api.xenition.com/mcp/workspace \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-06-18" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Response

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      { "name": "search_artifacts", "title": "Search your workspace", "annotations": { "readOnlyHint": true } },
      { "name": "create_slides",   "title": "Create a slide deck" },
      { "name": "build_app",       "title": "Build a web app" }
    ]
  }
}

Add Xenition to an assistant

Give any client the one address https://api.xenition.com/mcp (or the /mcp/workspace URL where AI media is not allowed). On first use the client opens Xenition sign-in; approve it once and your workspace is available.

ClientHow to add it
Claude & Claude DesktopSettings → Connectors → Add custom connector, then paste the URL.
Claude Codeclaude mcp add --transport http xenition https://api.xenition.com/mcp
ChatGPTAdd a custom connector and paste the URL.
VS Code & CursorAdd an MCP server with the URL over HTTP transport.

Xenition is also published in the official MCP Registry as com.xenition.api/xenition, so directories and the VS Code @mcp gallery can find it without a manual URL.

Tools that only read, or that compute a result (calculators, converters, searches), run without a sign-in. Tools that create, change, publish or deploy always act on the signed-in user's own workspace and nothing else.

Pricing, credits and the free tier

How you are charged

  • Calls draw from your Xenition credits (1 credit = $0.0001): first your plan's credits, then credits you bought.
  • Before a call runs, the most it can cost is held. When it succeeds, the real cost is charged and the rest of the hold returns at once.
  • If your credits cannot cover the hold, you get 402 insufficient_credits and nothing runs.
  • Every successful response reports its cost in usage.cost (USD). Audio responses report it in the X-Xenition-Cost header.

A failed call is never charged

An error, a timeout, an empty or invalid answer, a stream that breaks before it finishes, or a video or 3D job that fails or expires: each releases the hold, and you pay nothing. Built-in tools (/tools) are always free.

Free tier

An account that has not paid yet (no paid plan, no credits, never bought any) can make 2 successful calls per service and 10 in total. Each call is charged from the 25,000 one-time credits of your free plan, at the normal price. Failed calls do not count and cost nothing. GET /usage shows what is left in free_tier. After that, upgrade or add credits to keep going.

Errors

Errors always use OpenAI's shape, so OpenAI SDKs raise their usual typed exceptions: {"error": {"message", "type", "param", "code"}}.

HTTPtypeMeaningCharged?
400invalid_request_errorBad parameters or unknown model; param names the fieldNo
401authentication_errorMissing, wrong or revoked keyNo
402insufficient_creditsNot enough credits, key cap reached, or free tier used upNo
403permission_errorThe key lacks the scope, or the account is suspendedNo
404not_found_errorUnknown id, including another account'sNo
409idempotency_errorIdempotency-Key reused with a different body, or still in flightNo
429rate_limit_errorPer-key rate limit; wait for Retry-AfterNo
502upstream_errorThe model failed to answerNo
503service_unavailableTemporarily unavailable, or busy (see Retry-After)No
504timeout_errorThe model took too longNo

Response

{
  "error": {
    "message": "Unknown model for chat. Use a Xenition model name from GET /api/v1/models.",
    "type": "invalid_request_error",
    "param": "model",
    "code": "invalid_request_error"
  }
}

Rate limits

Each key has a requests-per-minute limit (60 by default). Every response carries the OpenAI-named headers below. Over the limit you get 429 with Retry-After in seconds.

HeaderMeaning
X-RateLimit-Limit-RequestsRequests allowed per minute for this key
X-RateLimit-Remaining-RequestsRequests left in the current minute
X-RateLimit-Reset-RequestsTime until the window resets, e.g. 42s
X-Xenition-Credits-RemainingCredits you can still spend

Retries and idempotency

Send Idempotency-Key: <a unique value> with any POST to make retries safe. A repeat within 24 hours returns the first response and is never charged twice. The same key with a different body returns 409.

If the first attempt failed with a 5xx or 429, it is not remembered: your retry with the same key really runs. Those failures were not charged, so there is nothing to protect.

Retry 429, 502, 503 and 504 with exponential backoff. Do not retry 400, 401, 402, 403 or 404; fix the request first.

Example

curl -X POST https://api.xenition.com/api/v1/chat/completions \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Idempotency-Key: order-1234-summary" \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":"Summarise order 1234"}]}'

Streaming

Set stream: true on chat completions to receive tokens as they are generated, as server-sent events of chat.completion.chunk objects, ending with data: [DONE]. Add stream_options: {"include_usage": true} to get a final chunk with usage, including cost.

If the model fails mid-answer, the stream ends with data: {"error": {…}} instead of [DONE], and you are not charged. If your client disconnects but the answer still completes, it is charged, as with any completed answer.

Example

curl -X POST https://api.xenition.com/api/v1/chat/completions \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"xenition-fast","stream":true,"messages":[{"role":"user","content":"Write a haiku"}]}' \
  --no-buffer

Webhooks

Asynchronous jobs (videos and 3D runs) can call you when they finish. Pass webhook_url, a public https URL, when you create the job. You get one POST:

{"id": "evt_…", "object": "event", "type": "video.completed" | "video.failed" | "run.completed" | "run.failed", "created_at": …, "data": { …the video or run object… }}

Verify the signature

Each delivery has Xenition-Signature: t=<unix seconds>,v1=<hex>, where v1 is HMAC-SHA256 of "<t>." + raw body, keyed with your webhook secret (on the Developers page). Recompute it over the raw body, compare in constant time, and reject timestamps older than a few minutes.

Answer with any 2xx within 10 seconds. Other answers are retried with exponential backoff, up to 8 attempts.

Example

# Webhooks are received, not sent: see the Python or Node verifier.

Files and media links

Generated files (images, speech, videos, 3D models, illustrations) come back as Xenition links, …/api/v1/media/m_…. They need no key and expire after 24 hours. Download what you want to keep. Links support HTTP Range, so video players can seek.

Create chat completion

POST /chat/completions

Generates a model response for a conversation. OpenAI-compatible, including tools, JSON mode and streaming.

Parameters

NameTypeDescription
messages (required)arrayThe conversation: [{role: "system"|"user"|"assistant"|"tool", content}]. Content may be text or an array of parts (text, image_url).
modelstringxenition (default), xenition-fast, xenition-pro or xenition-code.
max_tokensintegerMaximum tokens to generate, up to 4096 (the default). max_completion_tokens is accepted too.
temperaturenumberSampling temperature, 0–2.
top_pnumberNucleus sampling.
stopstring | arrayUp to 4 stop sequences.
seedintegerBest-effort determinism.
response_formatobject{"type": "json_object"} for JSON mode.
toolsarrayFunction tools the model may call.
tool_choicestring | objectauto, none, required, or a specific function.
parallel_tool_callsbooleanAllow several tool calls in one turn.
presence_penalty / frequency_penaltynumberRepetition controls.
streambooleanStream the answer as server-sent events. See Streaming.
stream_optionsobject{"include_usage": true} adds a final usage chunk with cost.
nintegerOnly 1 is supported.

Example

curl -X POST https://api.xenition.com/api/v1/chat/completions \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"xenition","messages":[{"role":"system","content":"Reply in JSON."},{"role":"user","content":"Three fruits and their colours"}],"response_format":{"type":"json_object"}}'

Response

{
  "id": "chatcmpl-…",
  "object": "chat.completion",
  "model": "xenition",
  "choices": [{ "index": 0, "message": { "role": "assistant", "content": "{\"fruits\": […]}" }, "finish_reason": "stop" }],
  "usage": { "prompt_tokens": 24, "completion_tokens": 31, "total_tokens": 55, "cost": 0.00009 }
}

Create embeddings

POST /embeddings

Turns text into vectors for search, clustering and retrieval.

Parameters

NameTypeDescription
input (required)string | arrayA string, or up to 2048 strings (each at most 32,000 characters).
modelstringxenition-embed (default).
encoding_formatstringfloat (default) or base64 (little-endian float32; the OpenAI Python SDK requests this by default and decodes it).

Example

curl -X POST https://api.xenition.com/api/v1/embeddings \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input":["first document","second document"]}'

Response

{
  "object": "list",
  "model": "xenition-embed",
  "data": [{ "object": "embedding", "index": 0, "embedding": [0.0123, -0.0456, …] }],
  "usage": { "prompt_tokens": 4, "total_tokens": 4, "cost": 0.0000009 }
}

Create image

POST /images/generations

Generates images from a prompt.

Parameters

NameTypeDescription
prompt (required)stringWhat to draw, up to 2000 characters.
modelstringxenition-image (default).
ninteger1–4 images (default 1).
sizestring1024x1024 (default), 1536x1024 (landscape), 1024x1536 (portrait) or auto.
response_formatstringurl (a Xenition link, 24h; default) or b64_json.

Example

curl -X POST https://api.xenition.com/api/v1/images/generations \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"a red fox in the snow, watercolor","size":"1024x1024"}'

Response

{
  "created": 1790726400,
  "data": [{ "url": "https://api.xenition.com/api/v1/media/m_4f1c…" }],
  "usage": { "cost": 0.0112 }
}

Create speech

POST /audio/speech

Turns text into spoken audio. The response body is the audio file. The cost is in the X-Xenition-Cost header.

Parameters

NameTypeDescription
input (required)stringThe text, up to 4000 characters.
modelstringxenition-voice (default).
voicestringA voice name. OpenAI stock names (alloy, nova, …) select the default voice.
response_formatstringmp3 (default), opus, aac, flac or wav.

Example

curl -X POST https://api.xenition.com/api/v1/audio/speech \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input":"Welcome to Xenition."}' \
  --output welcome.mp3

Create transcription

POST /audio/transcriptions

Transcribes audio into text. Send multipart/form-data.

Parameters

NameTypeDescription
file (required)fileThe audio file, up to 25 MB (mp3, m4a, wav, webm, …).
modelstringxenition-transcribe (default).
languagestringISO language hint, e.g. en or bn.
response_formatstringjson (default), text or verbose_json.

Example

curl -X POST https://api.xenition.com/api/v1/audio/transcriptions \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -F [email protected] \
  -F language=en

Response

{ "text": "Good morning, everyone…", "usage": { "cost": 0.0021 } }

Videos

POST /videos

Video generation is asynchronous. POST /videos starts a job and returns a video object with status: "queued". Poll GET /videos/{id} until completed (or pass webhook_url), then download from GET /videos/{id}/content. GET /videos lists your recent videos.

statusMeaning
queuedAccepted, waiting
in_progressRendering
completedReady: download from /content (for 24h)
failedNo video was made; you were not charged

Parameters

NameTypeDescription
prompt (required)stringWhat happens in the video, up to 2000 characters.
modelstringxenition-video (default).
secondsstring | integerLength, 1–20 (default 5).
sizestringe.g. 1280x720 (default) or 720x1280.
webhook_urlstringA public https URL to notify when the job finishes.

Example

curl -X POST https://api.xenition.com/api/v1/videos \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"a fox running through snow at dawn","seconds":"8","size":"1280x720"}'

Response

{
  "id": "video_9c1e…",
  "object": "video",
  "model": "xenition-video",
  "status": "completed",
  "progress": 100,
  "seconds": "8",
  "size": "1280x720",
  "created_at": 1790726400,
  "completed_at": 1790726495,
  "expires_at": 1790812895,
  "error": null,
  "usage": { "cost": 2.1 }
}

Runs and capabilities

POST /runs

Everything OpenAI has no endpoint for runs through one call: decks, diagrams, documents, spreadsheet formulas, quizzes, lessons, book chapters, code edits, writing tools, research synthesis, illustrations and 3D models. Pass a capability and its input, and get a run object back.

Most capabilities finish in the same call (status: "completed"). Asynchronous ones (such as model3d.generate) return queued: poll GET /runs/{id} or pass webhook_url. Add "background": true to run any capability that way (useful for long inputs); capabilities marked background in the catalogue always run so, because they can take longer than a request may stay open. GET /capabilities (no key needed) lists every capability with its inputs:

The full capability list is live at GET https://api.xenition.com/api/v1/capabilities.

Parameters

NameTypeDescription
capability (required)stringA capability id from GET /capabilities, e.g. deck.create.
input (required)objectThe capability's inputs. Unknown inputs are rejected with 400.
webhook_urlstringFor asynchronous capabilities only.

Example

curl -X POST https://api.xenition.com/api/v1/runs \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"capability":"deck.create","input":{"source":"Q3 results: revenue up 18%, two new markets, hiring plan for Q4","title":"Q3 review"}}'

Response

{
  "id": "run_7a3f…",
  "object": "run",
  "capability": "deck.create",
  "status": "completed",
  "output": {
    "markdown": "# Q3 review\n---\n## Revenue up 18%…",
    "slides": 8
  },
  "error": null,
  "usage": { "cost": 0.0187 },
  "created_at": 1790726400,
  "completed_at": 1790726412
}

Built-in tools

POST /tools/{id}/run

Nearly 70 converters and calculators computed by Xenition itself: length, weight, temperature and data size; loan, compound interest, APR/APY, CAGR, ROI, margin, salary, split bill and unit price; and text tools such as find/replace, case formats, reading time and sort lines. Always free. GET /tools lists them with their inputs; converters take value, from and to.

Parameters

NameTypeDescription
inputs (required)objectThe tool's inputs, e.g. {"value": 5, "from": "km", "to": "mi"}.

Example

curl -X POST https://api.xenition.com/api/v1/tools/length-convert/run \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"inputs":{"value":5,"from":"km","to":"mi"}}'

Response

{
  "object": "tool.result",
  "tool": "length-convert",
  "title": "Length converter",
  "result": "5 km = 3.10686 mi",
  "usage": { "cost": 0 }
}

Forms (document generators)

GET /forms

Every one of the app's 200+ document generators: resume, cover letter, invoice, proposal, contract, emails, plans and more. GET /forms lists them (q to search, category to filter) and GET /forms/{id} shows a form's inputs. Both are public: no key needed.

Generate a document with the form.generate capability on POST /runs: pass the form id and its values. Required inputs are checked, and an input name the form does not have is refused, before anything is charged. For anything the catalogue does not cover, document.generate takes a purpose and your own labelled answers.

Results are Markdown. Turn one into a file with POST /exports/pdf.

Parameters

NameTypeDescription
qstringSearch the catalogue, e.g. resume.
categorystringOnly this category.
limitintegerAt most this many forms.

Example

curl -X POST https://api.xenition.com/api/v1/runs \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"capability":"form.generate","input":{"form":"abandoned-cart-email","values":{"brand":"Wildgrain Coffee","customer":"Jordan"}}}'

Response

{
  "id": "run_7f3c…",
  "object": "run",
  "capability": "form.generate",
  "status": "completed",
  "output": {
    "result": "Subject: Your coffee is waiting, Jordan…",
    "title": "Abandoned Cart Email"
  },
  "usage": { "cost": 0.0021 }
}

Workspace actions

POST /actions/{name}

Everything you can do in your own Xenition workspace, as the key's owner: build, edit and deploy no-code apps (and start from a template), run agents and missions, create slides and documents, export a saved document to PDF, keep notes, tasks, a calendar and a ledger, search and publish your files, ask questions across your workspace, manage automations, and more.

GET /actions lists every action with its JSON input_schema and whether it is paid. These are the same actions ChatGPT and Claude use through Xenition's MCP server, so they behave the same everywhere. The key needs the actions scope.

Actions are billed like the app: model work draws your credits, and an account at its credit limit gets 402 before a paid action runs. Reads and bookkeeping (lists, notes, tasks, deploys, PDF export) are free. Actions do not use the API's free calls. Each result reports what the call charged in usage.cost (with billed_to: "app_credits"), and the same figure appears in your usage and request log; work an action starts in the background, such as an app build, is billed as it runs.

Parameters

NameTypeDescription
input (required)objectThe action's inputs, matching its input_schema.

Example

curl -X POST https://api.xenition.com/api/v1/actions/add_task \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input":{"title":"Send the invoice to Rahim","due":"2026-10-10"}}'

Response

{
  "object": "action_result",
  "action": "add_task",
  "is_error": false,
  "text": "Added \"Send the invoice to Rahim\" to your board.",
  "data": { "…": "the updated board" },
  "usage": { "cost": 0, "billed_to": "app_credits" }
}

Export to PDF, Word, PowerPoint and Excel

POST /exports/pdf

Turn any result into a file. All four are free.

EndpointSendGet
POST /exports/pdfmarkdown, titleA print-ready PDF, with the same renderer as the app
POST /exports/docxmarkdown, titleA Word document: headings, lists, tables, links, quotes and code keep their formatting
POST /exports/pptxmarkdown (slides separated by a --- line; the first heading of each slide is its title), titleA 16:9 PowerPoint deck: deck.create output works as is
POST /exports/xlsxcsv, sheetAn Excel sheet with a bold, frozen header; numbers stay numbers, IDs and ZIP codes stay text

Images must be inline data:image/... URIs; linked images are left out (nothing is fetched).

Parameters

NameTypeDescription
markdown (required)stringThe document, up to 2 MB.
titlestringA title printed at the top.

Example

curl -X POST https://api.xenition.com/api/v1/exports/pdf \
  -H "Authorization: Bearer $XENITION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"markdown":"# Jordan Lee\n\nProduct designer…","title":"Resume"}' \
  --output resume.pdf

Usage

GET /usage

Your spend per day and kind for the last days (default 30, max 90), credits remaining, and your free tier. GET /generation?id=… returns one call's status and cost.

Parameters

NameTypeDescription
daysintegerHow far back, 1–90.

Example

curl https://api.xenition.com/api/v1/usage?days=7 \
  -H "Authorization: Bearer $XENITION_API_KEY"

Response

{
  "object": "usage",
  "days": 7,
  "data": [{ "day": "2026-09-30", "kind": "chat", "requests": 42, "failed": 1, "cost": 0.0931 }],
  "credits_remaining": 118230,
  "balance_usd": 11.823,
  "free_tier": { "active": false, "remaining_calls": 0, "total_calls": 10, "per_service": 2 }
}