# GetItDone — Full Developer Documentation

> Concatenated markdown of the GetItDone developer docs. Source of truth: https://nowgetitdone.com/docs/api

# GetItDone for Developers

Build task automation, AI agents, and integrations on the GetItDone platform — one product, three doors: a REST API, a TypeScript SDK, and an MCP server.

## Get your API key

https://app.nowgetitdone.com/settings/api-keys

## The three doors

- **REST API** — https://app.nowgetitdone.com/v1 (https://nowgetitdone.com/docs/api)
- **TypeScript SDK** — https://github.com/DevinoSolutions/getitdone-sdk (published on npm — `npm install @nowgetitdone/sdk`)
- **MCP server** — https://app.nowgetitdone.com/api/mcp (https://nowgetitdone.com/mcp)

## Built for AI agents

GetItDone treats AI as a first-class user: the MCP server hands assistants rich task context (including image and video-frame context), keys are scope-gated, and plan quotas act as guardrails. Full API docs: https://nowgetitdone.com/docs/api

## Rate limits & quotas

| Plan | API calls / period | Burst / minute | Webhooks |
| --- | --- | --- | --- |
| Free | 50 | 10 | No |
| Pro | 50,000 | 120 | Yes |
| Team | 500,000 | 300 | Yes |


---

# GetItDone API — Documentation

The public GetItDone REST API is AI-native task management for people and agents. Authenticate with a `gid_` API key over Bearer auth.

## Base URL

```text
https://app.nowgetitdone.com/v1
```

## Quickstart — first 200

1. Create an API key in the app: https://app.nowgetitdone.com/settings/api-keys
2. Call the API with your key:

```bash
curl https://app.nowgetitdone.com/v1/organizations \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

A successful list returns a cursor envelope:

```json
{
  "data": [
    { "id": "org_a1b2c3", "name": "Acme Inc", "role": "owner" }
  ],
  "has_more": false,
  "next_cursor": null
}
```

## Authentication

Send `Authorization: Bearer gid_…` on every request; `x-api-key: gid_…` is also accepted. Keys are minted in-app (Profile → API Keys) and shown once. Test keys are prefixed `gid_test_`.

## Errors

Errors are RFC 9457 `application/problem+json` documents with a stable machine-readable `code` — switch on `code`, never on `title`. Every response carries an `x-request-id`; quote it in support requests. The full error index: https://nowgetitdone.com/docs/api/problems

## Rate limits & quotas

Two independent systems: a per-credential BURST window (429 `rate_limited`, retry after `Retry-After`) and a billing-period ALLOWANCE (429 `quota_exhausted`). Every response carries IETF draft-11 `RateLimit`/`RateLimit-Policy` headers plus the `X-RateLimit-Limit`/`-Remaining`/`-Reset` trio.

| Plan | API calls / period | Burst / minute |
| --- | --- | --- |
| Free | 50 | 10 |
| Pro | 50,000 | 120 |
| Team | 500,000 | 300 |

Outbound webhooks require a Pro or Team plan. One API call = one request against your workspace quota; it resets each billing period.

## Pagination

List endpoints return `{ data, has_more, next_cursor }`. Pass `next_cursor` back as the `after` query parameter to fetch the next page. Filters are baked into the cursor — reusing a cursor with different filters answers 400 `validation_failed`.

## Idempotency

Consequential POSTs accept an optional `Idempotency-Key` header (1–255 chars; a UUID works). Retrying with the same key and byte-identical body within 24h replays the stored response; a different body answers 422 `idempotency_key_reused`; a retry racing the first answers 409 `idempotency_in_progress`.

## Explore

- Operations index: https://nowgetitdone.com/docs/api/operations
- API reference (OpenAPI): https://nowgetitdone.com/docs/api/reference
- OpenAPI document: https://nowgetitdone.com/docs/api/openapi.json
- Error codes: https://nowgetitdone.com/docs/api/problems
- Webhooks: https://nowgetitdone.com/docs/api/webhooks
- TypeScript SDK: https://github.com/DevinoSolutions/getitdone-sdk (published on npm — `npm install @nowgetitdone/sdk`)
- MCP server: https://app.nowgetitdone.com/api/mcp


---

# API Operations

## Organizations

# List organizations — GetItDone API

`GET /v1/organizations`

Lists the organizations this credential can access. A credential is bound to exactly one organization today, so the list always fits one page.

- **Required scopes:** `workspaces:read`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Response 200

The organizations visible to this credential.

- `data` (object[], required) — The current page of results.
- `has_more` (boolean, required) — True when another page exists after this one.
- `next_cursor` (string | null, required) — Opaque cursor for the next page (pass as `after`); null on the last page.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/organizations \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Get an organization — GetItDone API

`GET /v1/organizations/{organization_id}`

Fetches a single organization by id. The id MUST equal this credential's own organization — any other id (including one that genuinely exists for a different tenant) answers 404 `resource_not_found`; there is no cross-org existence oracle.

- **Required scopes:** `workspaces:read`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `organization_id` (string, required) — Must equal the credential's own organization id.

## Response 200

The organization.

- `id` (string, required) — Stable opaque organization id.
- `name` (string, required) — Display name.
- `slug` (string, required) — URL-safe unique slug.
- `image_url` (string | null, required) — Logo URL, or null when none is set.
- `created_at` (string (date-time), required) — Creation time, ISO-8601 UTC.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/organizations/org_a1b2c3 \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

## Usage

# Get plan usage — GetItDone API

`GET /v1/usage`

Reports the current billing period, per-meter consumption against the plan, and the per-credential burst allowance. Reading usage never consumes the API-call quota (the meter cost is zero), so this endpoint stays reachable even when the period allowance is exhausted.

- **Required scopes:** `usage:read`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 0 API calls against your workspace quota.
- **Idempotency:** not applicable

## Response 200

The organization's current usage snapshot.

- `plan` ("FREE" | "PRO" | "TEAM", required) — The organization's current plan tier.
- `period_start` (string (date-time), required) — Start of the current billing period, ISO-8601 UTC. Paid plans anchor at their subscription renewal; free plans at the first of the calendar month.
- `period_end` (string (date-time), required) — End of the current billing period, ISO-8601 UTC — when period meters reset.
- `meters` (object[], required) — Per-meter consumption for the current period.
- `burst` (object, required) — The per-credential burst policy (separate from period quotas; every key/token gets its own window).

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/usage \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

## Members

# List members — GetItDone API

`GET /v1/members`

Cursor-paginated list of the credential's organization members, newest membership first.

- **Required scopes:** `members:read`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Query parameters

- `limit` (integer) — Maximum number of items to return (1-100).
- `after` (string) — Opaque cursor from a previous page's `next_cursor` — omit for the first page. Reusing a cursor with DIFFERENT query parameters (e.g. a different `limit`) answers 400 `validation_failed`.

## Response 200

Page of the organization's members.

- `data` (object[], required) — The current page of results.
- `has_more` (boolean, required) — True when another page exists after this one.
- `next_cursor` (string | null, required) — Opaque cursor for the next page (pass as `after`); null on the last page.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/members \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

## Projects

# List projects — GetItDone API

`GET /v1/projects`

Cursor-paginated list of the credential's organization projects, newest first.

- **Required scopes:** `projects:read`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Query parameters

- `limit` (integer) — Maximum number of items to return (1-100).
- `after` (string) — Opaque cursor from a previous page's `next_cursor` — omit for the first page. Reusing a cursor with DIFFERENT query parameters (e.g. a different `limit`) answers 400 `validation_failed`.

## Response 200

Page of the organization's projects.

- `data` (object[], required) — The current page of results.
- `has_more` (boolean, required) — True when another page exists after this one.
- `next_cursor` (string | null, required) — Opaque cursor for the next page (pass as `after`); null on the last page.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/projects \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Get a project — GetItDone API

`GET /v1/projects/{project_id}`

Fetches a single project by id, scoped to the credential's organization. A project id from another organization (or an unknown id) answers 404 `resource_not_found` — no cross-org existence oracle.

- **Required scopes:** `projects:read`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `project_id` (string, required)

## Response 200

The project.

- `id` (string, required) — Stable opaque project id.
- `name` (string, required) — Display name, unique within the organization.
- `description` (string | null, required) — Free-text description, or null when unset.
- `created_at` (string (date-time), required) — Creation time, ISO-8601 UTC.
- `updated_at` (string (date-time), required) — Last-modified time, ISO-8601 UTC.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/projects/proj_a1b2c3 \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Create a project — GetItDone API

`POST /v1/projects`

Creates a project in the credential's organization. Supports the optional `Idempotency-Key` header for safe retries; a project name that already exists in this organization answers 400 `validation_failed` with a `/name` field error (the uniqueness rule the in-app project creator also enforces) — note that when an Idempotency-Key IS supplied, that 400 is itself stored and replayed byte-identically on retry with the SAME key, exactly like any other outcome (D5).

- **Required scopes:** `projects:write`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** optional `Idempotency-Key` header supported

## Request body

- `name` (string, required) — Display name, 1-200 characters after trimming.
- `description` (string) — Optional free-text description (max 2000 characters).

## Response 201

The created project.

- `id` (string, required) — Stable opaque project id.
- `name` (string, required) — Display name, unique within the organization.
- `description` (string | null, required) — Free-text description, or null when unset.
- `created_at` (string (date-time), required) — Creation time, ISO-8601 UTC.
- `updated_at` (string (date-time), required) — Last-modified time, ISO-8601 UTC.

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/projects \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Website redesign"
  }'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `idempotency_in_progress` (409) — A request with this Idempotency-Key is still in progress: https://nowgetitdone.com/docs/api/problems/idempotency-in-progress
- `idempotency_key_reused` (422) — Idempotency-Key reused with a different request: https://nowgetitdone.com/docs/api/problems/idempotency-key-reused
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

## API keys

# List API keys — GetItDone API

`GET /v1/api-keys`

Cursor-paginated list of the organization's API keys (both generations), metadata only — never hashes or plaintext secrets.

- **Required scopes:** `api-keys:manage`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Query parameters

- `limit` (integer) — Maximum number of items to return (1-100).
- `after` (string) — Opaque cursor from a previous page's `next_cursor` — omit for the first page. Reusing a cursor with DIFFERENT query parameters (e.g. a different `limit`) answers 400 `validation_failed`.

## Response 200

Page of the organization's API keys.

- `data` (object[], required) — The current page of results.
- `has_more` (boolean, required) — True when another page exists after this one.
- `next_cursor` (string | null, required) — Opaque cursor for the next page (pass as `after`); null on the last page.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/api-keys \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Create an API key — GetItDone API

`POST /v1/api-keys`

Mints a new org-owned API key. Beyond the `api-keys:manage` scope check, the CALLING credential's creator must currently hold an owner/admin membership in the organization — a key minted while its creator was an admin stops being able to mint further keys the moment that user is demoted (403 `insufficient_scope`). Supports the optional `Idempotency-Key` header; note the replay caution: a replayed response includes the ORIGINAL plaintext `key` again within the 24h replay window (the same tradeoff Stripe makes for idempotent secret-bearing responses) — treat a stored Idempotency-Key as equally sensitive to the secret itself.

- **Required scopes:** `api-keys:manage`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** optional `Idempotency-Key` header supported

## Request body

- `name` (string, required) — Caller-given label for the key.
- `scopes` ("workspaces:read" | "tasks:read" | "tasks:write" | "members:read" | "projects:read" | "projects:write" | "usage:read" | "api-keys:manage" | "webhooks:read" | "webhooks:write"[]) — Subset of scopes to grant. Defaults to every scope EXCEPT `api-keys:manage` — key-minting is never granted by default and must be requested explicitly.
- `test_mode` (boolean) — Mint a `gid_test_…` sandbox-prefixed key instead of a live one.
- `expires_in_days` (integer) — Expiry in days from now (1-365). Omit for no expiry.

## Response 201

The created key, with its plaintext secret shown once.

- `id` (string, required) — Stable id of the key row.
- `name` (string | null, required) — Caller-given label.
- `key_prefix` (string | null, required) — Non-secret fingerprint prefix shown in key lists (e.g. `gid_ab12`); never the full secret.
- `scopes` ("workspaces:read" | "tasks:read" | "tasks:write" | "members:read" | "projects:read" | "projects:write" | "usage:read" | "api-keys:manage" | "webhooks:read" | "webhooks:write"[], required) — Scopes granted to this key.
- `last_used_at` (string (date-time) | null, required) — Last time this key authenticated a request, or null.
- `expires_at` (string (date-time) | null, required) — Expiry time, or null when the key never expires.
- `created_at` (string (date-time), required) — ISO-8601 UTC.
- `legacy` (boolean, required) — True for a pre-migration user-owned key; false for a current org-owned key. Legacy keys are read-only here — mint new keys as non-legacy.
- `key` (string, required) — The plaintext secret — shown EXACTLY ONCE. Store it now; it cannot be retrieved again.

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/api-keys \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CI deploy bot"
  }'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `idempotency_in_progress` (409) — A request with this Idempotency-Key is still in progress: https://nowgetitdone.com/docs/api/problems/idempotency-in-progress
- `idempotency_key_reused` (422) — Idempotency-Key reused with a different request: https://nowgetitdone.com/docs/api/problems/idempotency-key-reused
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Revoke an API key — GetItDone API

`DELETE /v1/api-keys/{key_id}`

Revokes an API key (either generation) — org-scoped; an id from another organization or an unknown id answers 404 `resource_not_found` (no cross-org existence oracle). A key revoking ITSELF is allowed: the credential is only checked at the top of the request, before the revoke runs. DELETE is naturally idempotent by HTTP semantics — this route does not use the Idempotency-Key ledger.

- **Required scopes:** `api-keys:manage`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `key_id` (string, required)

## Response 200

The key was revoked.

- `id` (string, required) — The id of the revoked key.
- `legacy` (boolean, required) — True when the revoked key was a legacy row (soft-revoked); false for a plugin key (deleted).

## Example request

```bash
curl -X DELETE https://app.nowgetitdone.com/v1/api-keys/id_123 \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

