HTTP API
Deploy websites programmatically via the Sandbox API. No API key required.
Overview
The Sandbox API lets you deploy websites with a single HTTP request. No account, no API key, no CLI installation needed.
curl -X POST https://sandbox-api.creek.dev/api/sandbox/deploy \
-H "Content-Type: application/json" \
-d '{
"assets": {
"index.html": "<base64-encoded-content>"
},
"source": "my-agent"
}'Endpoints
POST /api/sandbox/deploy
Deploy files to a sandbox preview (60 min TTL).
Request body:
{
"assets": {
"index.html": "PGh0bWw+Li4u",
"style.css": "Ym9keSB7fQ==",
"app.js": "Y29uc29sZS5sb2coKQ=="
},
"source": "my-agent"
}| Field | Type | Required | Description |
|---|---|---|---|
assets | Record<string, string> | Yes | File path → base64-encoded content |
source | string | No | Source identifier for tracking |
manifest | object | No | Optional — derived from assets keys |
framework | string | No | Framework hint |
Response (202):
{
"sandboxId": "a1b2c3d4",
"status": "queued",
"statusUrl": "https://sandbox-api.creek.dev/api/sandbox/a1b2c3d4/status",
"previewUrl": "https://a1b2c3d4.creeksandbox.com",
"expiresAt": "2026-03-27T16:00:00.000Z"
}Rate limit: 10 deploys per hour per IP. Demo deploys (source: "cli-demo") are exempt.
Rate limit headers:
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 7
X-RateLimit-Reset: 1774624000
Retry-After: 3200 (only on 429)GET /api/sandbox/:id/status
Poll deployment status.
{
"sandboxId": "a1b2c3d4",
"status": "active",
"source": "my-agent",
"renderMode": "spa",
"assetCount": 3,
"previewUrl": "https://a1b2c3d4.creeksandbox.com",
"deployDurationMs": 9234,
"createdAt": "2026-03-27T15:00:00.000Z",
"expiresAt": "2026-03-27T16:00:00.000Z",
"expiresInSeconds": 3200,
"claimable": true,
"failedStep": null,
"errorMessage": null
}Status values: queued → deploying → active (or failed, expired).
DELETE /api/sandbox/:id
Delete a sandbox before expiry. Only the creator (same IP) can delete.
POST /api/sandbox/:id/claim
Mark a sandbox as claimed (after creek login + creek claim).
POST /api/sandbox/:id/report
Report abuse on a sandbox deployment.
Error Format
All errors return structured JSON:
{
"error": "rate_limited",
"message": "Sandbox deploy limit reached (10/hr).",
"hint": "Create a free account for unlimited deploys: npx creek login"
}| Error code | HTTP | Description |
|---|---|---|
validation | 400 | Invalid input (empty assets, bad JSON, too large) |
content_policy | 400 | Content scanning blocked the deploy |
rate_limited | 429 | Deploy limit reached |
not_found | 404 | Sandbox not found |
forbidden | 403 | Not authorized (e.g., delete by different IP) |
Agent Challenge
Creek does not use CAPTCHAs. Instead, AI agents can prove they are capable callers via a "reverse CAPTCHA" — a small task that requires fetching a URL, extracting structured data, and computing a hash. Passing the challenge yields a signed agent token that grants elevated rate limits.
| Tier | Rate limit (per hour) |
|---|---|
| Unverified caller | 3 |
| Human (UI / browser) | 10 |
| Verified agent (via challenge) | 60 |
Protocol
- Start a challenge
curl -X POST https://sandbox-api.creek.dev/api/sandbox/agent-verify/startResponse:
{
"challengeId": "a1b2c3d4e5f6",
"nonce": "8f3e8a90-...",
"task": {
"url": "https://creek.dev/docs/cli",
"instruction": "Fetch the Creek CLI documentation page. Extract all CLI command names...",
"format": "Comma-separated, sorted alphabetically"
},
"expiresIn": 300,
"tos": {
"url": "https://creek.dev/legal/terms",
"aupUrl": "https://creek.dev/legal/acceptable-use",
"note": "Include tosAccepted: true and tosVersion in your submit request."
}
}- Solve the task
The agent fetches the URL, extracts data per the instruction, and computes:
digest = SHA-256(nonce + "|" + canonicalAnswer)The canonical answer must be exactly the format requested (e.g. comma-separated, sorted alphabetically — no extra whitespace).
- Submit the digest
curl -X POST https://sandbox-api.creek.dev/api/sandbox/agent-verify/a1b2c3d4e5f6/submit \
-H "Content-Type: application/json" \
-d '{
"digest": "<hex-encoded SHA-256>",
"tosAccepted": true,
"tosVersion": "v3"
}'Response:
{
"ok": true,
"token": "crk_agent_<payload>.<signature>",
"expiresAt": "2026-04-10T12:00:00.000Z",
"expiresIn": 3600,
"tier": "verified_agent",
"rateLimit": 60
}- Use the token
Pass the token in the X-Creek-Agent-Token header on subsequent sandbox API calls. Verified agents get 60/hr instead of the default 10/hr.
curl -X POST https://sandbox-api.creek.dev/api/sandbox/deploy \
-H "Content-Type: application/json" \
-H "X-Creek-Agent-Token: crk_agent_..." \
-d '{"assets": {...}}'Properties
- Tokens are bound to your IP hash — they cannot be shared.
- One challenge = one token. Replays are rejected.
- Token TTL: 1 hour. Re-challenge for a fresh token.
- Questions rotate — solutions cannot be cached or hardcoded. The nonce changes every challenge.
- TLS-grade fairness — humans pass via the dashboard sign-in flow; agents pass via this protocol. Neither needs the other.
Why a reverse CAPTCHA?
CAPTCHAs are designed to block bots. But AI agents are legitimate callers — they should not be locked out of deployment APIs just because they aren't human. The Agent Challenge inverts the problem: instead of proving you're human, you prove you can read documentation and follow instructions — exactly what an agent should be able to do.
GitHub Actions Example
- name: Deploy Preview
run: |
ASSETS=$(node -e "
const fs = require('fs'), path = require('path');
const a = {}; (function w(d,p=''){
for(const f of fs.readdirSync(d)){
const fp=path.join(d,f), k=p?p+'/'+f:f;
fs.statSync(fp).isDirectory()?w(fp,k):a[k]=fs.readFileSync(fp).toString('base64');
}
})('dist');
console.log(JSON.stringify(a));
")
curl -sf -X POST https://sandbox-api.creek.dev/api/sandbox/deploy \
-H "Content-Type: application/json" \
-d "{\"assets\": $ASSETS, \"source\": \"github-actions\"}"Or use the GitHub Action for a simpler setup.