Documentation
Languages & SDKs
Two official SDKs (TypeScript, Python) and a documented HTTP + SSE protocol — wire Relay into any stack.
What's supported
The SDK contract is the same in every language: createAgent({...}) returns something you iterate, yielding events.
| Runtime | Install | Status |
|---|---|---|
| Node.js (npm / pnpm / yarn) | npm install @relayhq/sdk | Official ✓ |
| Python (pip / uv / poetry) | pip install relayhq | Official ✓ |
| Next.js (server / route handlers) | npm install @relayhq/sdk | via Node SDK ✓ |
| Bun | bun add @relayhq/sdk | via Node SDK ✓ |
| Deno | import "npm:@relayhq/sdk" | via Node SDK ✓ |
| Cloudflare Workers | npm install @relayhq/sdk | via Node SDK ✓ |
| Browser | npm install @relayhq/sdk | via Node SDK ✓ (fetch + ReadableStream) |
| Go / Rust / Ruby / PHP / Elixir / … | — | Direct HTTP + SSE (~30 LOC, see below) |
TypeScript / Node
Published as @relayhq/sdk. Zero runtime dependencies. ESM only. Node 18+.
npm install @relayhq/sdk
# or
pnpm add @relayhq/sdk
# or
yarn add @relayhq/sdkimport { createAgent } from "@relayhq/sdk";
const agent = createAgent({
apiKey: process.env.RELAY_API_KEY!,
baseUrl: "https://api.relaygh.dev",
model: "gpt-4o-mini",
});
for await (const event of agent.run("Say hi in three languages.")) {
if (event.type === "token") process.stdout.write(event.text);
}See the SDK reference for the full surface.
Python
Published as relayhq on PyPI. Pure async viahttpx. Python 3.9+.
pip install relayhq
# or
uv add relayhq
# or
poetry add relayhqimport asyncio, os
from relayhq import create_agent
agent = create_agent(
api_key=os.environ["RELAY_API_KEY"],
base_url="https://api.relaygh.dev",
model="gpt-4o-mini",
)
async def main():
async for event in agent.run("Say hi in three languages."):
if event["type"] == "token":
print(event["text"], end="", flush=True)
asyncio.run(main())Custom function tools (Python)
from relayhq import create_agent, builtin, tool
async def get_user_handler(input):
return await db.users.find(input["id"])
get_user = tool(
name="get_user",
description="Look up a user by id",
input_schema={
"type": "object",
"properties": {"id": {"type": "string"}},
"required": ["id"],
},
handler=get_user_handler, # sync or async; both work
)
agent = create_agent(
model="claude-sonnet-4-6",
tools=[builtin.calculator, get_user],
)Next.js
The Node SDK works in every Next environment — server components, server actions, route handlers, middleware. Below is a route handler that proxies an agent run as an NDJSON stream.
import { createAgent } from "@relayhq/sdk";
export async function POST(req: Request) {
const { prompt } = await req.json();
const agent = createAgent({
apiKey: process.env.RELAY_API_KEY!,
baseUrl: "https://api.relaygh.dev",
model: "gpt-4o-mini",
});
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
for await (const event of agent.run(prompt)) {
controller.enqueue(encoder.encode(JSON.stringify(event) + "\n"));
}
controller.close();
},
});
return new Response(stream, {
headers: { "content-type": "application/x-ndjson" },
});
}The client component can read it with fetch(...).body.getReader() and parse each line.
cURL / HTTP
The protocol is plain HTTP + SSE. You can use Relay from anything that can do an HTTP POST.
curl -N -X POST https://api.relaygh.dev/v1/runs \
-H "authorization: Bearer $RELAY_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "gpt-4o-mini",
"input": "Say hi in three languages."
}'Each event arrives as one SSE frame:
data: {"type":"token","text":"Hello"}
data: {"type":"token","text":" Bonjour"}
data: {"type":"done","output":"...","usage":{"input_tokens":34,"output_tokens":12}}Full API surface lives at /docs/api.
Go (no official SDK, ~30 LOC)
No third-party deps required — just net/http + bufio.
package main
import (
"bufio"
"fmt"
"net/http"
"os"
"strings"
)
func main() {
body := strings.NewReader(`{"model":"gpt-4o-mini","input":"Say hi."}`)
req, _ := http.NewRequest("POST",
"https://api.relaygh.dev/v1/runs", body)
req.Header.Set("authorization", "Bearer "+os.Getenv("RELAY_API_KEY"))
req.Header.Set("content-type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil { panic(err) }
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "data: ") {
fmt.Println(strings.TrimPrefix(line, "data: "))
}
}
}Picking an SDK
- You're shipping a Node / Next / Bun app:
@relayhq/sdk. Type-safe, batteries-included. - You're shipping a Python service / FastAPI / Django:
relayhq. Async-native, fits cleanly into existing async stacks. - Anything else: the HTTP API is small enough to wrap in an afternoon. See /docs/api.