## Tasks

# List tasks — GetItDone API

`GET /v1/tasks`

Cursor-paginated list of the credential organization's tasks (current version of each), most recently updated first. Filters: `status`, `project_id`, `parent_task_id` (subtasks of one task) and `archived` (default false — archived tasks are excluded). Every filter is baked into the cursor: reusing an `after` cursor with different filters answers 400 `validation_failed`.

- **Required scopes:** `tasks:read`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Query parameters

- `limit` (integer) — Maximum number of items to return (1-100).
- `after` (string) — Opaque cursor from a previous page's `next_cursor` — omit for the first page. Reusing a cursor with DIFFERENT query parameters (e.g. a different `limit`) answers 400 `validation_failed`.
- `status` ("TODO" | "IN_PROGRESS" | "IN_REVIEW" | "COMPLETED" | "BLOCKED") — Only tasks whose CURRENT version has this status.
- `project_id` (string) — Only tasks whose CURRENT version is linked to this project.
- `parent_task_id` (string) — Only direct subtasks of this task. An unknown (or other-organization) parent answers 404 `resource_not_found`.
- `archived` ("true" | "false") — true = ONLY archived tasks; false (default) = only active tasks.

## Response 200

Page of tasks.

- `data` (object[], required) — The current page of results.
- `has_more` (boolean, required) — True when another page exists after this one.
- `next_cursor` (string | null, required) — Opaque cursor for the next page (pass as `after`); null on the last page.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/tasks \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Get a task — GetItDone API

`GET /v1/tasks/{task_id}`

Fetches a single task by short id, scoped to the credential's organization. A short id from another organization (or an unknown one) answers 404 `resource_not_found` — no cross-org existence oracle.

- **Required scopes:** `tasks:read`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `task_id` (string, required) — Task short id, e.g. `T-123` (a bare `123` is also accepted on input).

## Response 200

The task.

- `id` (string, required) — The task short id — the ONE public task identifier.
- `title` (string, required)
- `description` (string | null, required) — Free-text description, or null when unset.
- `status` ("TODO" | "IN_PROGRESS" | "IN_REVIEW" | "COMPLETED" | "BLOCKED", required) — Task workflow status.
- `priority` ("LOW" | "MEDIUM" | "HIGH" | "URGENT" | null, required)
- `due_date` (string (date-time) | null, required) — Due date, ISO-8601 UTC, or null.
- `notes` (string | null, required) — Rich-text notes of the current version, or null.
- `story_points` (number | null, required)
- `project_ids` (string[], required) — Ids of the projects the CURRENT version is linked to (a task can belong to several).
- `parent_task_id` (string | null, required) — The parent task's short id when this is a subtask, else null.
- `archived` (boolean, required)
- `created_at` (string (date-time), required) — Task creation time (first version), ISO-8601 UTC.
- `updated_at` (string (date-time), required) — Last content change (current version), ISO-8601 UTC.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/tasks/T-123 \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Create a task — GetItDone API

`POST /v1/tasks`

Creates a task in the credential's organization, owned by the credential's user — the SAME operation the external MCP `create_task` tool executes. `project_id` / `parent_task_id` additionally link the new task org-scoped (unknown ids answer 400 `validation_failed`). Supports the optional `Idempotency-Key` header for exactly-once retries.

