Connecting an AI Agent

How to give an AI agent access to a customer inbox without giving it the ability to cause damage

An AI agent is a caller that can be talked into things. A customer message, a contact field, a help article - anything the model reads can carry an instruction, and the model has no reliable way to tell your instruction from a stranger's. So the design question is not whether the agent behaves, it is what the agent is still able to do when it misbehaves.

This page is the division of labour: what Wexio enforces for you, and what only you can enforce.

What Wexio Enforces

A Key That Cannot Reach the Wrong Customer

Mint the agent's key bound to one client org. A bound key acts on that org and returns 403 for every other id, including your own provider org. The agent cannot read or write another customer's inbox even if it is instructed to, because the credential has no reach there.

A Key That Cannot Start Conversations

Give the agent MESSAGES_SEND without CONVERSATIONS_START. It can then answer chats that already exist and cannot open new ones. An agent persuaded to cold-message a list simply has no operation that would do it.

A Ceiling on the Damage per Day

Set a dailySendCap. A prompt-injected loop stops at the cap instead of running until someone notices, and the cap fails closed. Size it as the ceiling you accept during an incident.

Per-Client Webhook Secrets

Register a webhook per client org rather than one fan-out for everybody. Each gets its own URL and its own signing secret, so a leaked secret is scoped to one customer and can be rotated without touching the others.

An Audit Trail You Did Not Have to Build

Every write and every denial is recorded per key for 90 days, with the operation, the target org and a deny reason. Outbound messages carry apiKeyId. When something goes wrong you can establish what the agent did, which agent did it, and what it was refused.

None of this stops the agent from writing something wrong inside its own client's inbox. Wexio can constrain reach, rate and identity. It cannot judge the content of a reply. That part is yours.

What You Have to Enforce

The Dispatcher Chooses the Org, Never the Model

Resolve the target org in your code, from the webhook payload, and pass it as orgId. Do not put the org id in the model's context and do not accept it from a tool argument the model fills in.

A bound key makes this safe by construction, since there is only one org it can reach. If you run one unbound key across many clients, the org id is the whole security boundary and a model that can choose it can cross between customers.

Treat Everything the Agent Reads as Hostile

Customer messages, contact fields, notes, file names, help content: all of it is attacker-controlled text that will reach your prompt. Read it through a step that strips or neutralises instruction-shaped content before it becomes context, and keep it clearly separated from your own instructions.

A practical rule: inbound content is data to be summarised, never instructions to be followed. If your prompt cannot express that boundary, the model will not invent it.

Check the Output Before It Reaches a Customer

The agent's reply is going to a real person on the customer's channel. Check it on your side for the things you cannot take back: other customers' data, credentials, links you did not intend, promises you cannot honour. A reply that fails the check should go to a human, not out.

Verify Intake Properly

Three things, together, on every webhook you receive:

SignatureHMAC-SHA256 over the raw body. During a secret rotation the header carries two v1 values - accept if either matches.
TimestampReject t older than 300 seconds.
Event idDedupe on X-Wexio-Event-Id. Retries reuse the id, so this is what stops a replayed delivery becoming a second reply.

The verification snippet, rotation-aware and constant-time, is in the envelope reference.

Dedupe matters more with an agent than with a plain integration. A duplicate delivery to a webhook that files a ticket is a duplicate ticket. A duplicate delivery to an agent is a second, differently worded reply to the same customer, which reads to them as a system that does not know what it already said.

Putting It Together

A reasonable shape for an agent serving many client orgs:

  1. One key per client, bound to that client, MESSAGES_READ + MESSAGES_SEND, no CONVERSATIONS_START, with a daily cap and an IP allow-list.
  2. One webhook subscription per client, each with its own secret.
  3. Your dispatcher verifies the signature, the timestamp and the event id, resolves the client from the payload, and selects that client's key.
  4. The model sees the conversation as data. It never sees the org id, the key or another client's content.
  5. The reply passes an output check before it is sent.
  6. apiKeyId and the audit log are how you reconcile afterwards.

What this buys you is not a well-behaved agent. It is an agent whose worst case is one wrong reply in one inbox, capped and attributable - instead of a cross-customer incident.

On this page