Open Workspace

Developers

The Dyadic API.

Use Iris from OpenAI-compatible apps and SDKs: an OpenAI-compatible subset with a published contract, one key, your credits, the same assistant as the Workspace.

Base URL

Point an OpenAI-compatible app or SDK here and use a Dyadic API key. The Dyadic API is an OpenAI-compatible subset, not all of OpenAI's API: the compatibility table below says what each endpoint supports. Requests use your account's credits and plan, like the Workspace.

https://dyadic.app/api/openai/v1

Explore

Quick Start

  1. Create a key in the Workspace under API, and set limits if you like.
  2. Set your app's base URL to https://dyadic.app/api/openai/v1 and paste the key.
  3. Pick a model: iris, or iris-think for harder questions.
curl
curl https://dyadic.app/api/openai/v1/chat/completions \
  -H "Authorization: Bearer $DYADIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "iris", "messages": [{"role": "user", "content": "Hello"}], "stream": true}'

Anthropic-Compatible API

Apps built on Anthropic's SDKs or its Messages API, Claude Code included, can use Dyadic too: set the base URL to https://dyadic.app/api/anthropic and the API key to a Dyadic key (sent as x-api-key). Requests run like the OpenAI-compatible ones, with the same key, limits, credits and activity log, and are answered by the model chosen for this API. A model name is one of your key's agents (iris, iris-think) or any Claude model name.

Python
import anthropic

client = anthropic.Anthropic(base_url="https://dyadic.app/api/anthropic", api_key=DYADIC_API_KEY)
message = client.messages.create(model="iris", max_tokens=1024,
                                 messages=[{"role": "user", "content": "Hello"}])
FeatureDetails
Messages/v1/messages, streamed or not: text, images and PDFs, system prompts and stop sequences.
ToolsYour tools, tool_use and tool_result blocks, tool_choice (auto, any, tool, none) and disable_parallel_tool_use, streamed as input_json_delta.
Thinkingadaptive with output_config.effort, enabled with budget_tokens, or disabled. A thinking block carries the signature its model gave, so it can go back on the next turn; a model that gives none leaves it empty, never made up.
Prompt cachingcache_control on blocks, or at the top level for the last one; usage reports cache reads and writes.
Structured outputoutput_config.format with a JSON schema.
Counting and models/v1/messages/count_tokens and /v1/models; the whole API is described in OpenAPI at /api/anthropic/v1/openapi.json.
ErrorsAnthropic's shapes and statuses, with a request-id; out of credits or over a key's limit is 402 billing_error.
Server toolsweb_search and web_fetch on Dyadic's own search and page reader, code_execution in Dyadic's containers (Python and bash; the key's Code Interpreter switch), and remote MCP servers (mcp_servers; the key's MCP switch), answered with Anthropic's blocks (server_tool_use and its result, mcp_tool_use and mcp_tool_result). max_uses is enforced and usage.server_tool_use counts the requests. Search results carry no encrypted_content, and answers carry no citations.
Client toolsAnthropic's bash, text editor and memory tools: your app runs them, as with Anthropic. Claude on Anthropic gets Anthropic's own definitions; another model gets them described as functions.
Files and batches/v1/files keeps files with your API files (images and documents name one by file_id), and /v1/messages/batches runs up to 5,000 requests on Dyadic's batch runner, its results as Anthropic's JSONL. Both need the key's Files switch.
Not offeredDomain limits on web search and fetch, Anthropic's skills, the computer and browser toolsets and tool search are refused with 400.

OpenRouter-Compatible Gateway

Apps built for OpenRouter reach its models through Dyadic: set the base URL to https://dyadic.app/api/openrouter/v1 and use a Dyadic key with the AI gateway switch. The gateway reaches any of OpenRouter's models at the platform's cost, so Dyadic turns it on for an app's key on request; you can turn it off in the key's settings at any time, and turning it back on is Dyadic's. A key without it is answered 403 gateway_not_allowed: the policy, not a fault. Requests and answers are OpenRouter's, forwarded unchanged: its model ids, models fallback lists, provider routing, reasoning, plugins and usage.cost. Each request counts against the key's limits, is billed to your account and shows in its activity, on your own OpenRouter key when the key carries one.

Python (OpenAI SDK)
from openai import OpenAI

client = OpenAI(base_url="https://dyadic.app/api/openrouter/v1", api_key="dya-...")
reply = client.chat.completions.create(model="anthropic/claude-haiku-5.5",
                                       messages=[{"role": "user", "content": "Hello"}],
                                       extra_body={"models": ["openai/gpt-6-luna"], "usage": {"include": True}})
