relay

Documentation

HTTP API

Every control-plane endpoint, with the auth model and curl examples. The SDK is a thin wrapper around this — you can call it directly from any language.

Authentication

All /v1/* routes require a Bearer token — your tenant's relay_live_… key from pnpm bootstrap.

-H "authorization: Bearer relay_live_…"

The single /internal/* route requires Internal $RELAY_INTERNAL_SECRET when the secret is configured — it's how the runtime calls back to the control plane for custom tool results. Don't expose this from your client.

Endpoints at a glance

MethodPathPurpose
GET/healthpublic liveness
POST/v1/runsstart a run; returns an SSE event stream
GET/v1/runslist this tenant's runs
GET/v1/runs/:idrun metadata
GET/v1/runs/:id/eventsfull event log (ordered)
POST/v1/runs/:id/tool-results/:toolUseIdSDK posts a custom tool output
PUT/v1/credentials/:providerupload or rotate
GET/v1/credentialslist (no secrets returned)
DELETE/v1/credentials/:providerrevoke
GET/v1/memories?namespace=&limit=list memories
DELETE/v1/memories/:iddelete one
DELETE/v1/memories?namespace=clear a namespace
GET/internal/runs/:id/tool-result/:toolUseIdruntime long-poll (internal-auth)

POST /v1/runs

Start an agent run. Returns an SSE stream of events.

curl -N -X POST $RELAY_URL/v1/runs \
  -H "authorization: Bearer $RELAY_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "system": "You are a helpful assistant.",
    "input": "What is 23 * 47?",
    "tools": [{ "name": "calculator", "kind": "builtin" }],
    "memory": { "namespace": "demo-user" }
  }'

Response: text/event-stream

Every event is one SSE frame. Frames look like:

data: {"type":"token","text":"23"}

data: {"type":"token","text":" *"}

data: {"type":"tool_call","id":"call_…","name":"calculator","input":{"a":23,"b":47,"op":"*"}}

data: {"type":"tool_result","id":"call_…","output":1081}

data: {"type":"done","output":"…","usage":{"input_tokens":234,"output_tokens":12}}

The response header x-run-id carries the run id — you need it to post tool results.

Errors

StatusCause
400missing model/input; unknown model family; no credential for that provider
401missing or invalid bearer token
502runtime rejected the run (network, provider error, etc.)

POST /v1/runs/:id/tool-results/:toolUseId

Used by the SDK when a custom tool fires. You can hit it directly if you're implementing your own SDK.

curl -X POST $RELAY_URL/v1/runs/$RUN_ID/tool-results/$TOOL_USE_ID \
  -H "authorization: Bearer $RELAY_API_KEY" \
  -H "content-type: application/json" \
  -d '{ "output": { "ok": true, "user": { "id": "u_001" } } }'

Credentials

# upload / rotate
curl -X PUT $RELAY_URL/v1/credentials/openai \
  -H "authorization: Bearer $RELAY_API_KEY" \
  -H "content-type: application/json" \
  -d '{"apiKey":"sk-...","label":"prod","baseUrl":"..."}'   # baseUrl optional

# list (apiKey field is never returned)
curl -H "authorization: Bearer $RELAY_API_KEY" $RELAY_URL/v1/credentials

# revoke
curl -X DELETE -H "authorization: Bearer $RELAY_API_KEY" \
  $RELAY_URL/v1/credentials/openai

Memories

curl -H "authorization: Bearer $RELAY_API_KEY" \
  "$RELAY_URL/v1/memories?namespace=user:42&limit=50"

curl -X DELETE -H "authorization: Bearer $RELAY_API_KEY" \
  "$RELAY_URL/v1/memories/<memory-id>"

curl -X DELETE -H "authorization: Bearer $RELAY_API_KEY" \
  "$RELAY_URL/v1/memories?namespace=user:42"

List & inspect runs

# list runs (paginated by ?limit, filtered by ?status)
curl -H "authorization: Bearer $RELAY_API_KEY" \
  "$RELAY_URL/v1/runs?status=completed&limit=20"

# run metadata
curl -H "authorization: Bearer $RELAY_API_KEY" \
  "$RELAY_URL/v1/runs/<run-id>"

# full event log
curl -H "authorization: Bearer $RELAY_API_KEY" \
  "$RELAY_URL/v1/runs/<run-id>/events"