Skip to content

Links and protocol / Links

Links

Create one link per person and device with the publishable key, keep the link token, and show the person their MCP URL.

POST/v1/links
Auth Publishable key: Authorization: Bearer pk_…

A link is one person's installation of your app on one device. Creating it is the only HTTP request your app makes; everything else goes over the socket. Creating links is free.

Request#

Headers#

Authorization
stringrequired
The project's publishable key, from the dashboard.
Rules
Bearer pk_…
Content-Type
stringoptional
The body is always read as JSON.
Rules
application/json

Body#

A JSON object. Unknown fields are rejected. Send {} for a link without a label.

label
stringoptional
Shown in the dashboard's links list so you can tell links apart. Use the device name, never the person's email or other personal data.
Rules
1–64 characters, trimmed
curl https://api.meslzy.com/relay/v1/links \  -H "Authorization: Bearer $RELAY_PUBLISHABLE_KEY" \  -H "Content-Type: application/json" \  -d '{ "label": "Work laptop" }'

Response#

⫻

201 Created

HTTP/1.1 201 CreatedContent-Type: application/jsonX-Request-Id: req_0199c4e25b7a7d318f2e6a1c9b3d4e58
{  "linkId": "0199c4e2-5b7a-7d31-8f2e-6a1c9b3d4e57",  "linkToken": "lt_3Vd9xZr2Lm8Tn4Bw6Yc1Hs7Pf5Gj0A2U",  "mcpUrl": "https://api.meslzy.com/relay/v1/mcp/ut_8Hq3Lm2Vx7Tc9Rb4Nw1Ks6Jd5Yf0Pg2E",  "socketUrl": "wss://api.meslzy.com/relay/v1/socket"}
FieldMeaning
linkIdThe link's id, as the dashboard and ready show it.
linkTokenlt_…. The app's secret for this link, shown only now. Send it in `hello`.
mcpUrlThe person's MCP URL, ending in the URL token. Store it beside the link token: ready does not repeat it.
socketUrlWhere the app opens its WebSocket.

Store the link token and the URL#

  • Keep the link token and the MCP URL in the platform's secure storage. Both are shown only in this response; Relay keeps the link token as a SHA-256 hash and cannot show it again.
  • The app needs the link token to connect, and the URL to show the person where to paste it. ready carries neither.
  • After a rotation, link.rotated carries the new URL. Replace the stored one.
  • If the link token is lost, create a new link and revoke the old one in the dashboard.

One link per person and device#

  • Create the link the first time the person turns the integration on, not on every start.
  • Two copies of the app on one link keep replacing each other's socket, because the newest socket wins. Give each device its own link.
  • A person who uses the app on two devices gets two links and two MCP URLs. Each URL reaches the app on its own device only.
  • A project can have up to 10,000 links. Revoke the ones you no longer need from the dashboard, or from the app with `link.revoke`.

Allowed origins#

By default any caller holding the publishable key can create links. If your app runs in a web page, list its origins under Allowed origins in the project's settings: one https:// origin per line, such as https://notes.example.com.

  • A request whose Origin header is not on the list is refused with 403 FORBIDDEN, and a socket opened from such an origin closes with 4403.
  • A request without an Origin header passes. Native apps, command-line tools and servers send none, so the list restricts browsers only.
  • Web views inside desktop apps send origins such as file:// or a custom scheme, which the list cannot hold. Leave the list empty for those apps.

Errors#

Errors have one JSON shape: an error object with a stable code, a readable message and a requestId. Branch on code, never on message. Every response carries an X-Request-Id header with the same id, and a 429 carries Retry-After in seconds.

⫻

401 Unauthorized

HTTP/1.1 401 UnauthorizedContent-Type: application/jsonX-Request-Id: req_0199c4e25b7a7d318f2e6a1c9b3d4e58
{  "error": {    "code": "UNAUTHORIZED",    "message": "Missing or invalid publishable key",    "requestId": "req_0199c4e25b7a7d318f2e6a1c9b3d4e58"  }}
CodeHTTPWhen
VALIDATION_ERROR400The body is not a JSON object, has unknown fields, or the label breaks its rule. details lists each problem.
UNAUTHORIZED401The Authorization header is missing, or the publishable key is malformed, unknown or rotated away.
FORBIDDEN403The request carries an Origin that is not on the project's allowed origins.
PROJECT_SUSPENDED403The project is suspended. Contact support.
LIMIT_REACHED403The project already has 10,000 links.
RATE_LIMITED429More than 60 links a minute were created from one IP address, or too many for one project. Wait for Retry-After seconds.
INTERNAL_ERROR500Something failed on Relay's side. Retry with backoff.