Delegate tasks from your AI agent to a real human virtual assistant. This API enables seamless AI agent handoff for human-in-the-loop tasks that LLMs cannot complete autonomously.
https://taskbullet.comAuth: x-api-key: tb_live_…Rate limit: 60 req / min / keyOpenAPI (Swagger) Spec →MCP Server (npm) →MCP Server (GitHub) →Issue an API key from your account settings and send your first task in under a minute.
curl -X POST https://taskbullet.com/api/v1/delegate \
-H "x-api-key: tb_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"task": "Research and compile a list of the top 10 AI newsletters with subscriber counts",
"context": "We are preparing a partnership outreach deck for Q3.",
"priority": "normal",
"webhookUrl": "https://your-app.com/hooks/taskbullet"
}'// Response
{
"success": true,
"taskId": "atask_a3f9c2d1e4b5a6f7",
"status": "received",
"message": "Task received. A TaskBullet VA will pick this up shortly."
}All /api/v1/ requests must include your API key in the x-api-key header. Keys begin with tb_live_ and are issued from your settings page.
process.env) immediately.// All v1 endpoints
x-api-key: tb_live_<64 hex chars>Delegate a task to a TaskBullet VA. The task is routed through your Basecamp project and matched to the appropriate specialist.
| Field | Type | Description |
|---|---|---|
taskrequired | string | What you want done. Max 5,000 chars. Used as the Basecamp todo title (first 240 chars). |
context | string | Additional background for the VA. Appended to the Basecamp description. |
priority | "low" | "normal" | "high" | "urgent" | Defaults to "normal". |
dueDate | string | Free-form due date hint (e.g. "EOD Friday"). Appended to task description. |
webhookUrl | string | HTTPS URL to receive a signed POST when the VA marks the task complete. |
sourceAgent | string | Name of the calling agent for audit trails (e.g. "claude-3-opus"). |
200 OK{
"success": true,
"taskId": "atask_a3f9c2d1e4b5a6f7", // stable ID — use to poll status
"status": "received",
"message": "Task received. A TaskBullet VA will pick this up shortly."
}The initial "received" status is an acknowledgment that the request was accepted. It is only returned by this endpoint and will not appear in subsequent polls — the task transitions to "pending" as soon as it is queued internally (typically within a second).
List delegated tasks for your account. Optionally filter by status.
| Param | Values | Description |
|---|---|---|
status | "pending" | "in_progress" | "completed" | "failed" | "all" | Defaults to "all". Returns up to 50 tasks. |
// GET /api/v1/tasks?status=completed
{
"tasks": [
{
"taskId": "atask_a3f9c2d1e4b5a6f7",
"status": "completed",
"priority": "normal",
"createdAt": "2026-05-28T14:00:00.000Z",
"completedAt": "2026-05-29T09:15:00.000Z"
}
]
}Poll the status of a specific task by its taskId returned from /delegate.
// GET /api/v1/tasks/atask_a3f9c2d1e4b5a6f7
{
"taskId": "atask_a3f9c2d1e4b5a6f7",
"status": "completed", // pending | in_progress | completed | failed
"priority": "normal",
"createdAt": "2026-05-28T14:00:00.000Z",
"result": "Completed the research. List attached in Basecamp.",
"completedAt": "2026-05-29T09:15:00.000Z"
}| Status | Meaning |
|---|---|
pending | Received, not yet in Basecamp |
in_progress | In Basecamp — VA is working on it |
completed | VA has marked the Basecamp todo complete |
failed | Could not be delivered (todo was deleted, etc.) |
If you pass webhookUrl when delegating, TaskBullet will POST a signed payload when the VA completes the task. Verify the signature before processing.
POST https://your-app.com/hooks/taskbullet
Content-Type: application/json
x-taskbullet-signature: <hex>
x-taskbullet-timestamp: <unix seconds>
{
"event": "task.completed",
"taskId": "atask_a3f9c2d1e4b5a6f7",
"taskTitle": "Book a flight to Austin",
"status": "completed",
"result": "Booked on Delta flight 1423, confirmation #XYZ.",
"timestamp": "2026-05-29T09:15:00.000Z"
}import crypto from 'crypto';
function verifyWebhook(req, webhookSecret) {
const sig = req.headers['x-taskbullet-signature'];
const ts = req.headers['x-taskbullet-timestamp']; // Unix seconds
const body = req.rawBody; // RAW request body string — NOT JSON.stringify(parsed)
const expected = crypto
.createHmac('sha256', webhookSecret)
.update(`${ts}.${body}`)
.digest('hex');
// Use timingSafeEqual to prevent timing attacks
return crypto.timingSafeEqual(
Buffer.from(sig, 'hex'),
Buffer.from(expected, 'hex'),
);
}Important: x-taskbullet-timestamp is Unix seconds (not milliseconds), and rawBody must be the exact bytes received from the request — not a re-serialized JSON string. Most frameworks expose this as req.rawBody or via a buffer-capture middleware. Re-parsing and re-stringifying will produce a different byte sequence and the signature will not match.
The webhookSecret is the value shown at API key creation time — separate from the API key itself. Retries are attempted up to 5 times (every ~15 min) before giving up.
| Status | Cause |
|---|---|
400 | Missing or invalid request body |
401 | Missing, invalid, or revoked API key |
402 | No hour balance — add hours at taskbullet.com |
409 | Account not yet provisioned — complete onboarding first |
429 | Rate limit exceeded (60 req/min) — respect Retry-After header |
500 | Internal server error |
All error responses include a JSON body: { "error": "message" }
Ready to integrate?
Issue your API key from the dashboard settings, then connect your AI agent or automation workflow.
Get your API key