Skip to main content

Platform jobs API

The platform jobs API provides a durable, priority-based background job queue. You can enqueue provisioning and chat jobs that run asynchronously with automatic retries and status tracking.
These endpoints are backend-internal and require a valid internal API key passed in the Authorization header. Web clients should use the Jobs API proxy endpoints instead.

Job model

Every job follows a common lifecycle:
  1. A job is created with status queued.
  2. A worker claims the job and moves it to running.
  3. On success the job moves to completed with a result payload.
  4. On failure the job is retried (up to maxAttempts) or moves to failed.
Jobs that remain in running state for more than ten minutes are automatically requeued.

Job types

TypeLaneDescription
provision_managed_runtimedeployProvisions a new managed agent runtime
gateway_chat_completionruntime_execSends a chat completion request through a gateway
runtime_syncrecoverySynchronizes runtime state with the platform
retry_repairrecoveryRetries a previously failed operation to repair state

Job statuses

StatusDescription
queuedWaiting to be picked up by a worker
runningCurrently being processed
completedFinished successfully
failedExhausted all retry attempts

Enqueue a provision job

POST /api/platform-jobs/provision
Queues a new managed-runtime provisioning job. The job is processed asynchronously and the response is returned immediately with a 202 Accepted status.

Request body

FieldTypeRequiredDescription
userIdstringYesUser identifier
emailstringYesUser email address
agentIdstringYesAgent identifier to provision
planstringNoSubscription plan. Defaults to solo.
aiProviderstringNoAI provider. Defaults to openrouter.
agentTypestringNoAgent type. Defaults to creative.
autoProvisionbooleanNoWhether to provision automatically. Defaults to false.
stripeSubscriptionIdstring | nullNoStripe subscription identifier, if applicable. Defaults to null.

Response (202)

{
  "success": true,
  "queued": true,
  "job": {
    "id": "job_a1b2c3d4e5f6g7h8",
    "userId": "user_123",
    "agentId": "agent_456",
    "lane": "deploy",
    "jobType": "provision_managed_runtime",
    "status": "queued",
    "priority": 100,
    "attempts": 0,
    "maxAttempts": 5,
    "runAt": "2026-04-07T04:00:00Z",
    "lockedAt": null,
    "startedAt": null,
    "completedAt": null,
    "error": null,
    "result": null,
    "payload": {
      "userId": "user_123",
      "agentId": "agent_456",
      "plan": "solo",
      "aiProvider": "openrouter",
      "agentType": "creative",
      "autoProvision": false
    },
    "createdAt": "2026-04-07T04:00:00Z",
    "updatedAt": "2026-04-07T04:00:00Z"
  }
}

Errors

CodeDescription
400Missing or invalid userId, email, or agentId
500Failed to enqueue the job

Enqueue a chat job

POST /api/platform-jobs/chat
Queues a gateway chat completion job. The job is processed asynchronously and the response is returned immediately with a 202 Accepted status.

Request body

FieldTypeRequiredDescription
userIdstringYesUser identifier
agentIdstringYesAgent identifier
gatewayUrlstringYesGateway URL to send the chat request to
messagestringYesUser message content
systemPromptstring | nullNoOptional system prompt prepended to the conversation. Defaults to null.

Response (202)

{
  "success": true,
  "queued": true,
  "job": {
    "id": "job_b2c3d4e5f6g7h8i9",
    "userId": "user_123",
    "agentId": "agent_456",
    "lane": "runtime_exec",
    "jobType": "gateway_chat_completion",
    "status": "queued",
    "priority": 50,
    "attempts": 0,
    "maxAttempts": 3,
    "runAt": "2026-04-07T04:00:00Z",
    "lockedAt": null,
    "startedAt": null,
    "completedAt": null,
    "error": null,
    "result": null,
    "payload": {
      "userId": "user_123",
      "agentId": "agent_456",
      "plan": null,
      "aiProvider": null,
      "agentType": null,
      "autoProvision": false
    },
    "createdAt": "2026-04-07T04:00:00Z",
    "updatedAt": "2026-04-07T04:00:00Z"
  }
}

