Bỏ qua để đến nội dung

TasksBoard API reference

Nội dung này hiện chưa có sẵn bằng ngôn ngữ của bạn.

The TasksBoard REST API lets Team plan accounts read and write their Google Tasks (lists, tasks, boards) and receive webhooks when tasks change. Every list and task id is the Google Tasks id, so anything you build on the API stays compatible with Google Tasks itself.

Authentication. Create a personal API key on the Team page of the app (/team?tab=api) and send it as a bearer token: Authorization: Bearer tb_live_…. A key acts as the user who created it. Keys carry scopes (read, write); a key without write gets 403 forbidden on every write.

Errors are JSON: { "error": { "code": "…", "message": "…", "details": [...] } }. code is stable, message is for humans. details lists field errors on 422.

Rate limit: 60 requests per minute per key. Responses carry X-RateLimit-Limit and X-RateLimit-Remaining; a 429 carries Retry-After (seconds).

Pagination: list endpoints return meta.nextCursor when there is more; pass it back as cursor with the same filters.

Task extras. Google Tasks only stores a title, notes and a due date. TasksBoard keeps labels and the assignee inside the notes (labels on the first line, then 👤 Assigned to <email>), and the API reads and writes them as the labels and assignee fields, so the free text you see in notes is what the user sees on the board.

Base URL: https://api.tasksboard.com/v1

  1. In TasksBoard, open Team → API (/team?tab=api) and create a key. Copy it: it is shown once.
  2. Call the API with the key as a bearer token:
Terminal window
curl https://api.tasksboard.com/v1/lists -H "Authorization: Bearer tb_live_…"
  1. Create a task on a list:
Terminal window
curl -X POST https://api.tasksboard.com/v1/lists/LIST_ID/tasks \
-H "Authorization: Bearer tb_live_…" -H "Content-Type: application/json" \
-d '{"title": "Send the Q3 report", "due": "2026-10-24", "labels": ["❗️Important"]}'

Prefer no code? The TasksBoard app for Zapier uses the same keys.

GET /me

Responses

  • 200 The account and the key’s scopes.
{
"data": {
"id": "u_123",
"email": "ana@example.com",
"displayName": "Ana",
"plan": "team",
"key": {
"id": "k_1",
"scopes": [
"read",
"write"
]
}
}
}
  • 401 Missing, malformed, unknown or revoked API key.
  • 403 team_plan_required (the key’s owner has no Team plan), forbidden (the key lacks the write scope) or google_access_expired (the user must sign in to TasksBoard again).

GET /lists

Parameters

ParameterInTypeDescription
cursorquerystringOpaque cursor from a previous response’s meta.nextCursor.
limitqueryinteger, default 50

Responses

  • 200 The user’s Google Tasks lists. → data: array of List
  • 401 Missing, malformed, unknown or revoked API key.

POST /lists

Request body

FieldTypeDescription
title (required)string
{
"title": "Q4 launch"
}

Responses

  • 201 Created. Location points at the new list. → data: List
  • 403 team_plan_required (the key’s owner has no Team plan), forbidden (the key lacks the write scope) or google_access_expired (the user must sign in to TasksBoard again).
  • 422 The request body or query is invalid; details names the fields.

GET /lists/{listId}

Parameters

ParameterInTypeDescription
listId (required)pathstringGoogle Tasks list id.

Responses

  • 200 The list. → data: List
  • 404 No such list, task or webhook.

GET /lists/{listId}/tasks

Open tasks by default. updatedAfter is the polling idiom: ask for tasks changed since your last call (Zapier’s triggers do exactly this). Completed tasks that the user cleared from the board are still returned with status=completed or all.

Parameters

ParameterInTypeDescription
listId (required)pathstringGoogle Tasks list id.
statusqueryopen | completed | all, default open
updatedAfterquerystring (date-time)RFC 3339 timestamp; only tasks modified after it.
dueAfterquerystring (date-time)
dueBeforequerystring (date-time)
includeDeletedqueryboolean, default false
cursorquerystringOpaque cursor from a previous response’s meta.nextCursor.
limitqueryinteger, default 50

Responses

  • 200 Tasks, newest first as Google orders them. → data: array of Task
  • 404 No such list, task or webhook.
  • 422 The request body or query is invalid; details names the fields.

POST /lists/{listId}/tasks

Parameters

ParameterInTypeDescription
listId (required)pathstringGoogle Tasks list id.

Request body

FieldTypeDescription
title (required)string
notesstring
duestring (date-time)RFC 3339 date or date-time; the time is discarded.
labelsarray of stringA label name without whitespace
assigneestring (email)Must be a collaborator of the list (or the user).
parentstringMake it a subtask of this task.
previousstringInsert after this sibling.
{
"title": "Send the Q3 report",
"notes": "Numbers from finance first",
"due": "2026-10-24",
"labels": [
"❗️Important"
],
"assignee": "bob@example.com"
}

