message.comDevelopers

Build an AI agent with tools

Give the AI the ability to call your APIs. Order lookup, refund initiation, account changes, appointment booking. The AI decides when to call, you decide what the tool does. Tools are scoped per workspace and audited on every invocation.

Custom tools are part of the AI substrate (planned). The API surface is stable; pages and endpoints will activate when the AI rollout begins. See Custom tools reference.

1. Define the tool

A tool is a name, a description, an input schema, and a webhook URL. The model reads the description to decide when to call.

tool definition
{
  "name": "lookup_order",
  "description": "Look up an order by order number or customer email.",
  "input_schema": {
    "type": "object",
    "properties": {
      "orderNumber": { "type": "string", "description": "Order number, e.g. 4567" },
      "email": { "type": "string", "description": "Customer email" }
    },
    "anyOf": [
      { "required": ["orderNumber"] },
      { "required": ["email"] }
    ]
  },
  "endpoint": "https://api.yourdomain.com/internal/lookup_order"
}

Descriptions matter a lot. Write them like you would write a docstring for a teammate: what the tool does, when to use it, what the inputs mean.

2. Host the endpoint

Stand up an HTTPS endpoint that accepts a JSON POST and returns a JSON result. Verify the signature so a third party cannot call your endpoint directly.

server.ts
// Your endpoint receives a signed JSON POST
app.post("/internal/lookup_order", verifyMessageSignature, async (req, res) => {
  const { orderNumber, email } = req.body;
  const order = await db.orders.findOne({
    $or: [{ orderNumber }, { email }],
  });
  if (!order) return res.json({ result: "not_found" });
  res.json({
    result: "ok",
    order: {
      status: order.status,
      total: order.total,
      tracking: order.trackingUrl,
      placedAt: order.placedAt,
    },
  });
});

Verify the signature on every request. We sign every tool invocation with HMAC-SHA256 using your workspace's tool secret. Without the check, anyone with the URL could query your data.

3. Register the tool

  1. Open app.message.com.
  2. Go to Settings → AI → Custom tools.
  3. Click Add tool. Paste the definition.
  4. Copy the Tool signing secret into your server environment.
  5. Save.

4. Test in a sandbox conversation

  1. Open the test conversation panel in the dashboard (AI → Test).
  2. Ask "Where is my order 4567?".
  3. Watch the trace. The AI should pick lookup_order, pass orderNumber: "4567", then reply using the returned order data.

5. Ship to production

Tools default to shadow mode: the AI sees them but they do not run on live conversations until you flip the switch. Flip it on for the channels you want under Settings → AI → Channels.

Tool design tips

  • Keep tools narrow. One tool per intent. look up order, initiate refund, fetch account balance. A mega-tool with a command field is a recipe for confusion.
  • Return structured data, not prose. Let the model phrase the reply. Your tool returns facts.
  • Idempotent reads. Read tools are safe to retry. Mark write tools so we know not to retry on timeout.
  • Confirmation gates. For tools that mutate (refund, cancel order), require explicit visitor confirmation before calling. Surface in the agent assist sidebar for human review when in doubt.

Common pitfalls

  • Ambiguous descriptions. If the description says "look up customer", the model will call it for almost anything. Be specific: "Look up an order by number or email".
  • Slow endpoints. If your tool takes 10 seconds, the chat feels broken. Cap at 3 seconds. Return early; fan out async if needed.
  • Leaky errors. Do not return raw database errors. Return { result: "not_found" } or { result: "service_unavailable" }.
  • Auth bypass. The signed visitor identity is part of the tool invocation payload. Use it to scope queries; do not let the AI ask "show me order 9999" for a visitor who does not own that order.

Next steps