- **Required scopes:** `tasks:write`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** optional `Idempotency-Key` header supported

## Request body

- `title` (string, required) — Task title, 1-500 characters after trimming.
- `description` (string)
- `status` ("TODO" | "IN_PROGRESS" | "IN_REVIEW" | "COMPLETED" | "BLOCKED") — Task workflow status.
- `priority` ("LOW" | "MEDIUM" | "HIGH" | "URGENT") — Task priority level.
- `due_date` (string (date)) — Due date as YYYY-MM-DD (interpreted as UTC).
- `notes` (string)
- `story_points` (number)
- `project_id` (string) — Link the new task to this project (must belong to the credential's organization).
- `parent_task_id` (string) — Create as a subtask of this task (short id, must belong to the credential's organization).

## Response 201

The created task.

- `id` (string, required) — The task short id — the ONE public task identifier.
- `title` (string, required)
- `description` (string | null, required) — Free-text description, or null when unset.
- `status` ("TODO" | "IN_PROGRESS" | "IN_REVIEW" | "COMPLETED" | "BLOCKED", required) — Task workflow status.
- `priority` ("LOW" | "MEDIUM" | "HIGH" | "URGENT" | null, required)
- `due_date` (string (date-time) | null, required) — Due date, ISO-8601 UTC, or null.
- `notes` (string | null, required) — Rich-text notes of the current version, or null.
- `story_points` (number | null, required)
- `project_ids` (string[], required) — Ids of the projects the CURRENT version is linked to (a task can belong to several).
- `parent_task_id` (string | null, required) — The parent task's short id when this is a subtask, else null.
- `archived` (boolean, required)
- `created_at` (string (date-time), required) — Task creation time (first version), ISO-8601 UTC.
- `updated_at` (string (date-time), required) — Last content change (current version), ISO-8601 UTC.

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/tasks \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Ship the public API",
    "parent_task_id": "T-123"
  }'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `idempotency_in_progress` (409) — A request with this Idempotency-Key is still in progress: https://nowgetitdone.com/docs/api/problems/idempotency-in-progress
- `idempotency_key_reused` (422) — Idempotency-Key reused with a different request: https://nowgetitdone.com/docs/api/problems/idempotency-key-reused
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Update a task — GetItDone API

`PATCH /v1/tasks/{task_id}`

Partial update — the SAME operation the external MCP `update_task` tool executes: it writes a NEW immutable version carrying every omitted field (and the project links, attachments and collaborators) over from the current one. The change appears as a new entry in the task history.

- **Required scopes:** `tasks:write`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `task_id` (string, required) — Task short id, e.g. `T-123` (a bare `123` is also accepted on input).

## Request body

- `title` (string)
- `status` ("TODO" | "IN_PROGRESS" | "IN_REVIEW" | "COMPLETED" | "BLOCKED") — Task workflow status.
- `priority` ("LOW" | "MEDIUM" | "HIGH" | "URGENT") — Task priority level.
- `due_date` (string (date)) — New due date as YYYY-MM-DD (interpreted as UTC). Cannot be cleared — the shared update operation treats absence as "keep".
- `notes` (string)
- `story_points` (number)

## Response 200

The updated task.

- `id` (string, required) — The task short id — the ONE public task identifier.
- `title` (string, required)
- `description` (string | null, required) — Free-text description, or null when unset.
- `status` ("TODO" | "IN_PROGRESS" | "IN_REVIEW" | "COMPLETED" | "BLOCKED", required) — Task workflow status.
- `priority` ("LOW" | "MEDIUM" | "HIGH" | "URGENT" | null, required)
- `due_date` (string (date-time) | null, required) — Due date, ISO-8601 UTC, or null.
- `notes` (string | null, required) — Rich-text notes of the current version, or null.
- `story_points` (number | null, required)
- `project_ids` (string[], required) — Ids of the projects the CURRENT version is linked to (a task can belong to several).
- `parent_task_id` (string | null, required) — The parent task's short id when this is a subtask, else null.
- `archived` (boolean, required)
- `created_at` (string (date-time), required) — Task creation time (first version), ISO-8601 UTC.
- `updated_at` (string (date-time), required) — Last content change (current version), ISO-8601 UTC.

## Example request

```bash
curl -X PATCH https://app.nowgetitdone.com/v1/tasks/T-123 \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Archive a task — GetItDone API

`POST /v1/tasks/{task_id}/archive`

Archives the task (hides it from active lists; no data is deleted) — the SAME operation the external MCP `archive_task` tool executes. Archiving an already-archived task succeeds unchanged. Supports the optional `Idempotency-Key` header.

- **Required scopes:** `tasks:write`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** optional `Idempotency-Key` header supported

## Path parameters

- `task_id` (string, required) — Task short id, e.g. `T-123` (a bare `123` is also accepted on input).

## Response 200

The archived task.

- `id` (string, required) — The task short id — the ONE public task identifier.
- `title` (string, required)
- `description` (string | null, required) — Free-text description, or null when unset.
- `status` ("TODO" | "IN_PROGRESS" | "IN_REVIEW" | "COMPLETED" | "BLOCKED", required) — Task workflow status.
- `priority` ("LOW" | "MEDIUM" | "HIGH" | "URGENT" | null, required)
- `due_date` (string (date-time) | null, required) — Due date, ISO-8601 UTC, or null.
- `notes` (string | null, required) — Rich-text notes of the current version, or null.
- `story_points` (number | null, required)
- `project_ids` (string[], required) — Ids of the projects the CURRENT version is linked to (a task can belong to several).
- `parent_task_id` (string | null, required) — The parent task's short id when this is a subtask, else null.
- `archived` (boolean, required)
- `created_at` (string (date-time), required) — Task creation time (first version), ISO-8601 UTC.
- `updated_at` (string (date-time), required) — Last content change (current version), ISO-8601 UTC.

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/tasks/T-123/archive \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `idempotency_in_progress` (409) — A request with this Idempotency-Key is still in progress: https://nowgetitdone.com/docs/api/problems/idempotency-in-progress
- `idempotency_key_reused` (422) — Idempotency-Key reused with a different request: https://nowgetitdone.com/docs/api/problems/idempotency-key-reused
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Unarchive a task — GetItDone API

`POST /v1/tasks/{task_id}/unarchive`

Restores an archived task to the active lists — the archive operation with `archive: false`, exactly as the MCP `archive_task` tool exposes it. Supports the optional `Idempotency-Key` header.

- **Required scopes:** `tasks:write`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** optional `Idempotency-Key` header supported

## Path parameters

- `task_id` (string, required) — Task short id, e.g. `T-123` (a bare `123` is also accepted on input).

## Response 200

The unarchived task.

- `id` (string, required) — The task short id — the ONE public task identifier.
- `title` (string, required)
- `description` (string | null, required) — Free-text description, or null when unset.
- `status` ("TODO" | "IN_PROGRESS" | "IN_REVIEW" | "COMPLETED" | "BLOCKED", required) — Task workflow status.
- `priority` ("LOW" | "MEDIUM" | "HIGH" | "URGENT" | null, required)
- `due_date` (string (date-time) | null, required) — Due date, ISO-8601 UTC, or null.
- `notes` (string | null, required) — Rich-text notes of the current version, or null.
- `story_points` (number | null, required)
- `project_ids` (string[], required) — Ids of the projects the CURRENT version is linked to (a task can belong to several).
- `parent_task_id` (string | null, required) — The parent task's short id when this is a subtask, else null.
- `archived` (boolean, required)
- `created_at` (string (date-time), required) — Task creation time (first version), ISO-8601 UTC.
- `updated_at` (string (date-time), required) — Last content change (current version), ISO-8601 UTC.

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/tasks/T-123/unarchive \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `idempotency_in_progress` (409) — A request with this Idempotency-Key is still in progress: https://nowgetitdone.com/docs/api/problems/idempotency-in-progress
- `idempotency_key_reused` (422) — Idempotency-Key reused with a different request: https://nowgetitdone.com/docs/api/problems/idempotency-key-reused
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# List task history — GetItDone API

`GET /v1/tasks/{task_id}/history`

Cursor-paginated, read-only version history of a task, newest first — every content change (in-app, MCP or this API) is an immutable version snapshot. This is the ONE endpoint where versions surface; their ids are accepted nowhere else.

- **Required scopes:** `tasks:read`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `task_id` (string, required) — Task short id, e.g. `T-123` (a bare `123` is also accepted on input).

## Query parameters

- `limit` (integer) — Maximum number of items to return (1-100).
- `after` (string) — Opaque cursor from a previous page's `next_cursor` — omit for the first page. Reusing a cursor with DIFFERENT query parameters (e.g. a different `limit`) answers 400 `validation_failed`.

## Response 200

Page of version snapshots.

- `data` (object[], required) — The current page of results.
- `has_more` (boolean, required) — True when another page exists after this one.
- `next_cursor` (string | null, required) — Opaque cursor for the next page (pass as `after`); null on the last page.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/tasks/T-123/history \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

## Daily plan

# Get the daily board — GetItDone API

`GET /v1/daily-plan`

The credential user's board for a date: both sections (TODO plan + PROGRESS) with their fill-status and entries. Read-only — unlike the in-app board it never creates section rows; a date nobody planned answers empty sections with status NOT_FILLED.

- **Required scopes:** `tasks:read`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Query parameters

- `date` (string (date), required) — Board date as YYYY-MM-DD (UTC day).

## Response 200

The date's board.

- `date` (string (date), required) — The board date (UTC day).
- `sections` (object[], required) — Always both sections: TODO then PROGRESS.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/daily-plan \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Set a section's daily status — GetItDone API

`PATCH /v1/daily-plan`

Sets the fill-status of one section of the credential user's board for a date (creating the section row if the date was never touched — the in-app board creates it on view).

- **Required scopes:** `tasks:write`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Query parameters

- `date` (string (date), required) — Board date as YYYY-MM-DD (UTC day).

## Request body

- `section` ("TODO" | "PROGRESS", required) — Daily-board section: `TODO` = the plan list, `PROGRESS` = the in-progress list.
- `status` ("COMPLETED" | "PLANNED" | "NOT_FILLED" | "FILLING", required) — Fill-state of one daily-board section for one date.

## Response 200

The updated section status.

- `date` (string (date), required)
- `section` ("TODO" | "PROGRESS", required) — Daily-board section: `TODO` = the plan list, `PROGRESS` = the in-progress list.
- `status` ("COMPLETED" | "PLANNED" | "NOT_FILLED" | "FILLING", required) — Fill-state of one daily-board section for one date.

## Example request

```bash
curl -X PATCH https://app.nowgetitdone.com/v1/daily-plan \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "section": "TODO",
    "status": "COMPLETED"
  }'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Plan a task onto the board — GetItDone API