Errors

CodeDescription
400Missing or invalid userId, agentId, gatewayUrl, or message
500Failed to enqueue the job

Get a job

GET /api/platform-jobs/:jobId
Returns the current state of a job by its identifier.

Path parameters

ParameterTypeDescription
jobIdstringJob identifier (prefixed with job_)

Response

{
  "job": {
    "id": "job_a1b2c3d4e5f6g7h8",
    "userId": "user_123",
    "agentId": "agent_456",
    "lane": "deploy",
    "jobType": "provision_managed_runtime",
    "status": "completed",
    "priority": 100,
    "attempts": 1,
    "maxAttempts": 5,
    "runAt": "2026-04-07T04:00:00Z",
    "lockedAt": null,
    "startedAt": "2026-04-07T04:00:05Z",
    "completedAt": "2026-04-07T04:00:30Z",
    "error": null,
    "result": {
      "plan": "solo",
      "aiProvider": "openrouter",
      "agentType": "creative",
      "queuedUserId": "user_123",
      "agentId": "agent_456"
    },
    "payload": {
      "userId": "user_123",
      "agentId": "agent_456",
      "plan": "solo",
      "aiProvider": "openrouter",
      "agentType": "creative",
      "autoProvision": false
    },
    "createdAt": "2026-04-07T04:00:00Z",
    "updatedAt": "2026-04-07T04:00:30Z"
  }
}

Job response fields

FieldTypeDescription
job.idstringJob identifier
job.userIdstring | nullUser who owns this job
job.agentIdstring | nullAssociated agent identifier
job.lanestringProcessing lane: deploy for provisioning jobs, runtime_exec for chat completions, or recovery for sync and repair operations
job.jobTypestringJob type (see job types)
job.statusstringCurrent status (see job statuses)
job.prioritynumberPriority value. Higher values are processed first.
job.attemptsnumberNumber of processing attempts so far
job.maxAttemptsnumberMaximum number of attempts before the job is marked as failed
job.runAtstringISO 8601 timestamp of when the job is eligible to run
job.lockedAtstring | nullISO 8601 timestamp of when a worker locked this job
job.startedAtstring | nullISO 8601 timestamp of the first processing attempt
job.completedAtstring | nullISO 8601 timestamp of completion or final failure
job.errorstring | nullError message from the most recent failed attempt
job.resultobject | nullResult payload when the job completes successfully
job.payloadobjectSanitized input payload
job.createdAtstringISO 8601 creation timestamp
job.updatedAtstringISO 8601 last update timestamp

Errors

CodeDescription
404Job not found
500Failed to fetch the job

Get job metrics

GET /api/platform-jobs/metrics
Returns aggregate metrics across all jobs, grouped by lane and status. Useful for monitoring queue health.

Response

{
  "counts": [
    { "lane": "deploy", "status": "queued", "count": 3 },
    { "lane": "deploy", "status": "completed", "count": 120 },
    { "lane": "runtime_exec", "status": "running", "count": 1 }
  ],
  "oldestQueuedAgeSeconds": 12.5
}
FieldTypeDescription
countsarrayJob counts grouped by lane and status
counts[].lanestringProcessing lane
counts[].statusstringJob status
counts[].countnumberNumber of jobs in this lane and status
oldestQueuedAgeSecondsnumberAge in seconds of the oldest queued job. Returns 0 when the queue is empty.

Errors

CodeDescription
500Failed to fetch metrics

Retry behavior

Failed jobs are automatically retried with exponential backoff:
AttemptDelay
130 seconds
260 seconds
390 seconds
4120 seconds
5+300 seconds (capped)
Provision jobs allow up to five attempts. Chat jobs allow up to three attempts. After exhausting all attempts, the job status is set to failed.