Previews
Expose an HTTP service running in a sandbox through an authenticated preview URL.
A preview exposes an HTTP service listening on a port inside a sandbox at a stable HTTPS URL. In v1, all previews are authenticated — there are no public preview URLs.
The Preview object
| Field | Type | Description |
|---|---|---|
id | string | Preview ID, prefixed prv_ |
slug | string | DNS-safe slug, such as p-a1b2c3 |
url | string | https://p-a1b2c3.preview.crownest.dev |
orgId | string | Owning organization, prefixed org_ |
projectId | string | Owning project, prefixed prj_ |
sandboxId | string | Sandbox the service runs in, prefixed sbx_ |
port | integer | Port the sandbox service listens on |
authMode | string | authenticated (the only mode in v1) |
createdAt | string | ISO 8601 creation timestamp |
expiresAt | string | ISO 8601 expiry, when set |
revokedAt | string | ISO 8601 revocation timestamp, once revoked |
The preview URL has the shape
https://<slug>.preview.crownest.dev, where slug is generated by
CrowNest.
[!NOTE] Preview access requires authentication in v1. CrowNest strips its own cookies and
Authorizationheader before proxying the request to your sandbox app, so platform credentials never reach your code.
Create a preview
POST /v1/sandboxes/{sandboxId}/previews — requires scope
preview:create.
Exposes a port on the sandbox. Creating a preview for the same sandbox and port returns the existing active preview instead of a duplicate.
| Field | Type | Required | Default | Constraints |
|---|---|---|---|---|
port | integer | Yes | — | 1–65535 |
authMode | string | No | "authenticated" | authenticated is the only v1 value |
sourceCommandId | string | No | — | cmd_ ID of the command serving the port |
curl -X POST https://api.crownest.dev/v1/sandboxes/sbx_abc123/previews \
-H "Authorization: Bearer $CROWNEST_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "port": 3000, "sourceCommandId": "cmd_abc123" }'Returns 201 with the preview:
{
"preview": {
"id": "prv_abc123",
"slug": "p-a1b2c3",
"url": "https://p-a1b2c3.preview.crownest.dev",
"orgId": "org_abc123",
"projectId": "prj_abc123",
"sandboxId": "sbx_abc123",
"port": 3000,
"authMode": "authenticated",
"createdAt": "2026-06-11T13:00:00.000Z"
}
}Errors: invalid_request, unsupported_preview_auth_mode, forbidden,
not_found, sandbox_destroyed. If the port stops responding later,
requests to the preview URL fail with preview_unavailable (502).
List previews
GET /v1/sandboxes/{sandboxId}/previews — requires scope preview:read.
Returns a paginated list of the
sandbox's previews, newest first. Standard limit and cursor
parameters apply.
curl https://api.crownest.dev/v1/sandboxes/sbx_abc123/previews \
-H "Authorization: Bearer $CROWNEST_API_KEY"{
"data": [
{
"id": "prv_abc123",
"url": "https://p-a1b2c3.preview.crownest.dev",
"port": 3000,
"authMode": "authenticated"
}
],
"hasMore": false
}Get a preview
GET /v1/previews/{previewId} — requires scope preview:read.
Returns one preview by ID.
curl https://api.crownest.dev/v1/previews/prv_abc123 \
-H "Authorization: Bearer $CROWNEST_API_KEY"Returns 200 with { "preview": { ... } }. Errors: forbidden,
not_found.
Revoke a preview
DELETE /v1/previews/{previewId} — requires scope preview:revoke.
Revokes the preview so its URL stops routing to the sandbox. The operation is idempotent — revoking an already-revoked preview returns the revoked record.
curl -X DELETE https://api.crownest.dev/v1/previews/prv_abc123 \
-H "Authorization: Bearer $CROWNEST_API_KEY"Returns 200 with { "preview": { ... } } including revokedAt.
Errors: forbidden, not_found.
Next steps
- Start the server behind your preview in Commands.
- Check what each scope allows in Authentication.