`POST /v1/daily-plan/entries`

Pins a task (current version) onto one section of the credential user's board for a date — mirroring the in-app add: only tasks OWNED by the credential's user and not archived can be planned; a parent task brings its subtasks along; a task already on that section answers 400 `validation_failed`. Supports the optional `Idempotency-Key` header.

- **Required scopes:** `tasks:write`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** optional `Idempotency-Key` header supported

## Request body

- `date` (string (date), required) — Board date as YYYY-MM-DD (UTC day).
- `task_id` (string, required) — Task short id, e.g. `T-123` (a bare `123` is also accepted on input).
- `section` ("TODO" | "PROGRESS", required) — Daily-board section: `TODO` = the plan list, `PROGRESS` = the in-progress list.

## Response 201

The created board entry.

- `id` (string, required) — Board-entry id. NOTE: moving an entry between sections re-creates it (mirroring the in-app move), so the id CHANGES on move.
- `section` ("TODO" | "PROGRESS", required) — Daily-board section: `TODO` = the plan list, `PROGRESS` = the in-progress list.
- `task_id` (string, required) — The planned task's short id.
- `title` (string, required) — The planned task's current title.
- `status` ("TODO" | "IN_PROGRESS" | "IN_REVIEW" | "COMPLETED" | "BLOCKED", required) — Task workflow status.
- `created_at` (string (date-time), required) — When the task was placed on this section, ISO-8601 UTC. Entries within a section are ordered by this (oldest first) — there is no free positional reorder.

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/daily-plan/entries \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "date": "2026-07-24",
    "task_id": "T-123",
    "section": "TODO"
  }'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `idempotency_in_progress` (409) — A request with this Idempotency-Key is still in progress: https://nowgetitdone.com/docs/api/problems/idempotency-in-progress
- `idempotency_key_reused` (422) — Idempotency-Key reused with a different request: https://nowgetitdone.com/docs/api/problems/idempotency-key-reused
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Move an entry between sections — GetItDone API

`PATCH /v1/daily-plan/entries/{entry_id}`

Moves a board entry to the other section of the same date, mirroring the in-app move: subtask entries of a parent move along, a task already present in the target section answers 400 `validation_failed`, and the move RE-CREATES the entry — the returned entry carries a NEW id. Sections are the only movement the board models (no positional reorder exists).

- **Required scopes:** `tasks:write`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `entry_id` (string, required)

## Request body

- `section` ("TODO" | "PROGRESS", required) — Daily-board section: `TODO` = the plan list, `PROGRESS` = the in-progress list.

## Response 200

The entry in its new section (new id).

- `id` (string, required) — Board-entry id. NOTE: moving an entry between sections re-creates it (mirroring the in-app move), so the id CHANGES on move.
- `section` ("TODO" | "PROGRESS", required) — Daily-board section: `TODO` = the plan list, `PROGRESS` = the in-progress list.
- `task_id` (string, required) — The planned task's short id.
- `title` (string, required) — The planned task's current title.
- `status` ("TODO" | "IN_PROGRESS" | "IN_REVIEW" | "COMPLETED" | "BLOCKED", required) — Task workflow status.
- `created_at` (string (date-time), required) — When the task was placed on this section, ISO-8601 UTC. Entries within a section are ordered by this (oldest first) — there is no free positional reorder.

## Example request

```bash
curl -X PATCH https://app.nowgetitdone.com/v1/daily-plan/entries/id_123 \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "section": "TODO"
  }'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Remove an entry from the board — GetItDone API

`DELETE /v1/daily-plan/entries/{entry_id}`

Removes a board entry (the task itself is untouched), mirroring the in-app remove: a parent entry takes its subtasks' entries on the same board with it. An entry from another organization or user answers 404 `resource_not_found`.

- **Required scopes:** `tasks:write`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `entry_id` (string, required)

## Response 200

Removal acknowledgement.

- `id` (string, required)
- `deleted` (boolean, required)

## Example request

```bash
curl -X DELETE https://app.nowgetitdone.com/v1/daily-plan/entries/id_123 \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

## Attachments

# List task attachments — GetItDone API

`GET /v1/tasks/{task_id}/attachments`

Cursor-paginated attachments of the task's CURRENT version, newest first (metadata only — mint download URLs per attachment via the `download-url` endpoint).

- **Required scopes:** `tasks:read`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `task_id` (string, required) — Task short id, e.g. `T-123` (a bare `123` is also accepted on input).

## Query parameters

- `limit` (integer) — Maximum number of items to return (1-100).
- `after` (string) — Opaque cursor from a previous page's `next_cursor` — omit for the first page. Reusing a cursor with DIFFERENT query parameters (e.g. a different `limit`) answers 400 `validation_failed`.

## Response 200

Page of attachments.

- `data` (object[], required) — The current page of results.
- `has_more` (boolean, required) — True when another page exists after this one.
- `next_cursor` (string | null, required) — Opaque cursor for the next page (pass as `after`); null on the last page.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/tasks/T-123/attachments \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Start an attachment upload — GetItDone API

`POST /v1/tasks/{task_id}/attachments/uploads`

Phase 1 of the two-phase upload (the SAME presign flow the in-app uploader uses): declares the file and answers a short-lived presigned PUT URL plus the `file_key` to register afterwards. Checked against the plan's file-size and storage allowances. Nothing is attached until phase 2. Supports the optional `Idempotency-Key` header (a replay returns the SAME URL, which may have expired — start a fresh upload instead of replaying old keys).

- **Required scopes:** `tasks:write`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** optional `Idempotency-Key` header supported

## Path parameters

- `task_id` (string, required) — Task short id, e.g. `T-123` (a bare `123` is also accepted on input).

## Request body

- `file_name` (string, required)
- `content_type` (string, required)
- `size` (integer, required) — File size in bytes — checked against the organization's plan file-size and storage allowances.

## Response 201

Where to PUT the file.

- `upload_url` (string, required) — Presigned URL — PUT the raw file bytes here (Content-Type must match what you declared).
- `upload_method` (string, required)
- `file_key` (string, required) — Opaque storage key; pass it back when registering the attachment after the upload succeeds.
- `expires_at` (string (date-time), required) — When the upload URL stops working, ISO-8601 UTC.

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/tasks/T-123/attachments/uploads \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "file_name": "screenshot.png",
    "content_type": "image/png",
    "size": 1
  }'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `idempotency_in_progress` (409) — A request with this Idempotency-Key is still in progress: https://nowgetitdone.com/docs/api/problems/idempotency-in-progress
- `idempotency_key_reused` (422) — Idempotency-Key reused with a different request: https://nowgetitdone.com/docs/api/problems/idempotency-key-reused
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Register an uploaded attachment — GetItDone API

