Make a public URL for a port on the computer
Serve port on https://<label>.<base_domain>. Without a label, a name like brave-otter-3f2a is picked. The body is at most 4096 bytes. The errors this route adds are { error, code }, except four that carry error alone: a body over that size (413), a body that is not JSON or not a JSON object (400), a computer that is not found (404), and the 503 at the end of this list.
- 400 INVALID_BODY: a field other than port, label and access, named in the error. Nothing is made.
- 400 INVALID_PORT: not an integer from 1 to 65535, or 22, which belongs to the computer.
- 400 INVALID_LABEL: 3 to 40 letters, digits and hyphens, starting and ending with a letter or digit, not all digits, no hyphens in the third and fourth places (ab--), not shaped like a computer id, and not a name that reads as the platform’s or another company’s own address: a reserved word such as www or login, numbered, spelled with look-alikes or split by hyphens (www2, l0gin, sign-in); mandala as a part, or run together with reserved words (mandala-login, mandalalogin); a well-known brand among its parts, whole or split (paypal-refunds, pay-pal-refunds), or for the most distinctive brands anywhere in a part (paypalrefunds); or nothing but reserved words and numbers (secure-login, securelogin). Surrounding spaces are trimmed and it is lowercased.
- 400 INVALID_ACCESS: access is public (the default) or private.
- 402 PLAN_REQUIRED: the account’s plan includes no public URLs.
- 403 PUBLIC_URLS_BLOCKED: the platform has turned public URLs off for this computer or account.
- 404 PUBLIC_URLS_DISABLED: public URLs are not enabled here.
- 409 LABEL_TAKEN or PUBLIC_URL_LIMIT: the name is taken, or the computer has as many as its plan allows (Solo 2, Studio 5, Swarm 10). A name the platform has blocked reads as taken, and so does one another account has ever held: a name is never given to a second account.
- 409 WORKSPACE_MOVING: a change of this computer’s workspace is unsettled. reason is contention while the move is being made, so try again in a moment, and unsupported when its outcome was lost, so check the workspace change in the dashboard.
- 429 RATE_LIMITED: this account has made 25 in the last 24 hours, deleted ones included. Retry-After says when to try again.
- 503, with no code: no free generated name was found. Try again, or give a label.
WHO MAY OPEN IT. A public URL answers anyone with the link. A private one answers two credentials and nothing else (401): an API key of this account sent as Authorization: Bearer, where a key confined to a workspace opens only the URLs of that workspace’s computers; or a member of the account whose browser is signed in to that one URL from the dashboard, whose Open button sends it through a one-time sign-in link good for a minute. That sign-in lasts at most 12 hours and ends with the dashboard session it came from, and it admits requests from the URL’s own pages and a top-level visit to it, never a fetch, script, frame or form post from another site. A browser opening a private URL with neither gets a page saying how to open it, still a 401; any other request without one gets an empty 401. While a change of the computer’s workspace is unsettled, a private URL answers 503 to everyone: which workspace’s keys may open it is not settled yet. Neither credential reaches the app, and neither does a Mandala API key or MCP token sent to a public URL. Any other Authorization header is the app’s own and passes through. Cookies the app sets stay on its own host name.
A NEW ACCOUNT’S URLS WARN A BROWSER FIRST. For an account created in the last 14 days, a browser opening one of its URLs, public or private, is sent to a warning page at /__mandala/warning first; Continue takes it on, and that browser is not warned about that URL again for 30 days. A browser navigation is told by fetch metadata — Sec-Fetch-Mode: navigate, or a Sec-Fetch-Dest of document or a frame — or, from a browser that sends no fetch metadata, by an Accept naming text/html with a User-Agent beginning Mozilla/. A programmatic client that sends none of those never sees the page. An agent driving a real browser skips it by sending the request header mandala-skip-warning, with any value.
WHAT THE APP CANNOT HAVE. /__mandala and every path under /__mandala/ belong to the platform and never reach the app. A service worker cannot be registered: a request for a worker script (Service-Worker: script) is answered 403. The app cannot set a cookie named __Host-mandala_*, which is dropped, and never sees the platform’s own. Every answer is marked X-Robots-Tag: noindex, nofollow and is never cached at the edge; a private URL’s answers are also sent Cache-Control: no-store, without ETag or Last-Modified.
HOW IT ANSWERS. A URL serves a running computer. A stopped or suspended computer’s URLs answer 503, and traffic never starts or resumes it; traffic does count as use, so it keeps a running computer from being suspended for idleness. Nothing listening on the port is a 503 with Retry-After, and a browser opening a page gets one saying nothing is listening yet. A request body is at most 100 MiB (413), one computer takes at most 256 requests through its URLs at once (503 past that), the app has 100 seconds to start answering (504), and a request that moves no bytes either way for five minutes, a WebSocket included, is ended.
Requires the member role or higher.
Request
- Base URL: https://app.mandala.computer/api/v1
- URL: https://app.mandala.computer/api/v1/computers/{id}/public-urls
- Auth: HTTP bearer
Path parameters
The computer id.
Request body
Response
The URL as stored.
Changes
No recorded changes to this operation across all 1 revision of this API.