Links
Create one link per person and device with the publishable key, keep the link token, and show the person their MCP URL.
/v1/linksAuthorization: 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#
- Rules
Bearer pk_…
- Rules
application/json
Body#
A JSON object. Unknown fields are rejected. Send {} for a link without a label.
- Rules
- 1–64 characters, trimmed
Response#
⫻
201 Created
| Field | Meaning |
|---|---|
| linkId | The link's id, as the dashboard and ready show it. |
| linkToken | lt_…. The app's secret for this link, shown only now. Send it in `hello`. |
| mcpUrl | The person's MCP URL, ending in the URL token. Store it beside the link token: ready does not repeat it. |
| socketUrl | Where 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.
readycarries neither. - After a rotation,
link.rotatedcarries 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
Originheader is not on the list is refused with403 FORBIDDEN, and a socket opened from such an origin closes with4403. - A request without an
Originheader 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
| Code | HTTP | When |
|---|---|---|
| VALIDATION_ERROR | 400 | The body is not a JSON object, has unknown fields, or the label breaks its rule. details lists each problem. |
| UNAUTHORIZED | 401 | The Authorization header is missing, or the publishable key is malformed, unknown or rotated away. |
| FORBIDDEN | 403 | The request carries an Origin that is not on the project's allowed origins. |
| PROJECT_SUSPENDED | 403 | The project is suspended. Contact support. |
| LIMIT_REACHED | 403 | The project already has 10,000 links. |
| RATE_LIMITED | 429 | More than 60 links a minute were created from one IP address, or too many for one project. Wait for Retry-After seconds. |
| INTERNAL_ERROR | 500 | Something failed on Relay's side. Retry with backoff. |