`POST /v1/tasks/{task_id}/attachments`

Phase 2 of the two-phase upload: attaches the uploaded file (by its `file_key`) to the task's CURRENT version — exactly how the in-app flow registers uploads after the presigned PUT. Supports the optional `Idempotency-Key` header for exactly-once retries.

- **Required scopes:** `tasks:write`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** optional `Idempotency-Key` header supported

## Path parameters

- `task_id` (string, required) — Task short id, e.g. `T-123` (a bare `123` is also accepted on input).

## Request body

- `file_name` (string, required)
- `file_key` (string, required) — The `file_key` returned by the upload endpoint.
- `content_type` (string, required)
- `size` (integer, required) — File size in bytes as uploaded.

## Response 201

The registered attachment.

- `id` (string, required) — Stable opaque attachment id.
- `file_name` (string, required)
- `content_type` (string, required)
- `size` (integer, required) — File size in bytes.
- `created_at` (string (date-time), required)

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/tasks/T-123/attachments \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "file_name": "string",
    "file_key": "string",
    "content_type": "string",
    "size": 1
  }'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `idempotency_in_progress` (409) — A request with this Idempotency-Key is still in progress: https://nowgetitdone.com/docs/api/problems/idempotency-in-progress
- `idempotency_key_reused` (422) — Idempotency-Key reused with a different request: https://nowgetitdone.com/docs/api/problems/idempotency-key-reused
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Mint an attachment download URL — GetItDone API

`GET /v1/attachments/{attachment_id}/download-url`

Answers a short-lived presigned GET URL for the attachment's bytes (the SAME signer the in-app proxy and the MCP `get_task_details` tool use). An attachment from another organization (or an unknown id) answers 404 `resource_not_found`.

- **Required scopes:** `tasks:read`
- **Entitlement:** public_api — available on every plan
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `attachment_id` (string, required)

## Response 200

The presigned download URL.

- `url` (string, required) — Presigned GET URL.
- `expires_at` (string (date-time), required) — When the URL stops working, ISO-8601 UTC.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/attachments/att_a1b2c3/download-url \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

## Webhook endpoints

# List webhook endpoints — GetItDone API

`GET /v1/webhook-endpoints`

Cursor-paginated list of the organization's webhook endpoints. PRO plan and above (`outbound_webhooks`) — a FREE-plan credential gets 403 `feature_not_enabled`. Never includes signing secrets.

- **Required scopes:** `webhooks:read`
- **Entitlement:** outbound_webhooks — Pro and Team plans
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Query parameters

- `limit` (integer) — Maximum number of items to return (1-100).
- `after` (string) — Opaque cursor from a previous page's `next_cursor` — omit for the first page. Reusing a cursor with DIFFERENT query parameters (e.g. a different `limit`) answers 400 `validation_failed`.

## Response 200

Page of the organization's webhook endpoints.

- `data` (object[], required) — The current page of results.
- `has_more` (boolean, required) — True when another page exists after this one.
- `next_cursor` (string | null, required) — Opaque cursor for the next page (pass as `after`); null on the last page.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/webhook-endpoints \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Get a webhook endpoint — GetItDone API

`GET /v1/webhook-endpoints/{endpoint_id}`

Fetches a single webhook endpoint by id, scoped to the credential's organization. An id from another organization (or an unknown id) answers 404 `resource_not_found` — no cross-org existence oracle. Never includes the signing secret.

- **Required scopes:** `webhooks:read`
- **Entitlement:** outbound_webhooks — Pro and Team plans
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `endpoint_id` (string, required)

## Response 200

The webhook endpoint.

- `id` (string, required) — Stable id of the endpoint.
- `url` (string, required) — The https destination URL.
- `enabled` (boolean, required) — False when disabled — manually, or auto-disabled after repeated delivery failures (see `disabled_reason`).
- `event_types` ("task.created" | "task.updated" | "task.archived"[], required) — Subscribed event types. An EMPTY array means "every type".
- `verified` (boolean, required) — True once the `verify` action has proven this endpoint accepts a correctly-signed request.
- `disabled_reason` (string | null, required) — Why the endpoint was auto-disabled, or null when never auto-disabled.
- `created_at` (string (date-time), required) — ISO-8601 UTC.
- `updated_at` (string (date-time), required) — ISO-8601 UTC.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/webhook-endpoints/whep_a1b2c3 \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Create a webhook endpoint — GetItDone API

`POST /v1/webhook-endpoints`

Registers a new webhook endpoint in the credential's organization and mints its signing secret, returned EXACTLY ONCE in this response. The endpoint starts UNVERIFIED (`verified: false`) — call the `verify` action before relying on it; the worker only queues deliveries to enabled AND verified endpoints. The URL is validated at save time (https, port 443, no embedded credentials) — a disallowed URL answers 422 `webhook_url_rejected` and creates NO row. Supports the optional `Idempotency-Key` header; a replayed response includes the ORIGINAL plaintext secret again within the 24h replay window (same tradeoff as `createApiKey`).

- **Required scopes:** `webhooks:write`
- **Entitlement:** outbound_webhooks — Pro and Team plans
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** optional `Idempotency-Key` header supported

## Request body

- `url` (string, required) — The https destination URL. Must be https, port 443 (explicit or default), and carry no `user:pass@` credentials — a URL failing this check answers 422 `webhook_url_rejected` with the specific reason and creates NO row.
- `event_types` ("task.created" | "task.updated" | "task.archived"[]) — Subset of event types to subscribe to. Omit or send an empty array to subscribe to every type.
- `enabled` (boolean) — Defaults to true.

## Response 201

The created endpoint, with its plaintext secret shown once.

- `id` (string, required) — Stable id of the endpoint.
- `url` (string, required) — The https destination URL.
- `enabled` (boolean, required) — False when disabled — manually, or auto-disabled after repeated delivery failures (see `disabled_reason`).
- `event_types` ("task.created" | "task.updated" | "task.archived"[], required) — Subscribed event types. An EMPTY array means "every type".
- `verified` (boolean, required) — True once the `verify` action has proven this endpoint accepts a correctly-signed request.
- `disabled_reason` (string | null, required) — Why the endpoint was auto-disabled, or null when never auto-disabled.
- `created_at` (string (date-time), required) — ISO-8601 UTC.
- `updated_at` (string (date-time), required) — ISO-8601 UTC.
- `secret` (string, required) — The signing secret (`whsec_…`) — shown EXACTLY ONCE. Store it now; it cannot be retrieved again, only rotated. Note: replaying this exact request within the 24h Idempotency-Key window returns this SAME secret again — treat a stored Idempotency-Key as equally sensitive to the secret itself.

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/webhook-endpoints \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/getitdone"
  }'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `idempotency_in_progress` (409) — A request with this Idempotency-Key is still in progress: https://nowgetitdone.com/docs/api/problems/idempotency-in-progress
- `idempotency_key_reused` (422) — Idempotency-Key reused with a different request: https://nowgetitdone.com/docs/api/problems/idempotency-key-reused
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `webhook_url_rejected` (422) — Webhook endpoint URL rejected: https://nowgetitdone.com/docs/api/problems/webhook-url-rejected
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Update a webhook endpoint — GetItDone API

`PATCH /v1/webhook-endpoints/{endpoint_id}`

Partial update of url/event_types/enabled — org-scoped, 404 for a cross-org or unknown id. NEVER rotates the secret (use the `rotate-secret` action). Changing `url` to a different value resets `verified` to false. The (re-validated) URL check can answer 422 `webhook_url_rejected`.

- **Required scopes:** `webhooks:write`
- **Entitlement:** outbound_webhooks — Pro and Team plans
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `endpoint_id` (string, required)

## Request body

- `url` (string) — New destination URL, re-validated the same way as create. Changing the URL to a DIFFERENT value resets `verified` to false — the new destination must be re-verified.
- `event_types` ("task.created" | "task.updated" | "task.archived"[]) — Replaces the full subscribed-type set.
- `enabled` (boolean) — Enable or disable delivery. Re-enabling (false → true) clears any prior auto-disable reason and resets the consecutive-failure counter.

## Response 200

The updated endpoint.

- `id` (string, required) — Stable id of the endpoint.
- `url` (string, required) — The https destination URL.
- `enabled` (boolean, required) — False when disabled — manually, or auto-disabled after repeated delivery failures (see `disabled_reason`).
- `event_types` ("task.created" | "task.updated" | "task.archived"[], required) — Subscribed event types. An EMPTY array means "every type".
- `verified` (boolean, required) — True once the `verify` action has proven this endpoint accepts a correctly-signed request.
- `disabled_reason` (string | null, required) — Why the endpoint was auto-disabled, or null when never auto-disabled.
- `created_at` (string (date-time), required) — ISO-8601 UTC.
- `updated_at` (string (date-time), required) — ISO-8601 UTC.