PathWhat It Does
/chat/completions, /completions, /embeddings, /audio/speech, /audio/transcriptions, /imagesForwarded to OpenRouter; the key's Images, Embeddings, Audio and Moderate switches apply.
/models, /models/{author}/{slug}/endpointsOpenRouter's models and their providers' prices.
/generationA generation's cost and tokens, for this key's own requests only.
/key, /creditsAnswered by Dyadic: the key's usage and limits, and your account's allowance, in dollars.

Described in OpenAPI at /api/openrouter/v1/openapi.json.

Works with

Apps and SDKs that use the endpoints and fields in the compatibility table, including the official OpenAI Python SDK (tested with 3.26.0):

Kilo CodeRoo CodeClineContinueOpen WebUILibreChatJanitorAISillyTavernOpenAI Python and Node SDKsLangChainn8n

Supported

FeatureDetails
StreamingServer-Sent Events with content, reasoning_content and tool-call fragments, and a final usage chunk with stream_options.include_usage.
Function callingYour tools, tool_choice and parallel_tool_calls, streamed argument by argument.
Structured outputresponse_format: json_object or json_schema.
Generation Settingstemperature, top_p, top_k, min_p, presence_penalty, frequency_penalty, repetition_penalty, seed, logit_bias, stop, max_tokens, reasoning_effort, logprobs.
Responses API/responses with streaming events, function calling, web search, stored responses, previous_response_id, conversations, background responses with cancel, input token counts, compaction and a WebSocket mode.
Conversations/conversations and their items, continued with the Responses conversation parameter.
Stored chat completionsstore: true keeps a chat completion 30 days: list, retrieve, update its metadata, delete, and read its messages.
Embeddingsiris-embed and iris-embed-large (Iris's names for text-embedding-3-small and -large), text-embedding-3-small, text-embedding-3-large and text-embedding-ada-002, as floats or base64.
AudioText to speech with iris-voice or OpenAI's model and voice names (mp3, wav, pcm); transcription and translation with iris-transcribe, Whisper and GPT-4o models (json, text, srt, vtt, verbose_json). In runs, Iris can speak (audio.speak) and transcribe an uploaded recording (audio.transcribe).
Moderations/moderations in OpenAI's format, for text and images (iris-moderation or OpenAI's model names).
Decisions/decisions in OpenAI's beta format: typed answers (a predicate's probability, a choice, a rubric score) to questions about text or images, paid on input. Needs the key's Decisions switch.
ImagesImages in messages (https or data URLs), /images/generations, /images/edits and /images/variations.
Files and batchesUpload files to reference by file_id in messages, and run JSONL batches of chat, Responses, embeddings or moderation requests in the background.
Hosted toolsIn /responses: code_interpreter and shell (Python and Bash in an offline container, files at /mnt/data), file_search over your vector stores, image_generation, and mcp for tools on a public HTTPS MCP server, with approvals unless you turn them off. Each needs its switch on the key.
Containers, vector stores and skills/containers and their files (expire after 20 minutes without use), /vector_stores with files, file batches and search, and /skills with versions, mounted read-only into containers.
Not offeredAssistants, Assistants threads, ChatKit, content provenance checks, evals, fine-tuning, multi-part uploads (use /v1/files), safety checks, the admin API, the Live API, the organization API, the Realtime API, the retired edits endpoint, the retired engines endpoints, video generation and webhooks return 404 unsupported_endpoint.
Tracing and limitsEvery response has an X-Request-Id (errors too); your own X-Client-Request-Id is kept in your activity log; x-ratelimit-* headers show the key's requests per minute and token limit.
ContextYour whole conversation is sent; the model's context window is the limit. Keys can add your memory or a Workspace library's context.

Compatibility

The Dyadic API is an OpenAI-compatible subset. An OpenAI field an endpoint knows but can't honor is refused with 400 and code unsupported_parameter (the field in param), never silently dropped; a field OpenAI doesn't define for the endpoint is ignored and named in the X-Dyadic-Ignored-Parameters header. The same contract is machine-readable at /capabilities (version 1.1.0).

