Skip to content

Api contract

The REST API is the single entry point for all platform interactions. The CLI, webhook integrations, and any future clients use this API to submit tasks, check status, and manage integrations. This is a design-level specification; the source of truth for types is cdk/src/handlers/shared/types.ts.

  • Use this doc for: endpoint paths, payload shapes, auth requirements, and error codes.
  • Related docs: INPUT_GATEWAY.md for the gateway’s role, ORCHESTRATOR.md for the task state machine, SECURITY.md for the authentication model.
EnvironmentBase URL
Productionhttps://{api-id}.execute-api.{region}.amazonaws.com/v1
Custom domainhttps://api.{customer-domain}/v1

Versioning uses a path prefix (/v1). Breaking changes increment the version. New optional fields and endpoints do not require a version bump.

All endpoints require authentication. Two methods are supported:

ChannelMethodHeader
CLI / RESTCognito JWTAuthorization: Bearer <token>
WebhookHMAC-SHA256X-Webhook-Id + X-Webhook-Signature: sha256=<hex>

The gateway extracts user_id from the authenticated identity and attaches it to all internal messages. Downstream services never see raw tokens.

Requests: application/json, UTF-8, max 1 MB body. Clients may include an Idempotency-Key header on POST requests (24-hour TTL).

Successful responses:

{ "data": { ... } }

List responses include pagination:

{ "data": [ ... ], "pagination": { "next_token": "...", "has_more": true } }

Error responses:

{ "error": { "code": "TASK_NOT_FOUND", "message": "Task abc-123 not found.", "request_id": "req-uuid" } }

Standard headers: X-Request-Id (ULID, all responses), X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.

MethodPathAuthDescription
POST/v1/tasksCognitoCreate a task
GET/v1/tasksCognitoList tasks (paginated)
GET/v1/tasks/{task_id}CognitoGet task details
DELETE/v1/tasks/{task_id}CognitoCancel a task
GET/v1/tasks/{task_id}/eventsCognitoGet task audit trail
POST/v1/webhooksCognitoCreate webhook integration
GET/v1/webhooksCognitoList webhooks (paginated)
DELETE/v1/webhooks/{webhook_id}CognitoRevoke webhook
POST/v1/webhooks/tasksHMACCreate task via webhook
POST /v1/tasks

Creates a new task. The orchestrator runs admission control, context hydration, and starts the agent session.

Request body:

FieldTypeRequiredDescription
repoStringYesGitHub repository (owner/repo)
issue_numberNumberNoGitHub issue number. Title, body, and comments are fetched during hydration.
task_descriptionStringNoFree-text description (max 2,000 chars). At least one of issue_number, task_description, or pr_number required.
task_typeStringNonew_task (default), pr_iteration, or pr_review
pr_numberNumberNoPR to iterate on or review. Required when task_type is pr_iteration or pr_review.
max_turnsNumberNoMax agent turns (1-500, default 100)
max_budget_usdNumberNoCost ceiling in USD (0.01-100). If omitted, no budget limit.
attachmentsArrayNoMulti-modal attachments (see below)

Attachments:

FieldTypeRequiredDescription
typeStringYesimage, file, or url
content_typeStringNoMIME type (for inline data)
dataStringNoBase64-encoded content (max 10 MB decoded)
urlStringNoURL to fetch
filenameStringNoOriginal filename

Response: 201 Created

{
"data": {
"task_id": "01HYX...",
"status": "SUBMITTED",
"repo": "org/myapp",
"task_type": "new_task",
"issue_number": 42,
"branch_name": "bgagent/01HYX.../fix-auth-bug",
"created_at": "2025-03-15T10:30:00Z"
}
}

For PR tasks, branch_name is initially pending:pr_resolution and resolved to the PR’s head_ref during hydration.

Idempotency: Clients may send Idempotency-Key (same format as other POST requests). The first successful create returns 201 Created with the body shape above. A subsequent request with the same key and the same authenticated user returns 200 OK with the same { data: ... } envelope (full TaskDetail, reflecting current task state), plus response header Idempotent-Replay: true. No duplicate task is created and the orchestrator is not invoked again for that replay. If the key is already bound to a task owned by another user, the API returns 409 DUPLICATE_TASK without exposing that task (extremely unlikely for high-entropy keys).