## Example request

```bash
curl -X PATCH https://app.nowgetitdone.com/v1/webhook-endpoints/whep_a1b2c3 \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `webhook_url_rejected` (422) — Webhook endpoint URL rejected: https://nowgetitdone.com/docs/api/problems/webhook-url-rejected
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Delete a webhook endpoint — GetItDone API

`DELETE /v1/webhook-endpoints/{endpoint_id}`

Permanently (hard) deletes the endpoint — org-scoped, 404 for a cross-org or unknown id — mirroring how `deleteApiKey` hard-deletes a plugin key. The delete CASCADES (schema.prisma `onDelete: Cascade` on WebhookDelivery.endpointId, and from there to WebhookAttempt) to every delivery still queued for this endpoint: pending/in-flight deliveries for this endpoint stop existing rather than being left stuck. DELETE is naturally idempotent by HTTP semantics — this route does not use the Idempotency-Key ledger.

- **Required scopes:** `webhooks:write`
- **Entitlement:** outbound_webhooks — Pro and Team plans
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `endpoint_id` (string, required)

## Response 200

The endpoint was deleted.

- `id` (string, required) — The id of the deleted endpoint.

## Example request

```bash
curl -X DELETE https://app.nowgetitdone.com/v1/webhook-endpoints/whep_a1b2c3 \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Rotate a webhook endpoint secret — GetItDone API

`POST /v1/webhook-endpoints/{endpoint_id}/rotate-secret`

Create-overlap-revoke rotation: mints a NEW signing secret (returned ONCE, same as create) and moves the CURRENT secret to `previous_secret_expires_at`-bounded overlap — the worker signs every delivery with BOTH secrets during that ~24h window so you can finish updating your verifier without dropping deliveries. Rotating a SECOND time before the first rotation's grace window elapses immediately drops the FIRST previous secret (there is only ever one previous-secret slot, not a stack) — do not chain rotations faster than your own verifier can keep up. Never mutates a secret in place; always mints fresh. Supports the optional `Idempotency-Key` header (a replay returns the SAME newly-minted secret again, never rotates twice for one logical request).

- **Required scopes:** `webhooks:write`
- **Entitlement:** outbound_webhooks — Pro and Team plans
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** optional `Idempotency-Key` header supported

## Path parameters

- `endpoint_id` (string, required)

## Response 200

The endpoint with its newly rotated secret.

- `id` (string, required) — Stable id of the endpoint.
- `url` (string, required) — The https destination URL.
- `enabled` (boolean, required) — False when disabled — manually, or auto-disabled after repeated delivery failures (see `disabled_reason`).
- `event_types` ("task.created" | "task.updated" | "task.archived"[], required) — Subscribed event types. An EMPTY array means "every type".
- `verified` (boolean, required) — True once the `verify` action has proven this endpoint accepts a correctly-signed request.
- `disabled_reason` (string | null, required) — Why the endpoint was auto-disabled, or null when never auto-disabled.
- `created_at` (string (date-time), required) — ISO-8601 UTC.
- `updated_at` (string (date-time), required) — ISO-8601 UTC.
- `secret` (string, required) — The NEW signing secret — shown EXACTLY ONCE.
- `previous_secret_expires_at` (string (date-time), required) — The prior secret keeps signing outgoing deliveries alongside the new one until this time (~24h out) — dual-secret acceptance so you can finish updating your verifier before the old secret dies.

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/webhook-endpoints/whep_a1b2c3/rotate-secret \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `idempotency_in_progress` (409) — A request with this Idempotency-Key is still in progress: https://nowgetitdone.com/docs/api/problems/idempotency-in-progress
- `idempotency_key_reused` (422) — Idempotency-Key reused with a different request: https://nowgetitdone.com/docs/api/problems/idempotency-key-reused
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Verify a webhook endpoint — GetItDone API

`POST /v1/webhook-endpoints/{endpoint_id}/verify`

Live, synchronous probe: SSRF-checks the stored URL, then POSTs a signed synthetic test request (Standard Webhooks headers; event type `webhook.verification` — NOT part of the delivery vocabulary, never persisted as a WebhookEvent) and requires a 2xx to mark the endpoint verified. This is a re-runnable probe, not a consequential write — no Idempotency-Key support (`idempotent: false`). A failure reports `verified: false` with a `reason` and does NOT unset a previously-earned verified state.

- **Required scopes:** `webhooks:write`
- **Entitlement:** outbound_webhooks — Pro and Team plans
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `endpoint_id` (string, required)

## Response 200

The verification probe result.

- `verified` (boolean, required) — True when the endpoint answered the signed test request with a 2xx status. On true, the endpoint's verified state is set.
- `status` (integer) — The HTTP status the endpoint returned, when a response was received at all (absent for a blocked/timed-out/network-failed probe).
- `reason` (string) — Present when `verified` is false — why the probe failed.

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/webhook-endpoints/whep_a1b2c3/verify \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Send a test event to a webhook endpoint — GetItDone API

`POST /v1/webhook-endpoints/{endpoint_id}/test-event`

Sends a synchronous, signed sample of a REAL event type (default `task.created`, using a representative sample task payload in the same TaskDto shape real deliveries carry) directly to the endpoint's URL and returns the immediate HTTP outcome. Does NOT create a queued WebhookDelivery row and never appears in the delivery log — it is a live probe, not a domain event. Re-runnable; no Idempotency-Key support.

- **Required scopes:** `webhooks:write`
- **Entitlement:** outbound_webhooks — Pro and Team plans
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `endpoint_id` (string, required)

## Request body

- `event_type` ("task.created" | "task.updated" | "task.archived") — One of the frozen domain event types an endpoint can subscribe to.

## Response 200

The immediate delivery outcome.

- `outcome` ("delivered" | "blocked" | "redirect_blocked" | "request_failed" | "timeout", required) — The immediate outcome of the synchronous test POST.
- `status` (integer) — The HTTP status returned, when a response was received.
- `duration_ms` (integer, required) — Wall-clock time the probe took.

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/webhook-endpoints/whep_a1b2c3/test-event \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# List a webhook endpoint delivery log — GetItDone API

`GET /v1/webhook-endpoints/{endpoint_id}/deliveries`

Cursor-paginated, REDACTED delivery log for one endpoint — org-scoped via the endpoint (404 for a cross-org or unknown endpoint id). Never includes response bodies or the signing secret. Optional `state` filter.

- **Required scopes:** `webhooks:read`
- **Entitlement:** outbound_webhooks — Pro and Team plans
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `endpoint_id` (string, required)

## Query parameters

- `limit` (integer) — Maximum number of items to return (1-100).
- `after` (string) — Opaque cursor from a previous page's `next_cursor` — omit for the first page. Reusing a cursor with DIFFERENT query parameters (e.g. a different `limit`) answers 400 `validation_failed`.
- `state` ("PENDING" | "DELIVERING" | "SUCCEEDED" | "FAILED" | "DISABLED") — Filter to deliveries currently in this state.

## Response 200

Page of the endpoint's delivery log.

- `data` (object[], required) — The current page of results.
- `has_more` (boolean, required) — True when another page exists after this one.
- `next_cursor` (string | null, required) — Opaque cursor for the next page (pass as `after`); null on the last page.

## Example request

```bash
curl -X GET https://app.nowgetitdone.com/v1/webhook-endpoints/whep_a1b2c3/deliveries \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Replay a webhook delivery — GetItDone API

`POST /v1/webhook-endpoints/{endpoint_id}/deliveries/{delivery_id}/replay`

Re-enqueues one delivery, Stripe-style: creates a FRESH PENDING WebhookDelivery row for the SAME event and endpoint (attempt count 0, next attempt now) that the worker picks up on its normal cycle — the original row is never mutated, so the log keeps the full history. Allowed only when the target delivery is in a terminal state (FAILED, SUCCEEDED or DISABLED — replaying a succeeded delivery is a deliberate resend). Answers 409 `delivery_already_pending` when ANY delivery for this event+endpoint pair is already PENDING or DELIVERING (no double-enqueue) — which also makes an accidental double-click naturally safe, so this route does not use the Idempotency-Key ledger. The replayed delivery carries the SAME `webhook-id` signature header as the original (the event id), so consumer-side dedup keeps working. Replaying does NOT re-enable a disabled endpoint — the worker only delivers to enabled endpoints; re-enable via the update route first.

- **Required scopes:** `webhooks:write`
- **Entitlement:** outbound_webhooks — Pro and Team plans
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `endpoint_id` (string, required)
- `delivery_id` (string, required)

## Response 202

The freshly enqueued replay delivery.

- `id` (string, required) — Stable id of the delivery row.
- `event_id` (string, required) — The owning WebhookEvent's id — also the `webhook-id` signature header on the wire.
- `event_type` (string, required) — The domain event type.
- `state` ("PENDING" | "DELIVERING" | "SUCCEEDED" | "FAILED" | "DISABLED", required) — Lifecycle state of one (event, endpoint) delivery.
- `attempt_count` (integer, required) — Number of delivery attempts made so far.
- `last_status` (integer | null, required) — HTTP status of the most recent attempt, or null before any attempt has run.
- `next_attempt_at` (string (date-time) | null, required) — When the next retry is scheduled, or null when not PENDING.
- `created_at` (string (date-time), required) — ISO-8601 UTC.

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/webhook-endpoints/whep_a1b2c3/deliveries/id_123/replay \
  -H "Authorization: Bearer gid_YOUR_API_KEY"
```