Responses

  • 201 Created. Location points at the task (with its listId). → data: Task
  • 403 team_plan_required (the key’s owner has no Team plan), forbidden (the key lacks the write scope) or google_access_expired (the user must sign in to TasksBoard again).
  • 404 No such list, task or webhook.
  • 422 The request body or query is invalid; details names the fields.

GET /tasks/{taskId}

Google Tasks addresses a task by list and id, so listId is required.

Parameters

ParameterInTypeDescription
taskId (required)pathstringGoogle Tasks task id.
listId (required)querystringThe Google Tasks list the task belongs to.

Responses

  • 200 The task. → data: Task
  • 404 No such list, task or webhook.

PATCH /tasks/{taskId}

Partial update: only the fields you send change. Send null to clear notes, due, labels or assignee. status: "open" reopens a completed task.

Parameters

ParameterInTypeDescription
taskId (required)pathstringGoogle Tasks task id.

Request body

FieldTypeDescription
listId (required)string
titlestring
notesstring | null
duestring | null (date-time)
labelsarray | null
assigneestring | null (email)
statusopen | completed
{
"listId": "MTIzNDU2Nzg5",
"due": "2026-10-31",
"labels": [
"🔥Hot"
]
}

Responses

  • 200 The updated task. → data: Task
  • 403 team_plan_required (the key’s owner has no Team plan), forbidden (the key lacks the write scope) or google_access_expired (the user must sign in to TasksBoard again).
  • 404 No such list, task or webhook.
  • 422 The request body or query is invalid; details names the fields.

DELETE /tasks/{taskId}

Parameters

ParameterInTypeDescription
taskId (required)pathstringGoogle Tasks task id.
listId (required)querystringThe Google Tasks list the task belongs to.

Responses

  • 204 Deleted.
  • 403 team_plan_required (the key’s owner has no Team plan), forbidden (the key lacks the write scope) or google_access_expired (the user must sign in to TasksBoard again).
  • 404 No such list, task or webhook.

POST /tasks/{taskId}/complete

Parameters

ParameterInTypeDescription
taskId (required)pathstringGoogle Tasks task id.
listId (required)querystringThe Google Tasks list the task belongs to.

Responses

  • 200 The completed task. → data: Task
  • 403 team_plan_required (the key’s owner has no Team plan), forbidden (the key lacks the write scope) or google_access_expired (the user must sign in to TasksBoard again).
  • 404 No such list, task or webhook.

GET /boards

TasksBoard boards and the list ids each one shows. The main board is always first.

Responses

  • 200 Boards. → data: array of Board

GET /webhooks

Responses

  • 200 Webhooks (secrets are never returned here). → data: array of Webhook

POST /webhooks

At most 10 webhooks per account, https URLs only. The signing secret is returned once, in this response. Verify deliveries with the X-TasksBoard-Signature header (t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>" with the secret>).

Where events come from: the API’s own writes, changes propagated on shared lists, and, when the user turns on “poll my lists every 15 minutes” on the Team page, any change made in Google’s own apps on lists that are not shared. Without polling, those changes are not observed.

Request body

FieldTypeDescription
url (required)string (uri)
events (required)array of WebhookEvent
secretstringYour own signing secret; generated when omitted.
{
"url": "https://hooks.example.com/tasksboard",
"events": [
"task.created",
"task.completed"
]
}

Responses

  • 201 Created, with the secret.
  • 409 A limit was reached.
  • 422 The request body or query is invalid; details names the fields.

GET /webhooks/{webhookId}

Parameters

ParameterInTypeDescription
webhookId (required)pathstring

Responses

  • 200 The webhook. → data: Webhook
  • 404 No such list, task or webhook.

PATCH /webhooks/{webhookId}

Setting active to true re-enables a webhook switched off after repeated failures.

Parameters

ParameterInTypeDescription
webhookId (required)pathstring

Request body

FieldTypeDescription
urlstring (uri)
eventsarray of WebhookEvent
activeboolean

Responses

  • 200 The updated webhook. → data: Webhook
  • 404 No such list, task or webhook.
  • 422 The request body or query is invalid; details names the fields.

DELETE /webhooks/{webhookId}

Parameters

ParameterInTypeDescription
webhookId (required)pathstring

Responses

  • 204 Deleted.
  • 404 No such list, task or webhook.

Sent to each webhook subscribed to the event. Answer with any 2xx within 10 seconds. Failed deliveries are retried up to 3 times with backoff; after 20 consecutive failures the webhook is switched off (active: false) until you re-enable it.

Headers

ParameterInTypeDescription
X-TasksBoard-Signature (required)headerstring
X-TasksBoard-Eventheadertask.created | task.updated | task.completed | task.deleted
X-TasksBoard-Deliveryheaderstring

Body

FieldTypeDescription
idstringDelivery id
eventWebhookEvent
createdAtstring (date-time)
sourceapi | sync | pollapi: a REST call; sync: shared-list propagation; poll: the 15-minute poll.
attemptinteger
dataobject
{
"id": "2b1f0c2e-…",
"event": "task.completed",
"createdAt": "2026-10-15T09:12:33.000Z",
"source": "sync",
"attempt": 1,
"data": {
"task": {
"id": "aBc123",
"listId": "MTIzNDU2Nzg5",
"title": "Send the Q3 report",
"status": "completed",
"completed": "2026-10-15T09:12:30.000Z",
"labels": [],
"assignee": null,
"notes": "",
"due": null,
"updated": "2026-10-15T09:12:33.000Z",
"parent": null,
"position": null,
"deleted": false,
"webViewLink": null
}
}
}

Verifying a signature (Node.js):

const crypto = require("crypto")
function verify(secret, rawBody, header, toleranceSeconds = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")))
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > toleranceSeconds) return false
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex")
return crypto.timingSafeEqual(Buffer.from(parts.v1, "hex"), Buffer.from(expected, "hex"))
}