EndpointAppliesOnly These ValuesRefusedAccepted, No Effect
POST /chat/completionsfrequency_penalty, function_call, functions, logit_bias, logprobs, max_completion_tokens, max_tokens, messages, metadata, min_p, model, parallel_tool_calls, presence_penalty, reasoning, reasoning_effort, repetition_penalty, response_format, safety_identifier, seed, stop, store, stream, stream_options, temperature, tool_choice, tools, top_a, top_k, top_logprobs, top_p, user, verbosityn (1), service_tier (auto / default), modalities (text)audio, moderation, prediction, web_search_optionsprompt_cache_key, prompt_cache_options, prompt_cache_retention, stream_options.include_obfuscation
POST /completionsfrequency_penalty, logit_bias, max_completion_tokens, max_tokens, min_p, model, presence_penalty, prompt, reasoning, reasoning_effort, repetition_penalty, response_format, seed, stop, stream, stream_options, temperature, top_a, top_k, top_p, usern (1), best_of (1), echo (false), logprobs (false), suffix ('')nonestream_options.include_obfuscation
POST/GET /responsesbackground, conversation, input, instructions, max_output_tokens, metadata, model, parallel_tool_calls, previous_response_id, reasoning, safety_identifier, store, stream, stream_options, temperature, text, tool_choice, tools, top_logprobs, top_p, userinclude (message.output_text.logprobs / message.input_image.image_url / reasoning.encrypted_content / code_interpreter_call.outputs / file_search_call.results), service_tier (auto / default), truncation (disabled)access_programs, context_management, max_tool_calls, moderation, promptprompt_cache_key, prompt_cache_options, prompt_cache_retention, reasoning.generate_summary, reasoning.summary, stream_options.include_obfuscation
POST /responses/input_tokensconversation, input, instructions, model, parallel_tool_calls, previous_response_id, reasoning, text, tool_choice, toolstruncation (disabled)personalitynone
POST /responses/compactinput, instructions, model, previous_response_idservice_tier (auto / default)noneprompt_cache_key, prompt_cache_options, prompt_cache_retention
POST /conversationsitems, metadatanonenonenone
GET/POST/DELETE /conversations/{conversation_id}metadatanonenonenone
GET/POST /conversations/{conversation_id}/itemsitemsnonenonenone
GET/DELETE /conversations/{conversation_id}/items/{item_id}nonenonenonenone
GET/POST/DELETE /chat/completions/{completion_id}metadatanonenonenone
GET /chat/completions/{completion_id}/messagesnonenonenonenone
POST /embeddingsdimensions, encoding_format, input, model, usernonenonenone
POST /moderationsinput, modelnonenonenone
POST /decisionsinput, model, questionsnonenonenone
POST /images/generationsprompt, quality, size, usern (1), background (auto), moderation (auto), partial_images (0), stream (false)output_compression, output_format, stylemodel, response_format
POST /images/editsimage, prompt, quality, size, usern (1), background (auto), partial_images (0), stream (false)input_fidelity, mask, output_compression, output_formatmodel, response_format
POST /images/variationsimage, size, usern (1)nonemodel, response_format
POST /audio/speechinput, model, response_format, speed, voicestream_format (audio)instructionsnone
POST /audio/transcriptionsfile, language, model, prompt, response_format, temperature, timestamp_granularitiesstream (false)chunking_strategy, include, known_speaker_names, known_speaker_referencesnone
POST /audio/translationsfile, model, prompt, response_format, temperaturenonenonenone
POST/GET /filesfile, purposenoneexpires_afternone
POST/GET /batchescompletion_window, endpoint, input_file_id, metadatanoneoutput_expires_afternone
POST/GET /containersexpires_after, file_ids, name, skillsmemory_limit (1g), network_policy ({'type': 'disabled'})nonenone
POST/GET /containers/{container_id}/filesfile, file_idnonenonenone
POST/GET /vector_storeschunking_strategy, expires_after, file_ids, metadata, namenonenonenone
GET/POST/DELETE /vector_stores/{vector_store_id}expires_after, metadata, namenonenonenone
POST /vector_stores/{vector_store_id}/searchfilters, max_num_results, query, ranking_optionsnoneranking_options.hybrid_searchranking_options.ranker, rewrite_query
POST/GET /vector_stores/{vector_store_id}/filesattributes, chunking_strategy, file_idnonenonenone
GET/POST/DELETE /vector_stores/{vector_store_id}/files/{file_id}attributesnonenonenone
POST /vector_stores/{vector_store_id}/file_batchesattributes, chunking_strategy, file_ids, filesnonenonenone
POST/GET /skillsfilesnonenonenone
GET/POST/DELETE /skills/{skill_id}default_versionnonenonenone
POST/GET /skills/{skill_id}/versionsdefault, filesnonenonenone