## Possible errors

- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `delivery_already_pending` (409) — A delivery for this event is already queued: https://nowgetitdone.com/docs/api/problems/delivery-already-pending
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Replay all recently failed deliveries — GetItDone API

`POST /v1/webhook-endpoints/{endpoint_id}/replay-failed`

Bulk sibling of the single replay: creates FRESH PENDING deliveries for this endpoint's FAILED/DISABLED deliveries created at or after `since`, skipping every event that already has a PENDING/DELIVERING delivery queued for this endpoint (no double-enqueue) — hard-capped at 1000 replays per call (call again with the same `since` for the rest; already-replayed events are skipped by the pending check). Repeating the call is naturally near-idempotent for the same reason, so this route does not use the Idempotency-Key ledger. Does NOT re-enable a disabled endpoint — the “re-enable & replay” console flow is: update `enabled: true` (which resets the failure counter), then call this.

- **Required scopes:** `webhooks:write`
- **Entitlement:** outbound_webhooks — Pro and Team plans
- **Meter cost:** 1 API call against your workspace quota.
- **Idempotency:** not applicable

## Path parameters

- `endpoint_id` (string, required)

## Request body

- `since` (string (date-time), required) — Only FAILED/DISABLED deliveries created at or after this ISO-8601 instant are replayed.

## Response 202

How many deliveries were re-enqueued.

- `replayed_count` (integer, required) — How many FRESH PENDING deliveries this call created (capped at 1000 per call).

## Example request

```bash
curl -X POST https://app.nowgetitdone.com/v1/webhook-endpoints/whep_a1b2c3/replay-failed \
  -H "Authorization: Bearer gid_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "since": "2026-07-24T00:00:00Z"
  }'
```

## Possible errors

- `validation_failed` (400) — Request validation failed: https://nowgetitdone.com/docs/api/problems/validation-failed
- `missing_credentials` (401) — Missing credentials: https://nowgetitdone.com/docs/api/problems/missing-credentials
- `invalid_api_key` (401) — Invalid API key: https://nowgetitdone.com/docs/api/problems/invalid-api-key
- `invalid_token` (401) — Invalid access token: https://nowgetitdone.com/docs/api/problems/invalid-token
- `insufficient_scope` (403) — Insufficient scope: https://nowgetitdone.com/docs/api/problems/insufficient-scope
- `feature_not_enabled` (403) — Feature not enabled on this plan: https://nowgetitdone.com/docs/api/problems/feature-not-enabled
- `resource_not_found` (404) — Resource not found: https://nowgetitdone.com/docs/api/problems/resource-not-found
- `rate_limited` (429) — Rate limit exceeded: https://nowgetitdone.com/docs/api/problems/rate-limited
- `quota_exhausted` (429) — Plan quota exhausted: https://nowgetitdone.com/docs/api/problems/quota-exhausted
- `internal_error` (500) — Internal server error: https://nowgetitdone.com/docs/api/problems/internal-error


---

# Error Codes

# Missing credentials (`missing_credentials`) — GetItDone API

- **HTTP status:** 401
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/missing-credentials

## What it means

The request arrived with no credential at all — no Authorization header and no x-api-key header.

## Likely causes

- The Authorization header was never set on the request.
- A proxy or client library stripped the header before it reached the API.

## How to fix

- Send `Authorization: Bearer gid_…` (or the `x-api-key` header) on every request.
- Mint a key in the app under Profile → API Keys, then store it as a server-side secret.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/missing-credentials",
  "title": "Missing credentials",
  "status": 401,
  "code": "missing_credentials",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Authentication: https://nowgetitdone.com/docs/api#authentication


---

# Invalid API key (`invalid_api_key`) — GetItDone API

- **HTTP status:** 401
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/invalid-api-key

## What it means

A `gid_` API key was supplied but does not match any active credential.

## Likely causes

- The key was revoked, rotated, or belongs to a different environment.
- The key value was truncated or has a stray whitespace/newline.

## How to fix

- Confirm the key is active in Profile → API Keys and copy it again (keys are shown once at creation).
- Check you are using a live key against production and a `gid_test_` key against test data.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/invalid-api-key",
  "title": "Invalid API key",
  "status": 401,
  "code": "invalid_api_key",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Authentication: https://nowgetitdone.com/docs/api#authentication


---

# Invalid access token (`invalid_token`) — GetItDone API

- **HTTP status:** 401
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/invalid-token

## What it means

An OAuth 2.1 access token was supplied but is expired, malformed, or revoked.

## Likely causes

- The access token has passed its expiry.
- The token was issued by a different authorization server or for a different resource.

## How to fix

- Refresh the access token using your refresh token (request the `offline_access` scope to receive one).
- Re-run the OAuth authorization flow if the grant was revoked.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/invalid-token",
  "title": "Invalid access token",
  "status": 401,
  "code": "invalid_token",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Authentication: https://nowgetitdone.com/docs/api#authentication


---

# Insufficient scope (`insufficient_scope`) — GetItDone API

- **HTTP status:** 403
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/insufficient-scope

## What it means

The credential is valid but was not granted a scope this operation requires.

## Likely causes

- The API key was minted without the needed scope (e.g. `tasks:write`).
- An OAuth grant requested read scopes only, then attempted a write.

## How to fix

- Re-mint the API key with the scopes the operation lists under “Required scopes”.
- For OAuth, request the missing scope during authorization.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/insufficient-scope",
  "title": "Insufficient scope",
  "status": 403,
  "code": "insufficient_scope",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Authentication: https://nowgetitdone.com/docs/api#authentication


---

# Feature not enabled on this plan (`feature_not_enabled`) — GetItDone API

- **HTTP status:** 403
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/feature-not-enabled

## What it means

The operation belongs to a capability the current plan does not include — a PLAN gate, distinct from a used-up allowance.

## Likely causes

- Outbound webhooks were called on a Free workspace (they are Pro+).

## How to fix

- Upgrade the workspace to a plan that includes the capability.
- Check the operation’s entitlement note on its reference page.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/feature-not-enabled",
  "title": "Feature not enabled on this plan",
  "status": 403,
  "code": "feature_not_enabled",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Webhooks: https://nowgetitdone.com/docs/api/webhooks
- Rate limits & quotas: https://nowgetitdone.com/docs/api#rate-limits


---

# Request validation failed (`validation_failed`) — GetItDone API

- **HTTP status:** 400
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/validation-failed

## What it means

The request body or query failed schema validation. The `errors` array names each offending field by JSON Pointer.

## Likely causes

- A required field was missing or had the wrong type.
- A value fell outside its allowed range or enum.
- A cursor was reused with different filters than the page it came from.

## How to fix

- Read the `errors` array — each entry has a `pointer`, a `code`, and a `message`.
- Fix the named field and retry. The request was never applied, so retrying is safe.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/validation-failed",
  "title": "Request validation failed",
  "status": 400,
  "code": "validation_failed",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Errors: https://nowgetitdone.com/docs/api#errors


---

# Resource not found (`resource_not_found`) — GetItDone API

- **HTTP status:** 404
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/resource-not-found

## What it means

No resource with that id exists inside the credential’s organization.

## Likely causes

- The id belongs to another organization (there is no cross-org existence oracle — you get 404, not 403).
- The id is mistyped, or the resource was deleted.

## How to fix

- Confirm the id was returned by a list/get call on the SAME credential.
- Use the public short id (e.g. `T-123`) for tasks — internal UUIDs are never accepted.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/resource-not-found",
  "title": "Resource not found",
  "status": 404,
  "code": "resource_not_found",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Errors: https://nowgetitdone.com/docs/api#errors


---

# Rate limit exceeded (`rate_limited`) — GetItDone API

- **HTTP status:** 429
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/rate-limited

## What it means

The per-credential burst window was exceeded. This is a short-term throttle, not your billing-period allowance.