Errors: 400 VALIDATION_ERROR, 400 GUARDRAIL_BLOCKED, 401 UNAUTHORIZED, 409 DUPLICATE_TASK (idempotency key collision across users only), 422 REPO_NOT_ONBOARDED, 429 RATE_LIMIT_EXCEEDED, 503 SERVICE_UNAVAILABLE.

GET /v1/tasks/{task_id}

Returns full details of a task. Users can only access their own tasks.

Response: 200 OK

{
"data": {
"task_id": "01HYX...",
"status": "RUNNING",
"repo": "org/myapp",
"task_type": "new_task",
"issue_number": 42,
"task_description": "Fix the authentication bug in the login flow",
"branch_name": "bgagent/01HYX.../fix-auth-bug",
"session_id": "sess-uuid",
"pr_url": null,
"error_message": null,
"error_classification": null,
"max_turns": 100,
"max_budget_usd": null,
"cost_usd": null,
"duration_s": null,
"build_passed": null,
"created_at": "2025-03-15T10:30:00Z",
"updated_at": "2025-03-15T10:31:15Z",
"started_at": "2025-03-15T10:31:10Z",
"completed_at": null
}
}

error_classification is a derived field computed at response time from error_message. When error_message is null, error_classification is null. When present, it contains:

FieldTypeDescription
categoryStringOne of: auth, network, concurrency, compute, agent, guardrail, config, timeout, unknown
titleStringHuman-readable error title
descriptionStringDetailed explanation of what went wrong
remedyStringSuggested action to resolve the error
retryableBooleanWhether retrying may succeed

Example for a failed task:

{
"error_message": "User concurrency limit reached",
"error_classification": {
"category": "concurrency",
"title": "Concurrency limit reached",
"description": "The maximum number of concurrent tasks for this user has been reached.",
"remedy": "Wait for an active task to complete, cancel a running task, or ask an admin to increase the limit.",
"retryable": true
}
}

Errors: 401 UNAUTHORIZED, 403 FORBIDDEN, 404 TASK_NOT_FOUND.

GET /v1/tasks

Returns the authenticated user’s tasks, newest first. Paginated.

Query parameters:

ParameterTypeDefaultDescription
statusStringallFilter by status (comma-separated: RUNNING,HYDRATING)
repoStringallFilter by repository (owner/repo)
limitNumber20Page size (1-100)
next_tokenString-Pagination token from previous response

Returns a summary subset of fields. Use GET /v1/tasks/{task_id} for full details.

Errors: 400 VALIDATION_ERROR, 401 UNAUTHORIZED.

DELETE /v1/tasks/{task_id}

Cancels a task. See ORCHESTRATOR.md for cancellation behavior by state.

Response: 200 OK with status: "CANCELLED".

Errors: 401 UNAUTHORIZED, 403 FORBIDDEN, 404 TASK_NOT_FOUND, 409 TASK_ALREADY_TERMINAL.

GET /v1/tasks/{task_id}/events

Returns the audit trail for a task: state transitions, hydration events, session events, and custom step events.

Query parameters: limit (default 50, max 100), next_token.

Event types: task_created, admission_passed, admission_rejected, preflight_failed, hydration_started, hydration_complete, guardrail_blocked, session_started, session_ended, pr_created, task_completed, task_failed, task_cancelled, task_timed_out. Custom blueprint steps emit {step_name}_started, {step_name}_completed, {step_name}_failed.

Errors: 401 UNAUTHORIZED, 403 FORBIDDEN, 404 TASK_NOT_FOUND.

External systems (CI pipelines, GitHub Actions, custom automation) can create tasks via HMAC-authenticated requests. Webhook integrations are managed through Cognito-authenticated endpoints; task submission uses HMAC.

POST /v1/webhooks

Creates a webhook and returns the shared secret (shown only once).

Request: { "name": "My CI Pipeline" } (1-64 chars, alphanumeric + spaces/hyphens/underscores).

Response: 201 Created

{
"data": {
"webhook_id": "01HYX...",
"name": "My CI Pipeline",
"secret": "<64-hex-characters>",
"created_at": "2025-03-15T10:30:00Z"
}
}

