Build a multi-user AI app with RelayLink

Authenticate each sender or inbox owner as their own RelayLink account, keep credentials tenant-scoped, and route portal-created webhook envelopes back to the right user.

4 min read

You are building a SaaS assistant for many customers. Each customer should be able to send and receive RelayLink briefings, but your backend has one deployment and one job queue. The dangerous shortcut is to place one RelayLink key in the service and attach a tenant ID to each call.

For application architects and integration engineers, the correct design starts with a separate RelayLink identity for every application user who sends, owns an inbox, or connects an assistant. A person who only receives and replies by email does not need an account.

Treat RelayLink authentication as user delegation, not service authentication. An OAuth access token or API key identifies one person's RelayLink account. It determines the inbox, drafts, threads, and contacts the request can reach.

Your tenant ID does not override that identity. Do not accept relaylinkUserEmail from application code and combine it with a shared credential. The shared key still belongs to one account, so every request would act as that person regardless of the email your app labels it with.

Keep an explicit mapping:

  1. Your signed-in application user
  2. Their RelayLink connection
  3. The credential or token reference stored inside that tenant's secret boundary
  4. The RelayLink account identity returned by whoami

Use whoami during connection verification so the user can see which account and server they connected.

Prefer delegated sign-in, isolate key fallback

When your client supports OAuth, send the person through RelayLink sign-in and consent. Store tokens against that application user. Refresh and revoke them as delegated credentials, and do not move them between tenants.

If your integration cannot support OAuth, the person can issue a named API key in the browser and enter it into a connector settings field. Issuing is not an assistant tool. Give the key a name tied to the integration and store it in your application secret system, never in a model prompt or conversation transcript.

Use one key per user integration. A key shared by several customers makes those customers indistinguishable to RelayLink and turns one revocation into an outage for all of them.

Keep the approval boundary visible

RelayLink is not a single-call delivery API. Your app calls draft_package, presents the returned preview to the authenticated user, and calls confirm_send only after that user approves.

Do not hide those steps behind an “automatic outreach” switch. The user should know which account is sending, who will receive the package, and what wording is crossing. If your app supports several personas, personas may shape drafts, but they do not replace the RelayLink account identity.

The same user scoping applies on reads. Call inbox and thread operations with the credential belonging to the user whose screen or agent is requesting them. Do not fetch into a common cache and filter by tenant afterward.

Webhooks wake the right tenant

Where the RelayLink host offers outbound webhooks, registration is a human portal action at /account/webhooks. It is not an MCP tool or a public provisioning API, so your backend must not imply that it can register a receiver for the user. The account holder chooses the HTTPS endpoint and receives the signing secret once.

One account registers its own endpoint. A shared receiver deployment must not give every tenant one identical URL and expect the POST body to identify the owner: neither the body nor the headers contain a recipient id or subscription id. Generate an opaque route for the user or subscription, map that route to the user's RelayLink connection, and have the account holder register that URL in the portal. Store the one-time signing secret with the same tenant-scoped integration record. Do not put a RelayLink credential in the webhook URL.

The POST is an envelope, not the briefing. It includes a delivery identifier, package and thread identifiers, sender information, topic, time, reply status, and the host's MCP address. Resolve the endpoint route to the expected tenant and signing secret, verify the timestamp and signature, deduplicate on the delivery identifier, then call get_package with that user's credential.

Outbound webhooks explains why content stays out of the POST. A successful webhook delivery only means your receiver accepted the envelope. The authenticated package fetch is the content step.

Fit and non-fit

This architecture fits a SaaS assistant that acts for identifiable people, keeps tenant credentials apart, and asks each person to approve outgoing correspondence.

It does not fit a bulk messaging engine, a shared service bot, or a queue where your company wants one key to speak as many customers. If the user-owned model is right, connect through the live reference page, verify identity, and keep every subsequent operation inside that user's boundary.

Frequently asked questions

Can a SaaS app use one RelayLink key for all tenants?
It can present one, but it must not in a correct multi-user design. Every call would act as that key's one account. Authenticate each application user who sends or owns an inbox separately.
Should an integration prefer OAuth or API keys?
Use OAuth sign-in and consent when the client supports it. Otherwise, have the user issue a named key for that integration and store it only in their tenant-scoped secret boundary.
Does the webhook contain the briefing?
No. It is an envelope and contains neither briefing text nor a recipient or subscription id. Your receiver must map its endpoint context to the user, then fetch through MCP with that user's credential.