Skip to main content
There are two ways to answer Relay conversations on Cloudflare, and which one you want depends on whether you already have an agent. Prerequisites for both:
  • An agent and its Agent Token. See Create and connect an agent.
  • A Cloudflare account. Both paths deploy with wrangler.
  • Node 20 or newer.

Add Relay as a channel to a Think agent

Think builds a channel by wrapping a Chat SDK adapter in messengerChannel(). That is how its own Telegram channel is built. Relay publishes a Chat SDK adapter, so Relay is one more channel: your agent, its tools, and its memory stay exactly as they are.
1

Install the adapter

On Workers, the adapter must be 0.2.1 or newer.
2

Declare the channel

The channel id names the route. Called relay, it serves POST /messengers/relay/webhook.
src/index.ts
3

Set the secrets and deploy

4

Register the webhook

Save signing_secret from the response, then set it:
5

Message your agent

Open Relay, find your agent, and send it a message. It replies.
An unsigned or forged delivery to the webhook route returns 401 before Think parses anything.
Think owns the parts a channel needs, so you write none of them. Two Relay rules shape what arrives on the other end. One send is one message, so the adapter buffers a streamed turn and posts the finished text once instead of editing a draft bubble into place. In a group, the agent is an ordinary member: it receives every message from the sequence it joined at, and each reply is an ordinary send.
A runnable version of this is examples/think-channel in the starter repository.

Deploy the starter

Deploy relay-agent-starter to answer Relay conversations from a Cloudflare Agent. Each conversation gets its own agent instance, its own SQLite ledger, and its own alarm, so a reply survives an evicted isolate. Replace one function with your model call and it is your agent.
The starter is developed in the public relaymessenger/relay-agent-starter repository. It depends on Cloudflare’s agents package and nothing of Relay’s own beyond the HTTPS API documented on this site.
1

Scaffold or deploy the starter

Use the one-click deploy:Deploy to CloudflareOr scaffold locally, then deploy:
Note the deployed URL. It looks like https://relay-agent.<your-subdomain>.workers.dev.
Never add --accept-defaults to the scaffold command. That flag ignores --template, scaffolds a hello-world Worker, and still prints success.
2

Set the Agent Token

The deploy button prompts for it. Locally:
3

Register the webhook

Point Relay at /webhooks/relay on the deployed Worker:
Save signing_secret from the response. Relay never returns it again.
4

Set the signing secret and redeploy

5

Message your agent

Open Relay, find your agent, and send it a message. It replies.
GET /healthz on the Worker returns {"ok":true} when it is up.

What it uses from the Agents SDK

The starter is a normal Cloudflare Agents project. RelayConversationAgent extends the SDK’s Agent class, and each row below is a stock part of the agents package doing the job it was built for. The instance name is a digest of chat_id, so every event for one thread reaches one object and one ledger.
The starter serves explicit routes only, with no routeAgentRequest fallthrough. That helper’s default /agents/<binding>/<name> shape includes an unauthenticated WebSocket that syncs agent state to any caller. Keep the fallthrough out unless you are authenticating it yourself.

What the starter handles for you

Each row is a contract from these docs that the starter implements.
The ledger stores identifiers only. Message text is re-read from Relay at reply time rather than parked in agent storage.

Write your agent

Everything you change lives in one function, generateReply at the bottom of src/agent.ts:
src/agent.ts
text is the whole user turn, with the messages of a burst joined back in order. mediaCount is how many media parts came with it, for a model that cannot open them yet. Call any model from there. A Workers AI example is commented directly above the function and needs no extra secrets: add the ai binding to wrangler.jsonc, uncomment AI in src/env.ts, and swap the return.
Keep the call inside the Worker CPU budget. Longer work belongs behind another schedule() call, which is the same alarm mechanism the reply already uses.

Secrets

RELAY_API_ORIGIN is a plain var, already set to https://api.relayapp.im.

Running it as a plain Worker

The starter needs the Agents SDK, because the ledger, the state, and the alarm are the SDK’s. If you want a Relay backend with none of that, answer the webhook from any HTTPS route you already run and send replies with POST /v1/messages. Webhooks has the verification steps. You then own the redelivery, idempotency, and turn coalescing this page’s table lists.

Next steps