← All posts
Engineering6 min read

[ENGINEERING] · Jun 5, 2026 · 10:00

Build a custom chatbot on the muro API, with your own model

Receive a visitor message, run it through whatever model you choose, and post the answer back as an agent. Your logic, your model, your keys. No black box.

Tm

The muro team

muro.chat

#api#ai#chatbot#byok#llm#integrations#engineering

Bundled chat bots are a black box: you cannot see the prompt, you cannot pick the model, and your conversations train someone else's system. The muro API lets you build the bot yourself, on the model you trust, with the data staying in your hands. The loop is three steps.

The loop

  1. 01A visitor sends a message. muro fires a message.created webhook to your endpoint.
  2. 02Your code calls the model of your choice with the message and any context you want.
  3. 03You POST the model's answer back to the conversation through the REST API.

1. Receive the message

Subscribe to message.created in Settings, then Webhooks. Verify the HMAC signature, ignore events where sender_type is agent (those are your own replies, you do not want a loop), and act only on visitor messages. The webhooks guide has the verification code.

2. Generate a reply

This is your code and your call. Use any provider, your own self-hosted model, a retrieval step over your docs, whatever fits. Because you own this step you can ground answers in your real product data and keep full control of the prompt. Nothing about it is locked to muro.

3. Post the answer back

Send the reply as an agent message and the visitor sees it in the widget instantly. Or send it as a note first if you want a human to approve before it goes out.

typescript// Inside your webhook handler, after verifying the signature
const event = JSON.parse(rawBody);
if (event.type !== 'message.created') return ok();
if (event.data.message.sender_type !== 'visitor') return ok();

const answer = await yourModel.reply(event.data.message.content);

await fetch(
  'https://muro.chat/api/v1/conversations/' + event.data.message.conversation_id + '/messages',
  {
    method: 'POST',
    headers: {
      Authorization: 'Bearer ' + process.env.MURO_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ content: answer, kind: 'agent' }),
  },
);

Human handoff

A good bot knows when to step back. When the model is unsure, post a note instead of an agent reply so your team picks it up, or simply do not reply and let the conversation sit in the inbox for a human. The visitor never sees a confident wrong answer.

✦ ✦ ✦

Three steps: receive, generate, reply. The two muro halves (a webhook in, a REST call out) are the easy part. The interesting part, the model and the logic, stays entirely yours.

Tm

✎ Written by

The muro team

muro.chat