Skip to main content
All relay endpoints are POST, take and return JSON, and live under one base URL:
Ringg shares the staging base URL with you during onboarding. Ringg calls your webhook with events.

Before you start

A registered number

Ringg registers your phone_number_id from the details you share.

Credentials from Ringg

Your workspace API key and the number’s signing secret, which sign every request.

Authentication

Every request carries three headers: The signature covers the exact bytes you send. Serialize the body once, sign those bytes, and send those same bytes. Re-serializing after signing changes spacing or key order and breaks the signature. Requests more than 300 seconds old or ahead are rejected.
The API key proves which workspace is calling; the signature proves the body came from you, unchanged. Both must be valid, and the API key must belong to the workspace that owns the number.

Forward a customer message

Endpoint: POST /inbound Send Meta’s value object (from entry[].changes[].value in Meta’s webhook) unchanged, one message per request.
Request
202 Accepted
202 means the message is stored and will be processed; the reply follows on your webhook. Sending the same messages[0].id again is harmless: it is processed once. If you get a 5xx or no response, retry the same request.

Custom variables

Use custom_args to give the AI agent facts about the customer that it can’t learn from the chat, such as a policy number or plan name. The agent’s prompt refers to them by name, so use the variable names agreed with Ringg.
  • Set when a chat starts. Ringg reads custom_args only from the message that starts a chat. Later messages in the same chat can’t change them.
  • Send them with every message anyway. When a chat closes or times out, the customer’s next message starts a new chat, which reads custom_args again. If you send them every time, a new chat always has them.
  • Missing and extra keys. A variable defined on the agent that you don’t send is stored as null, and the agent works without it. Keys the agent doesn’t define are stored too.
  • Where they show up. Every event for the chat carries them in custom_args, and the dashboard lists them with the conversation. Ringg adds mobile_number, the customer’s number, when you don’t send it, and source.

Events Ringg sends to your webhook

Ringg POSTs each event to your webhook URL with these headers: Answer 2xx once you have stored or queued the event, within 10 seconds. How Ringg reacts to anything else:

message.outbound

A reply to send to the customer. delivery.message is the exact body for Meta’s POST /{phone_number_id}/messages.
Then:
  • Order: send replies to Meta in sequence order per chat. Sequences start at 1 and increase by 1.
  • Expiry: don’t send a reply after its expires_at; ack it as skipped instead.
  • Ack: always ack every message.outbound.

message.typing

Sent as soon as Ringg starts working on a customer’s message. delivery.message marks the message as read and shows a typing indicator. Send it to Meta if you want the customer to see it. It has no sequence and no ack.

conversation.closed

The chat has ended, either because the AI agent closed it (reason: "completed") or because you called /close (your reason). There is nothing to send to Meta. The customer’s next message starts a new chat.

Report the result

Endpoint: POST /ack Call once per message.outbound, after you tried to send it.
Request
200 OK
  • unknown_event: Ringg doesn’t recognise the event_id, or it doesn’t belong to that chat_id. Don’t retry the ack.
  • chat_closed: true: Meta refused the reply in a way that ends the conversation (131047, 131026 or 131051). Ringg has closed the chat.

Forward delivery statuses

Endpoint: POST /status Pass on the statuses array from Meta’s status webhooks, as received. The body has exactly two fields: don’t wrap it in Meta’s entry or value.
Request
200 OK

Start a conversation

Endpoint: POST /outbound Opens a chat with a customer and returns an approved template for you to send. When the customer replies, forward it to /inbound as usual and the AI agent continues. Send an X-Idempotency-Key header to make retries safe: the same key within 24 hours returns the first response instead of opening a second chat.
Request
200 OK
Send delivery.message to Meta, then ack it with this event_id, exactly as for a message.outbound event.

Close a conversation

Endpoint: POST /close Ends a chat, for example when your human agent resolves it. Optionally sends one last message first.
Request
200 OK
closing means a final message is on its way to your webhook; without closing_message the status is closed. Either way, you then receive conversation.closed.

Handover from a human agent

When your own team has been talking to the customer, hand the conversation to the AI agent with the history so it can pick up where they left off.

Hand a conversation to the AI agent

When a human agent hands over, forward the customer’s latest message as usual, and add the messages Ringg has not seen in prior_messages.
The AI agent answers the latest message with everything above in mind: ages, city, condition, budget.

prior_messages fields

Rules

  • Order: oldest first, up to 200 messages.
  • Latest message: don’t include the customer message you are forwarding. It goes in value.messages.
  • Text only: send the text of each message. For a photo or voice note your agent handled, a short description such as [customer sent a photo of the policy] helps.
  • message_id: always include Meta’s message id. It lets Ringg recognise messages it already has, including the AI agent’s own replies, which you may store with your human agents’ messages. Without ids, Ringg can only match on text.

Send everything, or only what’s new

Either works:
  • Only what’s new. Send the messages from since the AI agent last saw the chat. This is the smallest payload.
  • A recent window every time. Send, say, the last 20 messages on every handover, including the AI agent’s own replies. Ringg skips the messages it already holds and stores the AI agent’s replies as its own, not as your human agent’s.
Either way, Ringg records each message once. It marks a handover only when one of your human agents wrote something new, or you sent a handover_note.

Take a conversation back

There is no API call to take a chat back. Your human agent simply starts answering, and you stop forwarding that chat’s customer messages to Ringg. When you hand over again, include the messages exchanged while your human agent had the chat: their replies and the customer’s messages. The AI agent then knows what was said in between.
A handover always travels with a customer message, and the AI agent answers it. Hand over with the customer’s latest unanswered message. If the customer hasn’t written since your human agent’s last reply, keep the history and send it with their next message.

End the conversation

When the conversation is done, call /close, optionally with a closing message. The customer’s next message starts a new chat.

What you see in the dashboard

In Logs → WhatsApp, a conversation that was handed over shows:
  • Handed over to AI agent where the AI agent took over.
  • Handed over to human agent where your human agent’s messages resume.
  • Human agent · Priya or AI agent above each message on the agent’s side.
  • Each handed-over message at the time it was actually sent.

Errors

Authentication and validation errors share one shape. Quote the trace_id when you contact Ringg.

Next steps

Hand over from a human agent

Pass a conversation to the AI agent with its history, and take it back.

Read chats in Logs

Every relay conversation with its transcript and analysis.