Skip to content

API for your bot

A number is 8 USD a month. Each number has its own keys. A read-only key can see recent chats and messages. A read-and-send key can also write, within that number's limits. Older history is a separate permission, messages:read_history, and it stays off while the number is warming up. Limits are not split by key: two keys on the same WhatsApp share the same send cap. Read limits belong to each key.

Put the key in the environment variable RELAY_WHATSAPP_API_KEY. The older name ENLACE_WHATSAPP_API_KEY still works. Do not write the key into instructions or a chat.

Base address: https://api.getrelay.chat

Spec: OpenAPI. Hosted MCP, with browser sign-in, is at https://api.getrelay.chat/mcp. A pasted key also works on that same path.

Bot signup

POST https://api.getrelay.chat/v1/signup-requests with a bot name and scopes. The response has an approval URL and a polling token. The person approves and pays $8 a month. On a phone, offer a pairing code: POST https://api.getrelay.chat/v1/pairing-code with the key for that number and their phone. Show the code in the chat. They open WhatsApp, Linked devices, Link with phone number. The code expires in 60 seconds. On a computer they can scan the QR instead. The first poll after WhatsApp is linked returns the API key once. A later poll does not. Sending an existing key on that POST asks for extra scopes and changes nothing until the person approves. The polling token cannot send, pay, or ask for a pairing code.

Authentication

Authorization: Bearer $RELAY_WHATSAPP_API_KEY

Hosted assistants can skip the key. They open the MCP URL, you sign in, and you pick the number. Disconnect them from My account.

Read chats

Pass limit. The largest page is 50. A missing limit is rejected.

curl -s "https://api.getrelay.chat/v1/chats?limit=20" \
  -H "Authorization: Bearer $RELAY_WHATSAPP_API_KEY"

Read messages

curl -s "https://api.getrelay.chat/v1/chats/5215512345678@c.us/messages?limit=20" \
  -H "Authorization: Bearer $RELAY_WHATSAPP_API_KEY"

Pairing code

Use the API key for that number. Pass the phone with country code. The reply is a code and expiresInSeconds. Say: WhatsApp, Linked devices, Link with phone number. Do not write the code into your logs. If that phone is already on another live number, the answer is 409 phone_in_use. With the default engine the answer is 501 and the person scans the QR.

curl -s https://api.getrelay.chat/v1/pairing-code \
  -H "Authorization: Bearer $RELAY_WHATSAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phone":"5215512345678"}'

Send one text

Send permission only. One chat at a time. A list returns 400. The same text to 5 or more chats in 10 minutes returns 429. Opening more than 30 conversations in an hour also returns 429. A new conversation is a chat with no messages, or one whose last message is older than 24 hours.

curl -s https://api.getrelay.chat/v1/messages \
  -H "Authorization: Bearer $RELAY_WHATSAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"chatId":"5215512345678@c.us","text":"Hello"}'

Responses that matter

  • 401: the key or assistant session is missing, wrong, revoked, or disconnected.
  • 403: this key can only read.
  • 409: WhatsApp is not linked. Scan another code.
  • 429: this number hit a limit. Wait. A notice is also emailed. conversation_start_limit is the cap of 30 conversations per hour. blast_not_allowed is the same text to too many chats.
  • 400 with code bulk_not_allowed: you tried to send to a list or broadcast. That cannot be turned off.

Webhooks

POST https://api.getrelay.chat/v1/webhooks with the URL and the events message or session.status. The secret is shown once. Each notice carries the signature X-Relay-Signature: sha256=… of the body, using HMAC SHA-256. Relay.chat does not store the message. It only forwards it.

Local MCP server

From the project folder: node apps/mcp/index.mjs. Set RELAY_API_URL and RELAY_WHATSAPP_API_KEY in the environment. ENLACE_API_URL and ENLACE_WHATSAPP_API_KEY still work as aliases. Tools: list_chats, read_messages, send_text, and get_account. send_text fails if the key is read-only.