Automation and HTTP Clients

n8n, Make, Zapier and Postman reach the endpoint through a plain HTTP request node.

No-code runners are ordinary HTTP clients, so they need nothing beyond the chat URL and a JSON body. The one thing to remember is to turn streaming off: most workflow nodes buffer the whole response and cannot parse an event stream.

n8n / Make / Zapier

json
// n8n: HTTP Request node (or the OpenAI node with a custom base URL)
// Method: POST
// URL:    https://zyraxonai.lovable.app/api/public/zyraxon/v1/chat/completions
// Header: Content-Type: application/json
// Header: Authorization: Bearer zyraxon
{
  "model": "zyraxon-codex",
  "messages": [{ "role": "user", "content": "{{ $json.prompt }}" }],
  "stream": false
}
⚠
Set stream to false
A workflow node that buffers the body will choke on SSE frames. Use "stream": false and read choices[0].message.content.

Postman and Insomnia

text
POST https://zyraxonai.lovable.app/api/public/zyraxon/v1/chat/completions
Content-Type: application/json
Authorization: Bearer zyraxon

{
  "model": "zyraxon-codex",
  "messages": [{ "role": "user", "content": "Hello" }]
}

Python tool-calling loop

The Python equivalent of the TypeScript loop on the SDKs page, for a runner written in Python.

python
from openai import OpenAI
import json, pathlib

client = OpenAI(base_url="https://zyraxonai.lovable.app/api/public/zyraxon/v1", api_key="zyraxon")

tools = [{
    "type": "function",
    "function": {
        "name": "write_file",
        "description": "Write text to a file on disk.",
        "parameters": {
            "type": "object",
            "properties": {"path": {"type": "string"}, "content": {"type": "string"}},
            "required": ["path", "content"],
        },
    },
}]

def run_tool(name, args):
    if name == "write_file":
        pathlib.Path(args["path"]).write_text(args["content"], encoding="utf-8")
        return f"wrote {args['path']}"
    return f"unknown tool {name}"

messages = [{"role": "user", "content": "Save a hello world file."}]

for _ in range(8):
    res = client.chat.completions.create(model="zyraxon-codex", messages=messages, tools=tools)
    choice = res.choices[0]
    messages.append(choice.message)

    if choice.finish_reason != "tool_calls":
        break

    for call in choice.message.tool_calls or []:
        result = run_tool(call.function.name, json.loads(call.function.arguments))
        messages.append({"role": "tool", "tool_call_id": call.id, "content": result})

Discovery, from a runner

An automation can read the endpoint's own description of itself, so it does not need to be updated when the model line changes.

shell
curl -s https://zyraxonai.lovable.app/api/public/zyraxon/v1/models          | jq -r '.data[].id'
curl -s https://zyraxonai.lovable.app/api/public/zyraxon/v1/provider        | jq '{modalities, overload, usage}'
curl -s https://zyraxonai.lovable.app/api/public/zyraxon/v1/integrations    | jq '.integrations[] | {id, name, category}'
★
Self-describing by design
/models, /provider and /integrations are all public and CORS-open, so a runner can configure itself at startup instead of hardcoding what ZYRAXON serves today.