Agent Computer API
Try it in the API Playground.
Base URL
Section titled “Base URL”https://api.rebyte.ai/v1Authentication
Section titled “Authentication”Every request requires an API_KEY header. Get your key from Settings > API Keys.
curl https://api.rebyte.ai/v1/tasks \ -H "API_KEY: rbk_your_key_here"The header name is case-insensitive. API_KEY, api-key, and x-api-key all work.
Endpoints
Section titled “Endpoints”| Method | Path | Description |
|---|---|---|
| POST | /tasks | Create a task |
| GET | /tasks | List tasks |
| GET | /tasks/:id | Get task with status and prompt history |
| POST | /tasks/:id/prompts | Send a follow-up prompt |
| PATCH | /tasks/:id/visibility | Change task visibility |
| DELETE | /tasks/:id | Soft-delete a task |
| GET | /tasks/:id/events | SSE stream of execution events |
| POST | /files | Get a signed file upload URL |
| POST | /webhooks | Register a webhook |
| GET | /webhooks | List webhooks |
| GET | /webhooks/:id | Get webhook details |
| DELETE | /webhooks/:id | Delete a webhook |
All paths are relative to the base URL (https://api.rebyte.ai/v1). |
Create Task
Section titled “Create Task”POST /tasksCreates a new task. By default, provisions a new VM (Agent Computer). Pass workspaceId to run the task on an existing workspace instead — this skips provisioning and is significantly faster.
The call blocks until the VM is provisioned and the first prompt is submitted.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Task description (max 100,000 chars) |
executor | string | No | claude (default), gemini, codex, opencode |
model | string | No | Model tier for the executor. See Models. |
workspaceId | string | No | UUID of an existing workspace to reuse |
files | object[] | No | Files from POST /files. Each: {"id": "...", "filename": "..."} |
skills | string[] | No | Skill slugs (e.g., ["deep-research", "pdf"]) |
githubUrl | string | No | GitHub repo in owner/repo format |
branchName | string | No | Branch name (default: main) |
curl -X POST https://api.rebyte.ai/v1/tasks \ -H "API_KEY: rbk_xxx" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Build a REST API with Express and add tests", "executor": "claude", "skills": ["deep-research"], "githubUrl": "your-org/your-repo" }'Response (201):
{ "id": "550e8400-e29b-41d4-a716-446655440000", "workspaceId": "660e8400-e29b-41d4-a716-446655440001", "url": "https://app.rebyte.ai/run/550e8400-e29b-41d4-a716-446655440000", "status": "running", "createdAt": "2026-01-28T12:00:00.000Z"}Save the workspaceId from the response to create follow-on tasks on the same Agent Computer:
# First task -- provisions a new VMRESP=$(curl -s -X POST https://api.rebyte.ai/v1/tasks \ -H "API_KEY: rbk_xxx" -H "Content-Type: application/json" \ -d '{"prompt": "Set up the project"}')WS_ID=$(echo $RESP | jq -r '.workspaceId')
# Second task -- reuses the same VM (much faster)curl -s -X POST https://api.rebyte.ai/v1/tasks \ -H "API_KEY: rbk_xxx" -H "Content-Type: application/json" \ -d "{\"prompt\": \"Now add tests\", \"workspaceId\": \"$WS_ID\"}"Models
Section titled “Models”Available models depend on the executor:
| Executor | Available Models | Default |
|---|---|---|
claude | claude-sonnet-4.6, claude-opus-4.6, gemini-3.1-pro, gpt-5.3-codex, gpt-5.4, minimax-m2.7, kimi-k2.5, glm-5, gemini-3-flash | claude-sonnet-4.6 |
codex | gpt-5.4, gpt-5.3-codex | gpt-5.4 |
gemini | auto-gemini-3 (auto-routes between flash and pro) | auto-gemini-3 |
opencode | Same as claude | gemini-3.1-pro |
With BYOK (bring your own API key), only the executor’s native provider models are available (e.g., claude executor with BYOK only gets claude-sonnet-4.6 and claude-opus-4.6).
List Tasks
Section titled “List Tasks”GET /tasks?limit=50&offset=0Returns tasks created via the API, sorted by creation time (newest first).
| Param | Type | Default | Description |
|---|---|---|---|
limit | number | 50 | Results per page (max 100) |
offset | number | 0 | Pagination offset |
curl "https://api.rebyte.ai/v1/tasks?limit=10" \ -H "API_KEY: rbk_xxx"Response:
{ "data": [ { "id": "550e8400-...", "url": "https://app.rebyte.ai/run/550e8400-...", "title": "Build REST API with Express", "executor": "claude", "model": "claude-sonnet-4.6", "createdAt": "2026-01-28T12:00:00.000000+00:00", "completedAt": "2026-01-28T12:05:00.000000+00:00" } ], "total": 42, "limit": 10, "offset": 0}Get Task
Section titled “Get Task”GET /tasks/:idReturns full task details including prompt history and derived status.
curl https://api.rebyte.ai/v1/tasks/550e8400-... \ -H "API_KEY: rbk_xxx"Response:
{ "id": "550e8400-...", "url": "https://app.rebyte.ai/run/550e8400-...", "status": "running", "title": "Build REST API with Express", "executor": "claude", "model": "claude-sonnet-4.6", "createdAt": "2026-01-28T12:00:00.000000+00:00", "completedAt": null, "prompts": [ { "id": "660e8400-...", "status": "running", "submittedAt": "2026-01-28T12:05:00.000000+00:00", "completedAt": null }, { "id": "550e8400-...", "status": "succeeded", "submittedAt": "2026-01-28T12:00:01.000000+00:00", "completedAt": "2026-01-28T12:03:00.000000+00:00" } ]}Task status is derived from prompt states:
| Status | Condition |
|---|---|
running | Any prompt is pending or running |
completed | All prompts terminal, latest is succeeded |
failed | All prompts terminal, latest is failed |
canceled | All prompts terminal, latest is canceled |
Send Follow-Up
Section titled “Send Follow-Up”POST /tasks/:id/promptsSend a follow-up prompt to a running or completed task. If the VM is stopped, it is automatically resumed.
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Follow-up prompt (max 100,000 chars) |
skills | string[] | No | Additional skill slugs for this prompt |
curl -X POST https://api.rebyte.ai/v1/tasks/550e8400-.../prompts \ -H "API_KEY: rbk_xxx" \ -H "Content-Type: application/json" \ -d '{"prompt": "Now add authentication with JWT"}'Response (201):
{ "promptId": "770f9500-..."}Stream Events (SSE)
Section titled “Stream Events (SSE)”GET /tasks/:id/eventsOpens a Server-Sent Events stream for the task’s latest prompt. Events include agent output (stdout, stderr), tool calls, and completion signals.
curl -N https://api.rebyte.ai/v1/tasks/550e8400-.../events \ -H "API_KEY: rbk_xxx"The stream emits two event types:
event— execution events (agent output, tool calls)done— final event with completion status, then the stream closes
Change Visibility
Section titled “Change Visibility”PATCH /tasks/:id/visibility| Field | Type | Required | Description |
|---|---|---|---|
visibility | string | Yes | private, shared, or public |
| Level | Who can view |
|---|---|
private | Only the API key owner |
shared | All organization members (default) |
public | Anyone with the link (read-only) |
curl -X PATCH https://api.rebyte.ai/v1/tasks/550e8400-.../visibility \ -H "API_KEY: rbk_xxx" \ -H "Content-Type: application/json" \ -d '{"visibility": "public"}'When set to public, the response includes a shareUrl for unauthenticated access.
Delete Task
Section titled “Delete Task”DELETE /tasks/:idSoft-deletes the task. Returns 204 No Content.
curl -X DELETE https://api.rebyte.ai/v1/tasks/550e8400-... \ -H "API_KEY: rbk_xxx"Upload files to attach to tasks. Uses a two-step signed-URL flow.
Step 1: Get Upload URL
Section titled “Step 1: Get Upload URL”POST /files| Field | Type | Required | Description |
|---|---|---|---|
filename | string | Yes | File name (max 255 chars) |
contentType | string | No | MIME type (default: application/octet-stream) |
Response (201):
{ "id": "550e8400-...", "filename": "data.csv", "uploadUrl": "https://storage.googleapis.com/...", "maxFileSize": 52428800}The upload URL expires in 1 hour.
Step 2: Upload the File
Section titled “Step 2: Upload the File”curl -X PUT "UPLOAD_URL_FROM_STEP_1" \ -H "Content-Type: application/octet-stream" \ --data-binary @data.csvStep 3: Attach to Task
Section titled “Step 3: Attach to Task”Pass id and filename from Step 1 when creating a task:
{ "prompt": "Analyze the uploaded data", "files": [ {"id": "550e8400-...", "filename": "data.csv"} ]}Files are automatically copied into the task’s VM when execution begins.
Webhooks
Section titled “Webhooks”Receive HTTP POST notifications when task events occur. Webhooks are universal — they fire for all tasks in your organization, whether created via API, UI, or any other channel.
Events
Section titled “Events”| Event | Fires when |
|---|---|
task.created | A new task is created |
task.running | The agent starts executing |
task.completed | Task finishes successfully |
task.failed | Task fails |
task.canceled | Task is canceled by user |
Create Webhook
Section titled “Create Webhook”POST /webhooks| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | HTTPS endpoint URL |
events | string[] | Yes | Events to subscribe to |
description | string | No | Human-readable label (max 500 chars) |
secret | string | No | Pre-shared secret (max 500 chars). When set, included as X-Webhook-Secret header in every delivery. |
# Webhook without secretcurl -X POST https://api.rebyte.ai/v1/webhooks \ -H "API_KEY: rbk_xxx" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-server.com/webhook", "events": ["task.completed", "task.failed"] }'
# Webhook with pre-shared secretcurl -X POST https://api.rebyte.ai/v1/webhooks \ -H "API_KEY: rbk_xxx" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-server.com/webhook", "events": ["task.completed", "task.failed"], "secret": "my-shared-secret-value" }'Response (201):
{ "id": "880e8400-...", "url": "https://your-server.com/webhook", "events": ["task.completed", "task.failed"], "description": null, "hasSecret": true, "isActive": true, "createdAt": "2026-01-28T12:00:00.000Z", "lastTriggeredAt": null, "failureCount": 0}Behavior notes:
- Duplicate URLs: registering the same URL twice returns the existing webhook (idempotent)
- Limit: maximum 3 webhooks per organization. The 4th returns
limit_exceeded. - Secret storage: the secret value is never returned in any response. Only
hasSecret: true/falseis exposed.
List Webhooks
Section titled “List Webhooks”GET /webhooksReturns all webhooks for your organization with status info (lastTriggeredAt, failureCount, isActive). Secrets are never exposed.
Get Webhook
Section titled “Get Webhook”GET /webhooks/:idDelete Webhook
Section titled “Delete Webhook”DELETE /webhooks/:idReturns 204 No Content. Deleted webhooks immediately stop receiving deliveries.
Delivery
Section titled “Delivery”When a task event matches a webhook’s subscribed events, Rebyte sends an HTTP POST to the webhook URL.
Payload:
{ "event": "task.completed", "taskId": "550e8400-e29b-41d4-a716-446655440000", "timestamp": 1706443200, "data": { "status": "succeeded", "taskUrl": "https://app.rebyte.ai/run/550e8400-...", "result": "Created CSV file with 10 Hacker News posts..." }}status— prompt status:pending(task.created),running(task.running),succeeded(task.completed),failed(task.failed),canceled(task.canceled)taskUrl— direct link to the task in the Rebyte UI (always present)result— final AI output text (present on terminal events:task.completed,task.failed,task.canceled; absent ontask.createdandtask.running)
Call GET /tasks/:id for full task details including prompt history.
Delivery headers:
| Header | Always present | Description |
|---|---|---|
Content-Type | Yes | application/json |
X-Webhook-Signature | Yes | Base64-encoded RSA-SHA256 signature |
X-Webhook-Timestamp | Yes | Unix timestamp (seconds) |
X-Webhook-Secret | Only if secret configured | The pre-shared secret value you set on creation |
Timeout: deliveries time out after 10 seconds.
Failure handling:
- Delivery is fire-and-forget — no automatic retries on failure
- Non-2xx responses increment
failureCount - After 10 consecutive failures, the webhook is automatically disabled (
isActive: false) - Successful deliveries reset
failureCountto 0
Signature Verification
Section titled “Signature Verification”Every delivery is signed with your organization’s RSA-2048 key pair, regardless of whether a pre-shared secret is configured.
How it works:
- Rebyte concatenates
{timestamp}.{body}(e.g.,1706443200.{"event":"task.completed",...}) - Signs the string with RSA-SHA256 using your org’s private key
- Sends the base64-encoded signature in
X-Webhook-Signature
Get your public key: contact support or retrieve it from the Rebyte dashboard. The RSA-2048 key pair is generated automatically on first webhook creation and persists for the organization.
Verification example (Node.js):
const crypto = require('crypto');
function verifyWebhook(rawBody, timestamp, signature, publicKey) { const payload = `${timestamp}.${rawBody}`; const verifier = crypto.createVerify('RSA-SHA256'); verifier.update(payload); return verifier.verify(publicKey, signature, 'base64');}
// In your webhook handler:app.post('/webhook', (req, res) => { const rawBody = req.body; // must be raw string, not parsed JSON const timestamp = req.headers['x-webhook-timestamp']; const signature = req.headers['x-webhook-signature'];
if (!verifyWebhook(rawBody, timestamp, signature, PUBLIC_KEY)) { return res.status(401).send('Invalid signature'); }
const event = JSON.parse(rawBody); console.log(`Task ${event.taskId}: ${event.event}`); res.status(200).send('OK');});Verification example (Python):
from cryptography.hazmat.primitives import hashes, serializationfrom cryptography.hazmat.primitives.asymmetric import paddingimport base64
def verify_webhook(raw_body: str, timestamp: str, signature: str, public_key_pem: str) -> bool: public_key = serialization.load_pem_public_key(public_key_pem.encode()) payload = f"{timestamp}.{raw_body}".encode() try: public_key.verify( base64.b64decode(signature), payload, padding.PKCS1v15(), hashes.SHA256() ) return True except Exception: return FalseTwo-layer security
Section titled “Two-layer security”Webhooks support two independent verification methods that can be used together:
| Method | Header | How it works | Use case |
|---|---|---|---|
| RSA signature | X-Webhook-Signature | Cryptographic proof the payload came from Rebyte | Tamper-proof verification |
| Pre-shared secret | X-Webhook-Secret | Static string you set on creation, echoed back in every delivery | Simple shared-secret check |
RSA signatures are always present. The pre-shared secret is optional — set it when creating the webhook if you want a simpler verification path.
Polling Example
Section titled “Polling Example”Complete example: create a task, poll until completion, then send a follow-up.
# Create taskTASK_ID=$(curl -s -X POST https://api.rebyte.ai/v1/tasks \ -H "API_KEY: rbk_xxx" \ -H "Content-Type: application/json" \ -d '{"prompt": "Write a Python CLI that converts CSV to JSON"}' | jq -r '.id')
echo "Task: https://app.rebyte.ai/run/$TASK_ID"
# Poll until donewhile true; do STATUS=$(curl -s https://api.rebyte.ai/v1/tasks/$TASK_ID \ -H "API_KEY: rbk_xxx" | jq -r '.status') echo "Status: $STATUS" [[ "$STATUS" == "completed" || "$STATUS" == "failed" ]] && break sleep 5done
# Send a follow-upcurl -s -X POST https://api.rebyte.ai/v1/tasks/$TASK_ID/prompts \ -H "API_KEY: rbk_xxx" \ -H "Content-Type: application/json" \ -d '{"prompt": "Now add support for nested JSON objects"}'Error Format
Section titled “Error Format”All errors follow this structure:
{ "error": { "code": "validation_error", "message": "Invalid request body" }}| Code | HTTP Status | Description |
|---|---|---|
missing_api_key | 401 | API_KEY header not provided |
invalid_api_key | 401 | Invalid or expired API key |
validation_error | 400 | Request body failed validation |
not_found | 404 | Resource does not exist or is not accessible |
limit_exceeded | 400 | Organization limit reached (e.g., max webhooks) |
agent_disabled | 403 | The requested executor is disabled for this organization |
internal_error | 500 | Server-side failure |
Rate Limiting
Section titled “Rate Limiting”The API does not currently enforce per-key rate limits. Each POST /tasks provisions a real VM, so costs scale with usage. Use webhooks instead of aggressive polling to reduce unnecessary requests.