Skip to main content

Previews

GET /api/projects/{projectId}/preview returns a preview's URLs and wakes its sandbox when it is paused. Pass sessionId for a chat session's preview, and leave it out for the project's main preview. Call it before you read a session's files, diff or git state. From here you can also check the preview's health, restart its services and share it with a public link.

MethodPathDescription
GET/api/projects/{projectId}/preview?sessionId=Read the preview URLs of the project's main sandbox, or of one chat session's.
GET/api/projects/{projectId}/preview/health?sessionId=Read the health of every service behind a preview.
POST/api/projects/{projectId}/preview/resetRestart the services of a preview's running sandbox in place. Fails when the sandbox is paused.
GET/api/projects/{projectId}/preview/share?sessionId=Read the public share link of a preview, if one exists.
POST/api/projects/{projectId}/preview/share?sessionId=Create the public share link of a preview. The body sessionId wins over the query one.
DELETE/api/projects/{projectId}/preview/share?sessionId=Revoke the public share link of a preview.
GET/api/shared-previews/{slug}Resolve a public share link. No credential needed; rate limited per caller.
GET/api/shared-previews/{slug}/artifacts/{artifactId}Read one artifact behind a public share link. No credential needed.

Get the preview and wake the sandbox​

ParameterWhat it does
sessionIdOptional. The chat session whose preview you want. Left out, the call reads the project's main preview.

A paused sandbox wakes in the background. The call returns provisioning: true with an empty frontendUrls within two seconds, so check health until the services are up. The call waits only while a missing chat session sandbox is created. A missing main sandbox is rebuilt by a deploy, and the call returns before that deploy finishes. Sandboxes and previews explains when a sandbox sleeps and what waking it costs.

curl -s "https://app.kosuke.ai/api/projects/$PROJECT_ID/preview?sessionId=$SESSION_ID" \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": {
"frontendUrls": { "web": "https://…" },
"projectId": "5a1e9c47-83b2-4d6f-a0e8-2b7c9d14f36a",
"sandboxKey": "c3f8a215-6e0d-4b97-9a42-81d5e7f02c6b",
"awayHoldMs": 600000
}
}

frontendUrls maps each service that serves the preview to its URL. When nothing could start, the answer is still 200, with an empty frontendUrls and one of these flags:

FlagWhat it meansWhat to do
creditLimitReached: trueThe workspace is blocked on billing, so nothing started.Sort out the workspace's billing. Retrying does not help.
sandboxLimitReached: trueThe workspace already runs as many chat session sandboxes as its plan allows.Stop another session's sandbox, or wait for an idle one to pause.
provisioning: trueThis call started a wake, or another request is waking, creating or changing this sandbox.Check health until the services are up.

An empty frontendUrls with no flag has four readings. The session may be Backlog, Completed or Archived. A deploy may be rebuilding the project's main preview. No service in the project may serve a preview. Or another operation held the session's sandbox for over five seconds, so call again. When the project's main sandbox is gone, asking for the main preview starts that deploy.

The CLI command is kosuke preview get <projectId> --session-id <sessionId>.

Check health​

GET .../preview/health reports whether the services behind a preview answer. It takes the same sessionId and never wakes a sandbox.

{
"data": {
"state": "healthy",
"frontendUrls": { "web": "https://…" },
"services": [
{ "name": "agent", "httpResult": "healthy" },
{ "name": "web", "httpResult": "healthy" }
],
"sandboxAvailable": true,
"sandboxId": "i8k2m4q6r1t3v5x7z9b0d",
"canRetainPreview": false
}
}
FieldWhat it holds
statehealthy when every service answers, starting otherwise.
servicesEach probed endpoint's name, which is its route key, and httpResult, which is healthy, not_healthy or null. When the check reached a running sandbox, the list starts with agent, the agent inside the sandbox. A project with public endpoints but none that serves a preview lists only those endpoints, each with a null httpResult. Otherwise the list is empty.
sandboxAvailabletrue when the check reached a running sandbox.
sandboxIdThe sandbox the check reached. Present only when it reached a running sandbox.
canRetainPreviewtrue when that sandbox was created with auto-resume off, so a request to its preview does not wake it once it pauses. Present with sandboxId.
pausedtrue when the sandbox is paused. Wake it with GET /api/projects/{projectId}/preview.
needsStarttrue when nothing is running or starting. Wake it with GET /api/projects/{projectId}/preview.
creditLimitReached, sandboxLimitReachedAs on GET /api/projects/{projectId}/preview.
indeterminatetrue when the check could not read the sandbox this time. A pause or resume held it, or it did not answer. Ignore the rest of the answer and ask again in a few seconds. Do not wake it with GET /api/projects/{projectId}/preview.

