TaskBullet Agent API API

Delegate tasks from AI agents and LLMs to real human virtual assistants (Human-in-the-loop).

Operations 11

POST /delegate File a task #
GET /balance Get Hour Balance #
GET /tasks List Delegated Tasks #
GET /tasks/{taskId} Get Task Status #
POST /actions Request one human email
GET /actions List email actions for this key
POST /actions/validate Validate an email action without a hold
GET /actions/{actionId} Read one email action
PATCH /actions/{actionId} Fill needs_info or answer a VA follow-up
POST /actions/{actionId}/approve Approve the final email
POST /actions/{actionId}/cancel Cancel an unsent email action

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/taskbullet-com:taskbullet-agent-api-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

taskbullet-com-api-openapi.json Raw ↑
{
  "openapi": "3.1.0",
  "info": {
    "title": "TaskBullet Agent API",
    "description": "Delegate tasks from AI agents and LLMs to real human virtual assistants (Human-in-the-loop).",
    "version": "1.0.0",
    "contact": {
      "name": "TaskBullet Support",
      "url": "https://taskbullet.com"
    }
  },
  "servers": [
    {
      "url": "https://taskbullet.com/api/v1",
      "description": "Production API"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Your TaskBullet Agent API Key (begins with tb_live_)"
      }
    },
    "schemas": {
      "TaskStatus": {
        "type": "string",
        "enum": ["pending", "in_progress", "completed", "failed", "cancelled"],
        "description": "The current status of the task. Stop polling on completed, failed, or cancelled. Customer cancel is cancelled, not pending or in_progress."
      },
      "TaskPriority": {
        "type": "string",
        "enum": ["low", "normal", "high", "urgent"],
        "default": "normal",
        "description": "The priority level of the task."
      },
      "ActionRequest": {
        "type": "object",
        "required": ["action_type", "recipients", "subject", "goal", "message", "consent_attestation", "deadline", "provider", "delegated_credential", "credential_scope", "credential_expires_at"],
        "properties": {
          "action_type": { "type": "string", "enum": ["email"] },
          "recipients": { "type": "array", "items": { "type": "string", "format": "email" } },
          "subject": { "type": "string" },
          "goal": { "type": "string" },
          "message": { "type": "string" },
          "on_behalf_of": { "type": "string" },
          "consent_attestation": { "type": "boolean" },
          "deadline": { "type": "string", "format": "date-time" },
          "provider": { "type": "string", "enum": ["google", "gmail"] },
          "delegated_credential": {
            "type": "object",
            "description": "Write-only one-time send credential. Never returned, logged, or sent to ops.",
            "required": ["access_token"],
            "properties": {
              "access_token": { "type": "string" },
              "refresh_token": { "type": "string" }
            }
          },
          "credential_scope": {
            "type": "object",
            "required": ["recipients", "subject", "message"],
            "properties": {
              "recipients": { "type": "array", "items": { "type": "string" } },
              "subject": { "type": "string" },
              "message": { "type": "string" }
            }
          },
          "credential_expires_at": { "type": "string", "format": "date-time" },
          "callback_url": { "type": "string", "format": "uri" }
        }
      }
    }
  },
  "paths": {
    "/delegate": {
      "post": {
        "summary": "File a task",
        "description": "Files a brief. The customer starts VA hours on Work. The dedicated VA already stored on the account is the assignee after release. If none is stored, the account manager staffs it. Requires an Idempotency-Key header.",
        "operationId": "delegateTask",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": { "type": "string" },
            "description": "Required. The same account and key returns the original task. Empty is 400. Length is bounded by the stored column."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["title"],
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 5000,
                    "description": "A clear, concise title or directive for the task. (Alias: 'task'.)"
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 8000,
                    "description": "Detailed instructions, context, or constraints for the virtual assistant (max 8000). Alias: 'context'. Never include passwords, OTP codes, recovery keys, cookies, or API keys."
                  },
                  "dueDate": {
                    "type": "string",
                    "description": "Optional human-readable due date or deadline for the task."
                  },
                  "priority": {
                    "$ref": "#/components/schemas/TaskPriority"
                  },
                  "webhookUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "An optional URL. TaskBullet will POST a signed webhook here when the customer closes the job (client_complete). A VA checkbox does not send this webhook. A customer cancel does not send it."
                  },
                  "sourceAgent": {
                    "type": "string",
                    "description": "Optional identifier for the calling agent (e.g. 'claude-3-opus', 'my-custom-gpt'). Used for audit trails and routing context."
                  },
                  "maxHours": {
                    "type": "number",
                    "minimum": 0.01,
                    "maximum": 8,
                    "default": 0.5,
                    "description": "Spend cap in hours (default 0.5, max 8). VA/AM stop and ask before exceeding. Actual tracked time is billed, not this cap."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task filed. awaiting_customer_start means it is NOT started until the customer clicks Start on Work.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "taskId": { "type": "string", "description": "Stable external ID used to track the task." },
                    "status": {
                      "type": "string",
                      "enum": ["awaiting_customer_start", "received"],
                      "description": "awaiting_customer_start means the task is NOT started until the customer clicks Start on Work. received is a replay after start, a hold, or a sent board card."
                    },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": { "description": "Bad Request (missing title, missing Idempotency-Key, unknown priority, oversize fields, or secrets in title/description)" },
          "401": { "description": "Unauthorized (Invalid or missing API key)" },
          "402": { "description": "Payment Required. Only when a live Ops read is not above zero. Body includes hoursRemaining and addHoursUrl (https://taskbullet.com/packages-pricing)." },
          "422": { "description": "The requested maxHours does not fit open caps. Hours remain. Body includes hoursRemaining and capRoom. No addHoursUrl. Lower maxHours to capRoom or wait for open work to finish." },
          "413": { "description": "Request body larger than 32 KiB" },
          "429": { "description": "Too Many Requests. The ceiling is per server instance and does not hold across instances." }
        }
      }
    },
    "/balance": {
      "get": {
        "summary": "Get Hour Balance",
        "description": "Remaining VA hours, capRoom, and whether a new cap can be filed. canDelegate is false when hours are unavailable, when spendable hours are not above zero, or when open caps leave less than the minimum new cap. canDelegate false while hoursRemaining is above zero means lower maxHours to capRoom or wait. It is not a buy-hours signal. Call before delegating. Does not create a task.",
        "operationId": "getBalance",
        "responses": {
          "200": {
            "description": "Hour balance for this account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "hoursRemaining": { "type": "number" },
                    "canDelegate": { "type": "boolean" },
                    "addHoursUrl": { "type": "string", "format": "uri" },
                    "hoursUnavailable": { "type": "boolean", "description": "True when Ops did not return a live remaining figure. capRoom is omitted on that read." },
                    "capRoom": { "type": "number", "description": "Hours free for a new cap after open caps, floored to the centihour. Present on a live read." }
                  }
                }
              }
            }
          },
          "401": { "description": "Unauthorized (Invalid or missing API key)" },
          "429": { "description": "Too Many Requests. The ceiling is per server instance and does not hold across instances." }
        }
      }
    },
    "/tasks": {
      "get": {
        "summary": "List Delegated Tasks",
        "description": "Fetch a list of recent tasks delegated via the Agent API.",
        "operationId": "listTasks",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter tasks by status.",
            "schema": {
              "type": "string",
              "enum": ["pending", "in_progress", "completed", "failed", "cancelled", "all"],
              "default": "all"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A list of tasks.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tasks": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "taskId": { "type": "string" },
                          "title": { "type": "string", "description": "Client-facing task title (ops prefixes stripped)." },
                          "status": { "$ref": "#/components/schemas/TaskStatus" },
                          "priority": { "$ref": "#/components/schemas/TaskPriority" },
                          "createdAt": { "type": "string", "format": "date-time" },
                          "completedAt": { "type": "string", "format": "date-time" },
                          "result": { "type": "string", "description": "Short VA result snippet when completed. Full notes are on GET /tasks/{taskId}." }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/tasks/{taskId}": {
      "get": {
        "summary": "Get Task Status",
        "description": "Poll the current status and result of a specific task. Stop when status is completed, failed, or cancelled. Customer cancel is cancelled and does not send the completion webhook.",
        "operationId": "getTask",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "description": "The stable ID returned when the task was delegated.",
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Task status and result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "taskId": { "type": "string" },
                    "title": { "type": "string" },
                    "status": { "$ref": "#/components/schemas/TaskStatus" },
                    "priority": { "$ref": "#/components/schemas/TaskPriority" },
                    "createdAt": { "type": "string", "format": "date-time" },
                    "result": { "type": "string", "description": "Notes or deliverables from the human VA (only present if completed)." },
                    "completedAt": { "type": "string", "format": "date-time" }
                  }
                }
              }
            }
          },
          "404": { "description": "Task not found" }
        }
      }
    },
    "/actions": {
      "post": {
        "summary": "Request one human email",
        "description": "Flat fee hold from the prepaid wallet (reason ACTION). Missing, expired, or scope-mismatched delegated credentials return needs_info and charge nothing. The delegated credential is write-only and is never returned. Idempotency-Key header is required.",
        "parameters": [
          { "name": "Idempotency-Key", "in": "header", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ActionRequest" }
            }
          }
        },
        "responses": {
          "201": { "description": "Queued and the flat fee is held." },
          "200": { "description": "needs_info. No charge." },
          "402": { "description": "Wallet cannot cover the flat fee." },
          "409": { "description": "idempotency_conflict or too_many_actions." }
        }
      },
      "get": {
        "summary": "List email actions for this key",
        "responses": { "200": { "description": "Recent actions. No credentials." } }
      }
    },
    "/actions/validate": {
      "post": {
        "summary": "Validate an email action without a hold",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActionRequest" } } }
        },
        "responses": { "200": { "description": "valid true or needs_info. No charge." } }
      }
    },
    "/actions/{actionId}": {
      "get": {
        "summary": "Read one email action",
        "parameters": [{ "name": "actionId", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "Action resource. credential_present is a boolean. The token is not included." },
          "404": { "description": "Not found" }
        }
      },
      "patch": {
        "summary": "Fill needs_info or answer a VA follow-up",
        "parameters": [{ "name": "actionId", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Updated action or needs_info." } }
      }
    },
    "/actions/{actionId}/approve": {
      "post": {
        "summary": "Approve the final email",
        "description": "Send stays blocked until consent_attestation is true and the final text matches the delegated scope.",
        "parameters": [{ "name": "actionId", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Approved, or needs_info when a new credential is required." } }
      }
    },
    "/actions/{actionId}/cancel": {
      "post": {
        "summary": "Cancel an unsent email action",
        "parameters": [{ "name": "actionId", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "Cancelled. Hold released and credential revoked." },
          "409": { "description": "cancel_too_late after the email was sent." }
        }
      }
    }
  }
}