Documentation
Use Riverz from your AI assistant
Riverz speaks MCP. With a key, any assistant that supports the protocol can query the account and act on it: which conversations went unanswered, why a message never arrived, how a campaign ended, or message a customer.
Connecting
Two steps. The first happens once; the second depends on which client you use.
Once only
Create your key in Riverz
Under Settings, Agents (MCP). Give it a name that says where it will live, for example "Juan’s laptop" or "n8n": that name is what lets you revoke one key without touching the rest.
Then choose the scope. Read only queries the account without changing anything. Read and write also lets it turn automations on and send messages.
The value is shown once. That is not an interface limitation: the database stores a hash, so Riverz cannot show it again either. If you lose it, revoke it and create another.
Depends on the client
Paste the key into your assistant
Claude Desktop, Cursor and compatible clients
In the MCP servers configuration file:
{
"mcpServers": {
"riverz": {
"type": "http",
"url": "https://riverz.co/api/mcp",
"headers": { "Authorization": "Bearer YOUR_KEY" }
}
}
}Terminal (Claude Code)
A single command:
claude mcp add --transport http riverz https://riverz.co/api/mcp \ --header "Authorization: Bearer YOUR_KEY"
The header is not optional. Without it the client reports a successful connection and then every tool fails.
Any other client
The server speaks JSON-RPC 2.0 over HTTP POST. This lists the available tools:
curl -s https://riverz.co/api/mcp \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'And this calls one. There is no need to send workspace_id: the server takes it from the key.
curl -s https://riverz.co/api/mcp \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": { "name": "conversaciones_pendientes", "arguments": {} }
}'No key, with OAuth
Clients that can discover an MCP server on their own need nothing pasted: give them the address and they open a Riverz screen where the person grants access.
https://riverz.co/api/mcp
The full flow is further down, under OAuth.
Tools
The 19 tools Riverz exposes. The list is generated from the code running in production, so it cannot fall out of date.
workspace_id shows up in several schemas because the server uses it internally, but you never send it: it comes from the key. Sending one that does not match rejects the call.
Read
They change nothing. Available with any key.
cuentas_listarLists the live accounts (workspaces) with their name, how many contacts and channels they have, and how many automations are active. It is the entry point: the workspace_id it returns is used by every other tool. With a merchant key it returns only its own.
operacion_estadoOverview of the account: connected channels, automations with their last run, how the last 24 hours of runs went, decisions waiting for approval, and the list of what needs attention (failing sends, rejected templates, stuck automations, broken connections).
por_que_no_salioExplains why a person did not receive a message. Takes a phone number and returns whether they opted out, which automations ran for that contact and with what result, which guard stopped it, and the messages that did go out. This is the diagnostic tool.
telefono (required), dias
conversaciones_pendientesThe conversations waiting for a reply: someone wrote and nobody answered, or the AI asked for a human. It is the first question of the morning.
limite
conversacion_detalleEverything known about ONE conversation without reading the messages: the summary the AI keeps, why it asked for a human, the satisfaction score the customer left, whether it came from an ad, which page of the site they were on, whether they left a payment half done, the last AI pass with the reason it did not reply, whether a reply is waiting for approval, and what it could not answer. The step before reading the thread.
conversacion_id (required)
conversacion_mensajesReads the messages of a conversation, oldest first. Each one says who wrote it (the customer, a team member or the AI), what sent it — agent, automation, broadcast —, whether it went out or failed and why, the transcript of voice notes, the reactions, and whether it is hidden and who hid it. This is what to read before having an opinion on a case.
conversacion_id (required), limite
contacto_buscarFinds a customer by phone, name or email and returns their record: tags, whether they opted out, when they last wrote, their orders and what caught their interest. Answers "who is this?" before writing to them.
busqueda (required)
contactos_listarA LIST of contacts with each one's order count and lifetime spend. With no text, the most recent ones. For browsing several; for one person's full record use contactos.detalle (by id) or contactos.buscar (by phone, name or email).
texto, limite
metricasAccount volume, closures (not verified resolutions), AI activity and orders, with the previous period. Stored paid-order amounts are separated by currency; they are not net cash or a live provider check. facturado is null without a safe single total; use por_moneda and check importes_no_disponibles. The "how are we doing?".
dias
plantillas_estadoThe WhatsApp templates with their status at Meta and the rejection reason when there is one. A rejected template cannot be used in any campaign or automation, so it is often the reason something does not go out.
campanas_estadoThe campaigns and how they ended: how many were targeted, how many received it, how many replied and how many failed. Includes the ones stuck in "sending".
dias
pedidos_listarThe orders of the account with their payment and shipping status, including tracking when it exists. Useful for telling a customer where their package is.
dias, estado_pago
etiquetas_listarThe tags that exist in the account. Use it to learn which names segments can filter by before writing a rule.
segmentos_listarSaved segments: name, how many rules each has, and when it was last touched. To see what a segment actually says, use segmentos.reglas.
segmentos_calcularHow many people a rule set reaches, without saving anything. The mandatory step before launching a campaign: it says whether the audience is the expected one.
contactos, segmento_id, reglas, modo
Action
They change something you can undo. They require a read and write key.
automatizacion_editar_esperaChanges how long a wait step waits. The step is identified by its id, which comes from the automation or from the canvas.
step_id (required), amount (required), unit (required)
Needs confirmation
Their effect reaches a person. They require a write key plus a second call carrying the confirmation token.
automatizacion_activarTurns an automation on or off. Undone by calling it again. Turning it on validates the configuration: if the template or the tag is missing, it will not activate.
automation_id (required), activa (required)
aprobacion_decidirApproves or rejects a decision that was waiting. Approving executes whatever was pending: it may charge an order.
approval_id (required), aprobar (required)
mensaje_enviarSends a WhatsApp message to a contact of the account. It reaches a real person, so it first returns what it would do and waits for confirmation.
contact_id (required), texto (required)
OAuth
For clients that discover the server on their own. Nothing gets pasted into them: they receive the address and open a Riverz screen where the person grants access. If the client can send an Authorization header, this path is unnecessary.
The flow
- The client calls
https://riverz.co/api/mcpwith no credential and gets a 401 with aWWW-Authenticateheader pointing at the discovery document. - From that document it finds the authorization server and registers itself at
/api/oauth/register. Nobody at Riverz has to create anything by hand. - It opens
/oauth/autorizar. The screen shows which application is asking, for which account, and what it will be able to do. With no session, you sign in first and land back on that same screen. - Once granted, the client receives a code and exchanges it for a token at
/api/oauth/token.
Discovery documents
GET https://riverz.co/.well-known/oauth-protected-resource GET https://riverz.co/.well-known/oauth-authorization-server
Both are public: they describe how to ask for access, they grant none.
PKCE required, S256 only
There is no client secret. Since clients register themselves, client_id proves nothing about identity: the only thing tying the exchange to whoever asked for the code is the code_verifier. Any code_challenge_method other than S256 is rejected.
Redirect URIs are matched exactly
They must match one of the registered URIs character for character. No prefixes, no wildcards: accepting partial matches is precisely how authorization codes get intercepted. https is allowed, and http only on localhost, since a desktop client cannot hold a certificate.
Scopes
mcp:read. Queries the account without changing anything.mcp:write. Also allows acting. Irreversible actions still ask for confirmation.
If no scope is requested, the most restrictive one is granted. A client that did not state what it needs does not need to write.
The token expires in an hour
That is deliberate: if it leaks, the exposure window is short. The refresh_token gets a new one without bothering the person again.
POST https://riverz.co/api/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=refresh_token&refresh_token=...&client_id=...
Access is revoked under Settings, Agents (MCP), the same as a hand pasted key. To Riverz both paths produce the same thing: a token bound to an account and a scope.
Security
The key carries the account inside it
Every key is bound to one account. If an agent sends a different workspace_id, the call is rejected. It is not silently ignored: an agent that believes it is working on another account should be told, not left to infer it from the results. The tool that lists accounts returns only its own.
A hash is stored, not the key
What is stored is a SHA-256. Anyone who obtained a copy of the database would not obtain usable keys, and for the same reason Riverz cannot show one again either.
Read only by default
A key that can message a customer and a key that only answers questions do not carry the same risk if they leak. That is why the default when creating one is read only, and the ability to write is asked for explicitly.
Irreversible actions ask for confirmation
Sending a message to a person does not run on the first call: the server returns what it would do along with a confirm_token valid for five minutes, and only that token on a second call executes it. The token is signed together with the arguments, so changing the text after someone approved it invalidates it.
It is worth knowing what that protects against. Confirmation guards against a mistake, not against a leaked key. Read only scope and revocation are what guard against that.
Everything is logged
Every call is recorded, including reads and rejected attempts. When personal data is involved, knowing who looked at what is part of the answer. The log is visible under Settings, Agents (MCP).
What that log does not keep: a contact’s phone number or the text of a message. It records which fields were used, never their contents.
Limits
- 60 calls per minute per key.
- Ten active keys per account.
- OAuth tokens expire in an hour and are renewed with the refresh token.
Common errors
-32001Invalid or missing key. The key is wrong, expired or revoked.
-32003The key only operates on its own account, or it is read only and the tool changes something. In the first case omit workspace_id: the server fills it in.
-32005More than 60 calls in one minute with the same key.
-32601The tool does not exist for this key. The ones belonging to the Riverz team are not available to an account.