## Likely causes

- Requests arrived faster than the plan’s per-minute burst allowance.

## How to fix

- Back off and retry after the `Retry-After` header’s number of seconds.
- Read the `RateLimit` / `X-RateLimit-*` headers to pace requests before you hit the wall.
- Spread bulk work over time, or upgrade for a higher burst allowance.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/rate-limited",
  "title": "Rate limit exceeded",
  "status": 429,
  "code": "rate_limited",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Rate limits & quotas: https://nowgetitdone.com/docs/api#rate-limits


---

# Plan quota exhausted (`quota_exhausted`) — GetItDone API

- **HTTP status:** 429
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/quota-exhausted

## What it means

The workspace has used its entire API-call allowance for the current billing period — an ALLOWANCE gate, distinct from the short-term burst throttle.

## Likely causes

- The plan’s calls-per-period quota is fully consumed.

## How to fix

- Wait for the billing period to reset, or upgrade to a plan with a larger allowance.
- Reduce call volume — batch reads and cache where you can.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/quota-exhausted",
  "title": "Plan quota exhausted",
  "status": 429,
  "code": "quota_exhausted",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Rate limits & quotas: https://nowgetitdone.com/docs/api#rate-limits


---

# Idempotency-Key header required (`idempotency_key_missing`) — GetItDone API

- **HTTP status:** 400
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/idempotency-key-missing

## What it means

An Idempotency-Key was required for this call but none was supplied or it was malformed.

## Likely causes

- The header was omitted where the client library expected one.
- The header value was empty or longer than 255 characters.

## How to fix

- Send an `Idempotency-Key` header (1–255 visible ASCII characters; a UUID works well).
- Reuse the SAME key when retrying the SAME request to replay the first result.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/idempotency-key-missing",
  "title": "Idempotency-Key header required",
  "status": 400,
  "code": "idempotency_key_missing",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Idempotency: https://nowgetitdone.com/docs/api#idempotency


---

# Idempotency-Key reused with a different request (`idempotency_key_reused`) — GetItDone API

- **HTTP status:** 422
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/idempotency-key-reused

## What it means

An Idempotency-Key was reused with a DIFFERENT request body than the one it first recorded.

## Likely causes

- A key was recycled across two genuinely different requests.
- The request body changed between the first attempt and the retry.

## How to fix

- Generate a fresh key for every distinct request.
- Send the byte-identical body when retrying with the same key.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/idempotency-key-reused",
  "title": "Idempotency-Key reused with a different request",
  "status": 422,
  "code": "idempotency_key_reused",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Idempotency: https://nowgetitdone.com/docs/api#idempotency


---

# A request with this Idempotency-Key is still in progress (`idempotency_in_progress`) — GetItDone API

- **HTTP status:** 409
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/idempotency-in-progress

## What it means

A request with this Idempotency-Key is still executing — the retry raced the original.

## Likely causes

- A retry fired before the first request finished.

## How to fix

- Wait briefly and retry with the same key — the stored result replays once the first call completes.
- Use a short exponential backoff on retries.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/idempotency-in-progress",
  "title": "A request with this Idempotency-Key is still in progress",
  "status": 409,
  "code": "idempotency_in_progress",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Idempotency: https://nowgetitdone.com/docs/api#idempotency


---

# Webhook endpoint URL rejected (`webhook_url_rejected`) — GetItDone API

- **HTTP status:** 422
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/webhook-url-rejected

## What it means

A webhook endpoint URL failed the safety checks: it must be https on port 443 and must not resolve to a private or internal address.

## Likely causes

- The URL used http, a non-443 port, or a private/loopback host.
- The host resolved to a blocked (SSRF-risk) address.

## How to fix

- Use a public https URL on port 443.
- Point the endpoint at an internet-reachable host, not an internal one.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/webhook-url-rejected",
  "title": "Webhook endpoint URL rejected",
  "status": 422,
  "code": "webhook_url_rejected",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Webhooks: https://nowgetitdone.com/docs/api/webhooks


---

# A delivery for this event is already queued (`delivery_already_pending`) — GetItDone API

- **HTTP status:** 409
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/delivery-already-pending

## What it means

A delivery for this webhook event is already queued or in flight, so a replay was not created.

## Likely causes

- A replay was requested for an event whose delivery is still pending.
- A duplicate replay request raced the first.

## How to fix

- Wait for the pending delivery to finish, then check the delivery log before replaying.
- Only replay deliveries that have reached a terminal (failed) state.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/delivery-already-pending",
  "title": "A delivery for this event is already queued",
  "status": 409,
  "code": "delivery_already_pending",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Webhooks: https://nowgetitdone.com/docs/api/webhooks


---

# Internal server error (`internal_error`) — GetItDone API

- **HTTP status:** 500
- **Problem type URI:** https://nowgetitdone.com/docs/api/problems/internal-error

## What it means

Something failed on our side. The response carries a `request_id` for support.

## Likely causes

- An unexpected server-side error.

## How to fix

- Retry after a short delay — transient errors usually clear.
- If it persists, contact support and quote the `request_id` from the response.

## Example problem+json

```json
{
  "type": "https://nowgetitdone.com/docs/api/problems/internal-error",
  "title": "Internal server error",
  "status": 500,
  "code": "internal_error",
  "request_id": "req_a1b2c3d4"
}
```

## Related

- Errors: https://nowgetitdone.com/docs/api#errors


---

# Webhooks — GetItDone API

Outbound webhooks (Pro and Team plans) deliver signed events to your HTTPS endpoint when tasks change.

## Event types

- `task.created`
- `task.updated`
- `task.archived`

## Signature verification

Payloads are signed with the Standard Webhooks scheme. Each request carries `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers. Verify against the RAW request bytes — parsing and re-serializing the body before verification breaks the signature. The `@nowgetitdone/sdk/webhooks` subpath exports `verifyWebhook` (published on npm).

## Retries & auto-disable

Failed deliveries retry with backoff. Endpoints that keep failing are disabled; re-enable them once your receiver is healthy.

## Secret rotation

Rotating a secret keeps the previous one valid for a 24-hour grace window so in-flight deliveries still verify. Accept both secrets during rotation.

## URL rules

Endpoint URLs must be https on port 443 and must not resolve to a private or internal address. A rejected URL answers 422 `webhook_url_rejected`. See https://nowgetitdone.com/docs/api/problems/webhook-url-rejected


---

# Changelog

# @nowgetitdone/sdk 0.1.0 on npm

_2026-07-30 · SDK_

The TypeScript SDK is now published: npm install @nowgetitdone/sdk. The package ships compiled ESM + CJS bundles with type declarations; the open-source mirror on GitHub tracks every release.

The npm scope is @nowgetitdone (npm rejected @getitdone as too similar to an existing package) — the GitHub repo name is unchanged.

## Highlights

- npm install @nowgetitdone/sdk
- ESM + CJS entrypoints with bundled type declarations
- Versioned with Changesets — changelog ships inside the package


---

# TypeScript SDK open-sourced

_2026-07-24 · SDK_

The official GetItDone TypeScript SDK is now developed in the open. It is a thin, typed wrapper over the /v1 REST surface with retries, automatic idempotency keys on consequential POSTs, cursor pagination helpers, and typed problem errors.

The npm release of @nowgetitdone/sdk is rolling out — until it lands, install from the GitHub source. The client-usage snippets in these docs are the real API.

## Highlights

- Source on GitHub, npm release rolling out
- Typed request/response shapes generated from the same contracts the server validates with
- Standard Webhooks signature verification helper for your server


---

# Outbound webhooks (Pro+)

_2026-07-24 · Webhooks, API_

Register HTTPS endpoints and receive signed events when tasks change. Payloads are signed with the Standard Webhooks scheme so you can verify authenticity from the raw request bytes.

Deliveries retry with backoff, secrets rotate with a 24-hour grace window, and you can send a test event while wiring things up. Outbound webhooks are available on Pro and Team plans.

## Highlights

- Event types: task.created, task.updated, task.archived
- Standard Webhooks signing with whsec_ secrets
- Delivery retries + test events + 24h secret-rotation grace


---

# Public API v1 launch

_2026-07-23 · API_

The public GetItDone REST API is live at /v1. Authenticate with a gid_ API key over Bearer auth and manage organizations, projects, tasks, the daily plan, and attachments.

Errors are RFC 9457 problem+json documents with a stable machine-readable code. Lists use cursor pagination, and consequential POSTs accept an Idempotency-Key for safe retries. Every plan can use the API — Free is differentiated by quota, not lockout.

## Highlights

- Versioned /v1 REST surface on gid_ API keys
- Plan-gated quotas + per-credential burst limits
- RFC 9457 problem+json errors, cursor pagination, idempotency


---
