Overview
An OpenAI API endpoint gives your agent a base URL that speaks the OpenAI protocol. Anything that already knows how to talk to OpenAI can talk to your agent — you paste the URL where the tool asks for an OpenAI base URL, paste an API key, and your agent shows up as a model. That covers, among others:- n8n — the OpenAI credential’s Base URL field, then any OpenAI node
- OpenRouter — adding your agent as a private / BYOK model
- Cursor, Continue, LibreChat, Open WebUI — custom OpenAI-compatible provider
- OpenAI SDKs —
OpenAI(base_url=…, api_key=…)in Python, JS, and the rest - LangChain / LlamaIndex — any
ChatOpenAI-style client that accepts a base URL
- Chat Completions (
/chat/completions, plus the legacy/completions) — the classic protocol most integrations use. - Responses (
/responses) — OpenAI’s newer stateful protocol, with server-stored responses,previous_response_idchaining, background mode and caller-supplied function tools.
Connecting a client
Two values go into the client: the Base URL from the card, and an API key from your API Keys page.…/v1/agents/youragentid/yoursubscriberid/yourtokenhere —
which works only with that subscriber’s own API key.
Do not add /chat/completions to the base URL — the client appends the route itself. If a tool asks for the “full endpoint URL” rather than a base URL, that is the one case where you add /chat/completions yourself.
The same call from the most common clients:
Streaming
Set"stream": true and the answer arrives as standard SSE chunks; add stream_options.include_usage for a final usage chunk:
Sending an image
Message content can be multi-part, exactly like OpenAI’s vision format — useful when the agent should read a photo, screenshot or scanned document:Routes
Every endpoint answers all of these routes under its base URL:Authentication
Use any API key from your API Keys page:The model name
There is nothing to configure. The endpoint advertises your agent’s name in/models (for clients with a model picker), and the model a caller sends is recorded and then ignored — default, the agent name, a typo, anything at all still gets an answer from your agent.
The model value does not pick a model. Which LLM actually answers is decided by your agent’s own LLM Routing settings.
The Advertised context window and Advertised max output fields are informational. Some clients (OpenRouter, LiteLLM) display them or use them to decide when to truncate. They don’t change what the model actually accepts — that comes from whichever model your agent routes to.
The Responses API
Every endpoint implements the stateful Responses protocol the way api.openai.com does:- Stored responses. Responses are stored by default (
"store": falseopts out) and stay retrievable for 30 days atGET /responses/{id}. - Conversation chaining. Pass
previous_response_idand the agent sees the whole prior exchange — you send only the new input. Or passconversation: "your-thread-id"and the endpoint threads turns implicitly under that id. A stored response is only visible to the API-key user that created it, on the endpoint that created it. - Caller function tools. Send
tools: [{type: "function", …}]and the agent can call your functions: the turn ends with afunction_calloutput item, you execute the function, and you continue withprevious_response_idplus afunction_call_outputinput item — the standard OpenAI tool loop. The agent’s own server-side tools keep running invisibly as usual;tool_choice(auto/none/required/a specific function) andparallel_tool_callsare honoured. - Background mode.
"background": truereturns immediately with"status": "queued"; pollGET /responses/{id}for the result, or cancel it withPOST /responses/{id}/cancel. - Structured output.
text.formatwithjson_objector ajson_schemainstructs the agent to answer as pure JSON (best-effort — the schema is enforced by instruction, not by a grammar). - The rest of the surface.
instructions(applied per call, never inherited across a chain),metadata(up to 16 keys, echoed back),max_output_tokens(a real ceiling for the turn),include,stream_options.include_obfuscation,truncation,service_tier,safety_identifieranduserare all accepted; sampling knobs (temperature,top_p,top_logprobs) are echoed back but the agent’s own LLM Routing settings decide actual sampling.prompttemplates and hosted tool types (web_search,file_search, …) are refused with a clear error — your agent brings its own tools.
Responses examples
Multi-turn withprevious_response_id — send only the new input; the endpoint replays the rest:
Conversations
With Chat Completions the protocol is stateless: the client sends the whole conversation on every call, and that history is what the agent reads. So multi-turn works out of the box — keep appending tomessages the way you would with OpenAI. With the Responses API, use previous_response_id or conversation instead (see above).
For the Inbox, consecutive calls that begin with the same first message are grouped into one thread, so a conversation appears as one entry instead of one per turn.
To control that grouping explicitly, send a chat id:
An id may be up to 128 characters of letters, digits and
. _ : @ + -. This is useful when each run of a workflow should be its own thread — n8n’s execution id makes a good chat id.
Two calls with the same id land in the same conversation:
Tool activity in responses
Your agent runs its tools server-side; a caller never seestool_calls. Show tool activity in the answer decides whether that work is visible:
- On — tool use appears inline as italic lines (
_searching the knowledge base…_), the way a chat UI shows it. Good for anything a person reads. - Off — the response is only the final answer. Usually what you want for an automation that parses the output.
Processing pipeline
Each endpoint card exposes the shared incoming-event pipeline. Every request flows through these stages before the agent sees it. By default every request reaches the agent. The stages below exist to change that. Because the caller is waiting on an open connection, an endpoint always answers: if a stage decides not to run the agent, the caller receives a standard OpenAI error rather than an empty completion or a hang.Event pre-processor
Optional code that runs in a sandbox before the classifier and the agent. Definehandle(event, ctx) and return a verdict — pass_to_agent, drop, run_tool, or respond.
event.payload is the parsed request body ({ model, messages, … }), so you can inspect or rewrite the whole conversation. A pass_to_agent verdict returning { messages: [...] } replaces the history the agent sees — that is how you redact, truncate or rewrite an incoming conversation. A respond verdict answers the caller directly without an agent run, which is a cheap way to serve canned replies.
See the Event pre-processor guide for the full contract and worked examples.
Interpreters
When one endpoint serves several different callers or workflows, Interpreters recognise each kind of request and inject a plain-language hint so the agent knows what it’s looking at. Each interpreter matches on JSON field presence (dot-paths, e.g.metadata.workflow) or regex against the raw request body, tested in order — first match wins.
See the Interpreters guide for the matching rules and examples.
Event classifier
Optional. When enabled, an LLM reads each request before the agent runs and picks React (answer it) or Drop (refuse it). Off → every request goes straight to the agent. Give it a prompt describing what this endpoint is for, e.g. “Only answer questions about our products; drop anything else.” A dropped request gets HTTP403 with "code": "request_blocked", so the caller knows it was refused rather than failing silently.
Context and Notes
- Context — instructions for the agent that apply to every call on this endpoint (e.g. “Callers here are n8n workflows. Answer in one short paragraph, no markdown.”). Added to the agent’s context for every request.
- Notes — private operator notes, never seen by the agent.
Spend budget
Owner-only advanced control.
429 with "code": "endpoint_budget_exceeded" until the period resets at UTC boundaries. Leave the cap at 0 for no limit.
Errors
Errors use the standard OpenAI envelope, so client libraries raise their normal exceptions:Testing your endpoint
Each card has a Test section. Pick a route, paste a request body, add an optional chat id, and click Run Test. The request goes through the real pipeline — interpreters, pre-processor and classifier all run — and the panel shows:- which interpreter matched, what the pre-processor and classifier decided, and the resulting outcome;
- the exact response the caller would receive, including the HTTP status;
- the exact prompt and data the agent receives — the context block added to its system prompt, any pipeline hint, and the full message array.
Setting it up in n8n
- In n8n, add an OpenAI credential.
- Set API Key to your Agentheya API key.
- Set Base URL to the endpoint’s Base URL (no
/chat/completions). - In any OpenAI node, pick your agent from the model dropdown (n8n loads the list from the endpoint) — or type any value; the model name never changes which agent answers.
X-Chat-Id so each run is its own conversation in the Inbox.
Adding it to OpenRouter
Use OpenRouter’s BYOK / private model flow, pointing it at the endpoint’s Base URL with your Agentheya API key. Use your agent’s name as the model id (any value works). OpenRouter probes/models to validate the provider, which the endpoint answers with your single model and its advertised context window.