A Backlog, Completed or Archived session answers 404. The CLI command is kosuke preview health <projectId> --session-id <sessionId>.

Restart the preview's services​

POST .../preview/reset restarts the services in a running sandbox, in place. It keeps the files and the branch.

FieldTypeWhat it does
sessionIdstringOptional. The chat session whose preview to restart. Left out, the project's main preview restarts. The body itself is required, so send {} for the main preview.
curl -s -X POST "https://app.kosuke.ai/api/projects/$PROJECT_ID/preview/reset" \
-H "Authorization: Bearer $KOSUKE_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"sessionId\": \"$SESSION_ID\"}"

The answer comes back at once with { "status": "queued" }, plus the projectId and the sandboxKey. Health reports starting until the restart finishes. A second reset while one runs does not queue another. The restart fails on a paused sandbox, so wake it with GET /api/projects/{projectId}/preview first. A Backlog, Completed or Archived session answers 400. The CLI command is kosuke preview reset <projectId> --session-id <sessionId>.

Share a preview​

A share link lets anyone open a preview without a Kosuke account. For a chat session, it also opens the session's artifacts. Any member of the workspace can create or revoke one. GET, POST and DELETE on .../preview/share take the same sessionId, and POST also takes it in the body.

CallWhat it doesAnswer
POST .../preview/shareCreates the link, or returns the one that already exists.{ "share": { ... } }
GET .../preview/shareReads the link.{ "share": { ... } }, or { "share": null } when there is none
DELETE .../preview/shareRevokes the link. It stops resolving at once. A page already open keeps the preview until its Auth Token expires, within 15 minutes.{ "share": null }, also when there was no link
curl -s -X POST "https://app.kosuke.ai/api/projects/$PROJECT_ID/preview/share?sessionId=$SESSION_ID" \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": {
"share": {
"slug": "Tq3xV9mZkP2rLw7sHc4nB8aQ",
"url": "https://app.kosuke.ai/share/Tq3xV9mZkP2rLw7sHc4nB8aQ",
"createdAt": "2026-09-30T09:20:11.402Z",
"lastViewedAt": null
}
}
}

lastViewedAt is when someone last opened the link, accurate to about five minutes. Opening the link wakes a paused sandbox, and the time it runs counts against the workspace. The CLI group is kosuke preview share, with create, get and delete.

These endpoints need no API key. Anyone who holds the link can call them. An unknown or revoked link answers 404.

GET /api/shared-previews/{slug} returns what the link shows and wakes a paused preview.

curl -s "https://app.kosuke.ai/api/shared-previews/$SLUG"
{
"data": {
"projectName": "storefront",
"sessionTitle": "Add a dark mode toggle to the settings page",
"status": "ready",
"frontends": [{ "name": "web", "url": "https://…", "isServing": true }],
"artifacts": [{ "id": "e2c7…", "slug": "qa-report", "title": "QA Report: kosuke/chat-4kd9wp", "kind": "html", "version": 3, "createdAt": "2026-09-30T09:31:47.208Z", "updatedAt": "2026-09-30T10:02:15.664Z" }]
}
}

sessionTitle is null for the main preview. artifacts lists the session's artifacts without their content, whatever status says. It is empty for the main preview.

statusreasonWhat it means
readyNoneAt least one service answers.
startingNoneThe preview is waking or its services are starting. Call again in a few seconds.
unavailablesession_endedThe session is Backlog, Completed or Archived.
unavailablenot_runningThe preview cannot start now. The workspace may be at its credit or sandbox limit, or the project's main sandbox is gone.
unavailableno_frontendsThe sandbox runs, but no service serves a preview.

Read an artifact​

GET /api/shared-previews/{slug}/artifacts/{artifactId} returns one artifact of the shared session, in the same shape as on Artifacts. It works while the sandbox is paused. An artifact from another session, or any artifact through a main-preview link, answers 404.

The CLI reads both without an API key, with kosuke preview shared <slug> and kosuke preview shared artifact <slug> <artifactId>.

Rate limits​

EndpointLimit per caller
GET /api/shared-previews/{slug}60 requests a minute
GET /api/shared-previews/{slug}/artifacts/{artifactId}30 requests a minute

Past the limit, the answer is 429 with TOO_MANY_REQUESTS.

Errors​

StatusCodeWhen
400BAD_REQUESTThe project was never deployed, a chat session's preview is asked for while a deploy is in progress, or a reset names a Backlog, Completed or Archived session.
400VALIDATION_ERRORA reset body has the wrong shape.
404NOT_FOUNDThe project, session or share link does not exist, or health was asked for a session with no preview.
429TOO_MANY_REQUESTSA public share-link endpoint passed its rate limit.

Responses and errors has the full table.

Next steps​