Skip to content

API Reference

Base URL:

https://api.relay.app

Agent-to-Relay calls use:

Authorization: Bearer relay_live_your_api_key

Message creation calls require:

Idempotency-Key: developer-generated-key
Method Path Purpose
POST /v1/agents Create an agent contact from dashboard or CLI flows.
PATCH /v1/agents/{agent_id}/webhook Set and validate an agent webhook URL.
POST /v1/attachments Create an upload handle for agent-sent media or files.
POST /v1/conversations/{conversation_id}/messages Send a completed message.
POST /v1/conversations/{conversation_id}/messages?stream=true Send a Streamable-HTTP reply.
POST /v1/conversations/{conversation_id}/typing Start or stop typing state.
POST /v1/conversations/{conversation_id}/receipts Send delivery or read receipt state.
POST /v1/conversations/{conversation_id}/read Mark a user message read.
POST /v1/messages/{message_id}/reactions Add or remove a reaction.
POST /v1/messages/{message_id}/blocks/{block_id}/append Append text to a streaming block.
POST /v1/messages/{message_id}/complete Complete a streamed message.

Creates an agent contact and returns credentials. Dashboard registration uses the same shape.

{
"handle": "scheduler",
"display_name": "Scheduler",
"webhook_url": "https://your-domain.example/relay/webhook",
"capabilities": ["text", "file", "image", "link_preview", "card", "buttons"]
}
{
"agent": {
"id": "agt_01JZ8A1Relay",
"handle": "scheduler",
"display_name": "Scheduler",
"status": "pending_webhook"
},
"api_key": "relay_live_your_api_key",
"webhook_secret": "whsec_your_webhook_secret"
}

Sets the webhook URL and sends a webhook.test event. The agent becomes available after the endpoint returns 2xx.

{
"webhook_url": "https://your-domain.example/relay/webhook",
"capabilities": ["text", "file", "image", "link_preview", "card", "buttons"]
}
{
"agent_id": "agt_01JZ8A1Relay",
"webhook_url": "https://your-domain.example/relay/webhook",
"webhook_status": "verified"
}

Creates an upload URL. Send messages by referencing the returned attachment_id; do not put binary payloads in message JSON.

{
"name": "report.pdf",
"mime_type": "application/pdf",
"size_bytes": 241882
}
{
"attachment_id": "att_01JZ8F4K9M2N6P8Q0R1S3T5V7W",
"upload_url": "https://uploads.relay.app/signed/att_01JZ8F4K9M2N6P8Q0R1S3T5V7W",
"download_url": "https://cdn.relay.app/signed/att_01JZ8F4K9M2N6P8Q0R1S3T5V7W",
"expires_at": "2026-07-06T17:54:00Z"
}

POST /v1/conversations/{conversation_id}/messages

Section titled “POST /v1/conversations/{conversation_id}/messages”

Sends a message from the agent into a Relay conversation.

{
"schema": "relay.agent-send.v1",
"content": [
{
"type": "text",
"text": "I can review it. The PDF is attached to this thread."
},
{
"type": "actions",
"layout": "quick_replies",
"actions": [
{
"actionId": "act_summarize",
"label": "Summarize",
"behavior": { "type": "postback", "value": "summarize" }
}
]
}
],
"fallbackText": "I can review it. Summarize?",
"replyToMessageId": "msg_01JZ8F2W7A8B9C0D1E2F3G4H5J",
"metadata": {
"runId": "run_789"
}
}
{
"message": {
"id": "msg_01JZ8G0A2B4C6D8E1F3G5H7J9K",
"conversationId": "cnv_01JZ8D9H3J7K4M2N1P6Q8R0S2T",
"status": "sent",
"content": [
{
"id": "blk_01JZ8G0B",
"type": "text",
"text": "I can review it. The PDF is attached to this thread."
}
]
}
}

POST /v1/conversations/{conversation_id}/messages?stream=true

Section titled “POST /v1/conversations/{conversation_id}/messages?stream=true”

Starts a Streamable-HTTP reply. The request is the same send shape, and the response is text/event-stream.

{
"schema": "relay.agent-send.v1",
"content": [],
"fallbackText": "",
"stream": true
}
event: message.started
data: {"schema":"relay.event.v1","eventId":"evt_1","conversationId":"cnv_01","type":"message.started","seq":1,"message":{"id":"msg_stream_1","content":[]}}
event: message.patch
data: {"schema":"relay.event.v1","eventId":"evt_2","conversationId":"cnv_01","type":"message.patch","seq":2,"messageId":"msg_stream_1","patch":{"op":"appendText","blockId":"blk_text","path":"/text","value":"Hello"}}
event: message.completed
data: {"schema":"relay.event.v1","eventId":"evt_3","conversationId":"cnv_01","type":"message.completed","seq":3,"messageId":"msg_stream_1"}

POST /v1/conversations/{conversation_id}/typing

Section titled “POST /v1/conversations/{conversation_id}/typing”
{ "state": "start" }
{
"conversation_id": "cnv_01JZ8D9H3J7K4M2N1P6Q8R0S2T",
"state": "start",
"expires_at": "2026-07-06T17:25:00Z"
}

Stop typing:

{ "state": "stop" }

POST /v1/conversations/{conversation_id}/receipts

Section titled “POST /v1/conversations/{conversation_id}/receipts”
{
"message_id": "msg_01JZ8F2W7A8B9C0D1E2F3G4H5J",
"type": "delivered"
}
{
"message_id": "msg_01JZ8F2W7A8B9C0D1E2F3G4H5J",
"type": "delivered",
"at": "2026-07-06T17:24:15Z"
}

POST /v1/conversations/{conversation_id}/read

Section titled “POST /v1/conversations/{conversation_id}/read”

Marks a user message read in the conversation.

{
"message_id": "msg_01JZ8F2W7A8B9C0D1E2F3G4H5J"
}
{
"message_id": "msg_01JZ8F2W7A8B9C0D1E2F3G4H5J",
"type": "read",
"at": "2026-07-06T17:24:20Z"
}
{
"emoji": "+1",
"action": "add"
}
{
"message_id": "msg_01JZ8F2W7A8B9C0D1E2F3G4H5J",
"emoji": "+1",
"action": "add",
"at": "2026-07-06T17:24:30Z"
}

POST /v1/messages/{message_id}/blocks/{block_id}/append

Section titled “POST /v1/messages/{message_id}/blocks/{block_id}/append”

Fallback endpoint for agents that cannot use Streamable HTTP but still need to patch a message.

{
"path": "/text",
"value": "next token"
}
{
"message_id": "msg_stream_1",
"block_id": "blk_answer",
"revision": 3
}

Completes a streamed or patched message.

{
"status": "sent",
"fallbackText": "The completed answer."
}
{
"message_id": "msg_stream_1",
"status": "sent",
"revision": 6
}