Cookie-issuing URLs that grant temporary access to private or password-gated apps.
A share link is a URL that, when visited, sets a cookie in the visitor's browser. The cookie satisfies the share-link gate (see Grants and visibility) for that browser, for as long as the share link is active.
Use a share link when you want to give someone access without making them sign up: a client reviewing a preview, a designer checking a mockup, a journalist previewing a launch under embargo.
Send data.url to the recipient. The token rides in the __vh_share query parameter. The first time they open it, their browser gets a signed 24-hour cookie (vh_app_share_<appId>) and the server redirects to the same URL with the token removed, so it does not sit in browser history or leak through a Referer header. The cookie satisfies the share-link gate (visibility/grant) on subsequent requests. If the app has a password set, the visitor is still asked for it. The password gate is separate and always applies.
data.token is returned once, at creation, and never stored. The server keeps only its hash. data.tokenPrefix is the first 12 characters, which is what share-link ls displays so you can identify a link without handling the whole token.
--label adds a searchable note that shows up in share-link ls and in the dashboard. Pick something you'll recognize in 6 months.
--expires-in takes a duration such as 30m, 6h or 7d. The server caps it at 90 days. Omit it and the link never expires. Once a link has expired its token stops being accepted, and the visitor falls through to the app's ordinary gates, so on a private app they land on the request-access page rather than getting a distinct "link expired" error.
You're delivering a landing page, and the client should be able to see it for 2 weeks before the link expires. Setting the app private means only grantees and holders of the share link can reach it.
Option A suits repeat reviewers, because the audit trail records each user. Option B suits a one-off "open this once and look at it".
You're launching with a press embargo. Reporters get the URL 48 hours before the public launch, and the link expires at launch, when the app goes public.
Two separate links can be revoked and audited separately. At launch, make the app public. Optionally, revoke the embargo links too so press can't keep linking the share URL:
The cookie is host-only (no Domain attribute), so the public-suffix listing on vibehost.space can't reject it.
The gate 302-redirects to the same URL with __vh_share removed, which is what the visitor's history and any outbound Referer end up carrying.
The follow-up request carries the share cookie. The share-link gate sees it and satisfies visibility/grant for this browser, skipping those checks on every later request as long as the cookie is valid and the share row is still active. The server then runs the password gate: if the app has a password set and there's no valid password cookie, the visitor gets a 401 password prompt. After they enter the password, the server sets a second cookie (vh_app_pw_<appId>, 7-day TTL).
With both cookies in place, every later request from this browser passes. The share cookie covers visibility/grant for 24 hours, and the password cookie covers the password gate for 7 days. The different lifetimes are deliberate. Share cookies belong to outside parties and stay short, while password cookies belong to viewers returning to an app they use. Whichever expires first re-prompts only for that one factor.
The cookie is bound to one app, and each app issues its own cookie. One share link can't unlock other apps in the same workspace.
They don't authenticate the visitor. The cookie is bound to the share link, not the person. Anyone with the URL can satisfy the gate.
They don't bypass the password gate. A valid share-link cookie satisfies the share-link gate (visibility/grant are skipped) for the app it was minted on, including visibility: private apps with no grants. But if the app has a password set, the visitor still has to enter it, because the password cookie is separate and always required. This is by design. Minting a share link is the operator's explicit consent for "anyone with this URL can view (no sign-in required)", but it doesn't override a password the operator set. If "anyone with this URL, no further friction" is what you want, don't set a password. If "anyone with this URL and this password" is what you want, set both.
They don't expire by default. Set --expires-in or revoke manually.
They don't carry an audit trail of the recipient. If you need "person X opened this on date Y", invite them with a grant instead.
The link id doesn't exist on this app. If you passed a token prefix instead of an id, no active link matches. Prefix resolution skips revoked links, so revoking one again by prefix lands here.
VALIDATION
None (CLI only)
Raised by the CLI, not the API, when the prefix you passed matches more than one active link. The error lists the matches; pass a longer prefix or the full id.
Revoking an already revoked link by its full id returns 200, because the call is idempotent.
There is no share-link-specific error for an expired token. An expired or revoked token is simply not accepted, and the request falls through to the app's ordinary gates: a private app answers with its request-access page, a password-gated app with the password prompt.