Compute the HMAC over the raw request body exactly as received (before any JSON parsing).

One of: read, write

FieldTypeDescription
error (required)object
FieldTypeDescription
nextCursorstring | null
hasNextboolean
FieldTypeDescription
idstring
titlestring
updatedstring (date-time)
sharedbooleanShared through TasksBoard with collaborators.
boardIdstringThe TasksBoard board the list is on (default = main board).
FieldTypeDescription
idstring
listIdstring
titlestring
notesstringFree text
statusopen | completed
duestring | null (date-time)Google keeps the date only; the time is always midnight UTC.
completedstring | null (date-time)
updatedstring (date-time)
parentstring | nullParent task id for subtasks.
positionstring | null
labelsarray of string
assigneestring | nullEmail of the collaborator the task is assigned to.
deletedboolean
webViewLinkstring | null
{
"id": "aBc123",
"listId": "MTIzNDU2Nzg5",
"title": "Send the Q3 report",
"notes": "Numbers from finance first",
"status": "open",
"due": "2026-10-24T00:00:00.000Z",
"completed": null,
"updated": "2026-10-15T09:12:33.000Z",
"parent": null,
"position": "00000000000000000001",
"labels": [
"❗️Important"
],
"assignee": "bob@example.com",
"deleted": false,
"webViewLink": "https://tasks.google.com/task/aBc123"
}
FieldTypeDescription
title (required)string
notesstring
duestring (date-time)RFC 3339 date or date-time; the time is discarded.
labelsarray of stringA label name without whitespace
assigneestring (email)Must be a collaborator of the list (or the user).
parentstringMake it a subtask of this task.
previousstringInsert after this sibling.
FieldTypeDescription
listId (required)string
titlestring
notesstring | null
duestring | null (date-time)
labelsarray | null
assigneestring | null (email)
statusopen | completed
FieldTypeDescription
idstring
titlestring
positioninteger
listIdsarray of string

One of: task.created, task.updated, task.completed, task.deleted

FieldTypeDescription
idstring
urlstring (uri)
eventsarray of WebhookEvent
activeboolean
createdAtstring (date-time)
updatedAtstring (date-time)
lastDeliveryAtstring | null (date-time)
lastStatusinteger | nullHTTP status of the last delivery.
failuresintegerConsecutive failed deliveries.
FieldTypeDescription
idstringDelivery id
eventWebhookEvent
createdAtstring (date-time)
sourceapi | sync | pollapi: a REST call; sync: shared-list propagation; poll: the 15-minute poll.
attemptinteger
dataobject
{
"id": "2b1f0c2e-…",
"event": "task.completed",
"createdAt": "2026-10-15T09:12:33.000Z",
"source": "sync",
"attempt": 1,
"data": {
"task": {
"id": "aBc123",
"listId": "MTIzNDU2Nzg5",
"title": "Send the Q3 report",
"status": "completed",
"completed": "2026-10-15T09:12:30.000Z",
"labels": [],
"assignee": null,
"notes": "",
"due": null,
"updated": "2026-10-15T09:12:33.000Z",
"parent": null,
"position": null,
"deleted": false,
"webViewLink": null
}
}
}

The TasksBoard app for Zapier authenticates with the same personal API key and offers:

  • Triggers: New Task, Task Completed (polling on updatedAfter).
  • Actions: Create Task, Complete Task, Create List.

Search for TasksBoard in Zapier, paste your key when asked, and pick a list. The app’s source lives in packages/zapier of the TasksBoard repository.

  • The API is part of the Team plan; a key whose owner leaves the plan answers 403 team_plan_required.
  • 60 requests per minute per key; Google Tasks’ own quotas apply on top.
  • A key acts as its owner: whatever that person can do in Google Tasks, the key can do. Revoke a key from the Team page the moment it may have leaked.
  • Due dates are dates: Google Tasks drops the time of day.
  • Changes made in Google’s own apps on lists that are not shared are only observed when “poll my lists every 15 minutes” is on (Team → API).