Store the secret securely. It cannot be retrieved again.

Errors: 400 VALIDATION_ERROR, 401 UNAUTHORIZED.

GET /v1/webhooks

Returns the authenticated user’s webhooks. Paginated.

Query parameters: include_revoked (default false), limit (default 20), next_token.

Errors: 401 UNAUTHORIZED.

DELETE /v1/webhooks/{webhook_id}

Soft-revokes a webhook. The secret is scheduled for deletion with a 7-day recovery window. The revoked record is auto-deleted after 30 days.

Errors: 401 UNAUTHORIZED, 404 WEBHOOK_NOT_FOUND, 409 WEBHOOK_ALREADY_REVOKED.

POST /v1/webhooks/tasks

Same request body as POST /v1/tasks. Requires X-Webhook-Id and X-Webhook-Signature headers instead of Cognito JWT.

Authentication flow:

sequenceDiagram
    participant C as Client
    participant AG as API Gateway
    participant Auth as Authorizer Lambda
    participant H as Handler Lambda
    participant SM as Secrets Manager

    C->>AG: POST /v1/webhooks/tasks
    AG->>Auth: Verify webhook exists + active
    Auth-->>AG: Allow (userId, webhookId)
    AG->>H: Forward request
    H->>SM: Fetch secret (cached 5 min)
    H->>H: HMAC-SHA256 verify (constant-time)
    H-->>C: 201 Created / 401 Unauthorized

HMAC verification runs in the handler (not the authorizer) because API Gateway REST API v1 does not pass the request body to Lambda REQUEST authorizers. Authorizer caching is disabled since each request has a unique signature.

Tasks created via webhook record channel_source: 'webhook' with audit metadata (webhook_id, source_ip, user_agent).

Errors: 400 VALIDATION_ERROR, 400 GUARDRAIL_BLOCKED, 401 UNAUTHORIZED, 409 DUPLICATE_TASK, 503 SERVICE_UNAVAILABLE.

LimitValueScopeResponse
Request rate60 req/minPer user, all endpoints429 Too Many Requests
Task creation rate10 tasks/hourPer user, task creation only429 RATE_LIMIT_EXCEEDED
Concurrent tasksConfigurable (default 3-5)Per user, running tasks409 CONCURRENCY_LIMIT_EXCEEDED
CodeStatusDescription
VALIDATION_ERROR400Invalid request body or parameters
GUARDRAIL_BLOCKED400Task description blocked by content screening
UNAUTHORIZED401Missing, expired, or invalid authentication
FORBIDDEN403Not authorized (e.g. accessing another user’s task)
TASK_NOT_FOUND404Task ID does not exist
WEBHOOK_NOT_FOUND404Webhook does not exist or belongs to another user
DUPLICATE_TASK409Idempotency key already used by another user (POST /v1/tasks / webhook create); same-user replays return 200 with the existing task instead
TASK_ALREADY_TERMINAL409Cannot cancel a terminal task
WEBHOOK_ALREADY_REVOKED409Webhook is already revoked
REPO_NOT_ONBOARDED422Repository not registered (onboard via CDK, not runtime API)
REPO_NOT_FOUND_OR_NO_ACCESS422Repo onboarded but credentials cannot reach it
PR_NOT_FOUND_OR_CLOSED422PR does not exist, is closed, or is inaccessible
INSUFFICIENT_GITHUB_REPO_PERMISSIONS422GitHub token lacks required permissions for the task type
GITHUB_UNREACHABLE502GitHub API unreachable during pre-flight (transient)
RATE_LIMIT_EXCEEDED429User exceeded rate limit
CONCURRENCY_LIMIT_EXCEEDED409User at max concurrent tasks
INVALID_STEP_SEQUENCE500Blueprint step sequence misconfigured (CDK error)
INTERNAL_ERROR500Unexpected server error
SERVICE_UNAVAILABLE503Downstream dependency unavailable (retry with backoff)

List endpoints use token-based pagination (consistent with DynamoDB’s ExclusiveStartKey).

  • pagination.next_token (opaque string) and pagination.has_more (boolean) in responses
  • Pass next_token as query parameter for the next page
  • Tokens are short-lived and should not be stored
  • Results ordered by created_at descending (newest first)