All My Ducks
Join the waitlist

The API.

Nearly everything All My Ducks does, your scripts can do too: the web app runs on this exact API.

REST API: script anything

A versioned REST API with two kinds of keys: personal keys that act as you everywhere, and workspace keys that admins manage, confined to one workspace. OAuth 2.1 is there for apps you build for other people. There are no private endpoints: the web app, the API and the MCP server all use the same routes, the same permissions, the same privacy rules.

Prefer to click around first? Download the Postman collection: every endpoint, generated from the API itself, ready for your key. Working in your own tools? Download the OpenAPI spec: the same routes, fields and examples, as OpenAPI 3.1.

Authentication

Send an API key as a bearer token. A key acts as you: same permissions, same visibility, nothing more. A personal key (from the API and webhooks page in the app) works everywhere you are. A workspace key (made by an admin on the API and webhooks page too, by choosing the workspace as the key’s scope, and every admin there can see and revoke it) works inside that one workspace and gets 403 anywhere else, “This key only works inside its workspace.” That includes the catalogue: GET /templates?workspace= answers a workspace key for its own workspace and for no other.

shell
curl https://allmyducks.app/api/v1/me \
  -H "Authorization: Bearer <your key>" \
  -H "Accept: application/json"

This line is written by hand, to show where a key goes. The examples under the rows below were played against this version of the API.

Building an app for other people? The API also accepts OAuth 2.1 bearer tokens (authorization code + PKCE): endpoints are discoverable at https://allmyducks.app/.well-known/oauth-authorization-server, clients can register dynamically at /oauth/register, and each user approves your app on a consent screen. Tokens act as the user who approved them: same permissions, same visibility. The All My Ducks apps for Android and iOS will sign in the same way, with OAuth 2.1 through the browser, and then use these same routes.

Zapier, Make and n8n

Three connectors are coming soon, each built on this API and this OAuth door: a Zapier app, a Make app and an n8n node. They connect as you, not as a workspace: a connection follows you into every workspace you are in, with your permissions, and each trigger takes an optional workspace, covering all of them when it is left empty. Their triggers are webhook subscriptions, so anything they can see you could have read from the API yourself. The page in the app lists them and says which are published.

  • Zapier: coming soon
  • Make: coming soon
  • n8n: coming soon

Building your own is the same two pieces: an OAuth client for the sign-in, and a webhook subscription for the changes. Both are documented on this page.

Basics

Base URL https://allmyducks.app/api/v1. Requests and responses are JSON; resources come wrapped in data. Dates are YYYY-MM-DD in the promiser’s timezone, and a due_time beside a date is HH:MM on the promiser’s clock, a deadline to the minute; with no time, the deadline is the end of that day. Timestamps are UTC ISO 8601. Errors use standard codes: 401 bad or revoked key, 403 not allowed (or outside a workspace key’s scope), 404 not yours to see, 402 a plan has no room, with the words to show (below), 422 validation with a message and per-field errors. The API is versioned in the path; breaking changes mean a new version, not a changed v1.

Reads that cross workspaces are opt-in: the feed, the calendar and the series list each answer at a path with no workspace in it, where scope=all is required and workspaces= narrows it to a comma-separated list of ids. Every commitment and every series carries a workspace object with its id, name and type, so a merged list can say where each row lives. A workspace key stays confined to its workspace, whatever scope it asks for.

When a plan has no room

Some limits depend on the plan, and a refusal says which. An add, an invite or a connection that a plan has no room for answers 402 with message, the words to show as they come, code, always plan_limit, and limit, which one it was. Nothing is lost by it: what is already there keeps working, and only adding waits. GET /plans lists what each plan holds and costs, with no key.

None of it is counted out to you: no answer says how much of a limit is used. GET /me says beforehand whether an add would go in, and the words when it would not, so an app can say so before anyone tries. A connector’s token on an account without Plus meets integrations on every call but signing out. Paying for a plan is for the web: the checkout, the plan change and the portal are listed below as its routes, and the phones never call them.

limitWhenmessage
open_tasks Adding a todo or something to know for yourself, a series of your own, or bringing one back, when there is no place left. There’s no room for another task of your own just now. Finishing, dropping or deleting one makes room.
steps Adding a step to a task or a series whose plan holds no more. There’s no room for another step here. Remove one to make room.
home_people Inviting someone to a home that has no room for them. There’s no room for anyone else in this home just now.
second_home Making a home, or accepting an invite to one, when you are in a home already. The invite is left standing. You’re already in a home, and for now each person has one.
team_invites Inviting someone to a team that has no plan yet. Invites open once this team has a plan.
team_room Inviting someone to a team whose plan has no room for them. There’s no room for anyone else in this team just now.
year_view Asking the calendar for more than six weeks at a time without Plus. The year view comes with Plus.
calendar_feed Making a calendar subscription link without Plus. Calendar subscription comes with Plus.
integrations Making, changing or testing a webhook without Plus, and any call from a connector on an account without Plus. Connecting other apps comes with Plus.
slack Connecting Slack to a team that has no plan. Slack is connected in the browser, so no API call answers it: GET /me carries these words on the workspace’s slack field beforehand. Slack comes with a team plan.
projects Making a project without Plus, with the words for making one; putting something into a project without Plus answers with the same code and the words for putting it in. Taking something out of a project, renaming and deleting stay open on any plan. New projects aren’t open on your plan just now. Putting things in a project isn’t open on your plan just now.
details Adding or changing the description of a todo, a promise, an ask or a series without Plus. Taking a description away, and reading one, stay open on any plan. Adding or changing a description isn’t open on your plan just now.

Each of those that a call can meet, played against this version of the API as a person without Plus:

open_tasks: POST https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/commitments

json
{
    "kind": "promise",
    "party": {
        "type": "user",
        "id": "0199a000-0000-7000-8000-000000000001"
    },
    "description": "Book the venue"
}

402, and this comes back

json
{
    "message": "There’s no room for another task of your own just now. Finishing, dropping or deleting one makes room.",
    "code": "plan_limit",
    "limit": "open_tasks"
}

steps: POST https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000020/steps

json
{
    "text": "Attach the screenshots"
}

402, and this comes back

json
{
    "message": "There’s no room for another step here. Remove one to make room.",
    "code": "plan_limit",
    "limit": "steps"
}

home_people: POST https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000013/invites

json
{
    "email": "[email protected]"
}

402, and this comes back

json
{
    "message": "There’s no room for anyone else in this home just now.",
    "code": "plan_limit",
    "limit": "home_people"
}

second_home: POST https://allmyducks.app/api/v1/workspaces

json
{
    "name": "Flat",
    "type": "home"
}

402, and this comes back

json
{
    "message": "You’re already in a home, and for now each person has one.",
    "code": "plan_limit",
    "limit": "second_home"
}

team_invites: POST https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/invites

json
{
    "email": "[email protected]"
}

402, and this comes back

json
{
    "message": "Invites open once this team has a plan.",
    "code": "plan_limit",
    "limit": "team_invites"
}

team_room: POST https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/invites

json
{
    "email": "[email protected]"
}

402, and this comes back

json
{
    "message": "There’s no room for anyone else in this team just now.",
    "code": "plan_limit",
    "limit": "team_room"
}

year_view: GET https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/calendar?from=2026-10-01&to=2027-03-31

402, and this comes back

json
{
    "message": "The year view comes with Plus.",
    "code": "plan_limit",
    "limit": "year_view"
}

calendar_feed: POST https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/calendar-feed

402, and this comes back

json
{
    "message": "Calendar subscription comes with Plus.",
    "code": "plan_limit",
    "limit": "calendar_feed"
}

integrations: POST https://allmyducks.app/api/v1/webhooks

json
{
    "url": "https://hooks.example.com/duck",
    "events": [
        "commitment.created",
        "commitment.done"
    ],
    "workspace_id": "0199a000-0000-7000-8000-000000000014"
}

402, and this comes back

json
{
    "message": "Connecting other apps comes with Plus.",
    "code": "plan_limit",
    "limit": "integrations"
}

projects: POST https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/projects

json
{
    "name": "Press kit",
    "description": "Logos, photos and the founders’ bios."
}

402, and this comes back

json
{
    "message": "New projects aren’t open on your plan just now.",
    "code": "plan_limit",
    "limit": "projects"
}

details: POST https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/commitments

json
{
    "kind": "promise",
    "party": {
        "type": "user",
        "id": "0199a000-0000-7000-8000-000000000001"
    },
    "description": "Book the venue",
    "details": "Ask about **step-free** access."
}

402, and this comes back

json
{
    "message": "Adding or changing a description isn’t open on your plan just now.",
    "code": "plan_limit",
    "limit": "details"
}

You and your workspaces

EndpointWhat it does
GET /me Who you are, your workspaces and roles
Request and responseHide request and response

It takes nothing.

A workspace key sees only its own workspace, and its email is the address that workspace knows you by: null once you have left it. On each workspace, capture_enabled is whether the app reads what people say in its Slack channels for suggestions: the workspace’s decision, made by its admins. plan says what you have and how (own, gift, team or trial), the most it holds and what it includes, and can_buy, whether buying is possible on this install: false until billing is set up, and a client that buys leaves its buttons out while it is false; for an own Plus it also says how it is paid (interval) and, once cancelled, its last day (ends_at), and currency is the one prices are shown in; adding says whether a task of your own goes in now, with the words when it does not. On a team workspace, plan is the team’s (with the last day of one that has been cancelled, and, for admins, whether a move down a band fits, and its own can_buy, true when the bands, or its arranged plan’s own Price, can be bought), and invites and slack say beforehand whether inviting and Slack are open there, each with the words when not; invites is for admins. On a home, invites also says whether Plus would give it more room (more_room_with_plus): false once an admin’s plan already gives the most. No field says how much of a limit is used: never how many.

shell
curl -X GET "https://allmyducks.app/api/v1/me" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000001",
        "name": "Alex Rivera",
        "email": "[email protected]",
        "avatar_url": null,
        "timezone": "Europe/London",
        "country": "GB",
        "timezone_country": "GB",
        "joined_on": "2026-10-01",
        "email_verified": true,
        "notify_email": true,
        "notify_slack": true,
        "email_updates": "instant",
        "digest_hour": 8,
        "ai_enabled": true,
        "rewrite": "ask",
        "needs_start": false,
        "two_factor_enabled": false,
        "has_password": true,
        "apple_connected": false,
        "current_workspace_id": "0199a000-0000-7000-8000-000000000014",
        "plan": {
            "name": "plus",
            "through": "team",
            "team_covers": false,
            "trial_ends_at": null,
            "interval": null,
            "ends_at": null,
            "limits": {
                "open_tasks": 500,
                "steps": 100,
                "home_people": 6
            },
            "features": {
                "year_view": true,
                "calendar_feed": true,
                "integrations": true,
                "projects": true,
                "details": true
            },
            "can_buy": false,
            "currency": "gbp",
            "adding": {
                "allowed": true,
                "reason": null
            }
        },
        "workspaces": [
            {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null,
                "role": "admin",
                "email": "[email protected]",
                "member_count": 1,
                "slack_connected": false,
                "slack_linked": false,
                "slack_needs_reconnect": false,
                "ai_enabled": true,
                "capture_enabled": false,
                "plan": null,
                "invites": {
                    "allowed": true,
                    "reason": null,
                    "more_room_with_plus": false
                },
                "slack": {
                    "allowed": false,
                    "reason": null
                }
            },
            {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null,
                "role": "admin",
                "email": "[email protected]",
                "member_count": 3,
                "slack_connected": false,
                "slack_linked": false,
                "slack_needs_reconnect": false,
                "ai_enabled": true,
                "capture_enabled": false,
                "plan": {
                    "active": true,
                    "through": "gift",
                    "seats": 10,
                    "interval": null,
                    "past_due": false,
                    "ends_at": null,
                    "smaller_band_fits": false,
                    "custom_offer": null,
                    "can_buy": false
                },
                "invites": {
                    "allowed": true,
                    "reason": null
                },
                "slack": {
                    "allowed": true,
                    "reason": null
                }
            }
        ]
    }
}
PATCH /me Update name, timezone, country, notification settings, your own AI switch, what the add box does with your wording (rewrite: ask, always, never), current workspace
Request and responseHide request and response
Field Type Needed What it means
name string Optional What people see, up to 255 characters.
timezone string Optional An IANA name, like Europe/London. Your dates end at the end of the day here.
country string Optional Where you live, as a two-letter code (ISO 3166-1) from GET /countries, in any case. It decides which templates and calendars apply.
notify_email boolean Optional Whether messages reach you by email as well as Slack.
notify_slack boolean Optional Whether messages reach you as Slack DMs, where Slack is connected.
email_updates enum Optional How news about promises and asks reaches you. One of instant, digest, off.
digest_hour integer Optional The local hour the morning email is sent, 0 to 23.
ai_enabled boolean Optional Your own AI switch. Off, and nothing is sent to a model for you.
rewrite enum Optional What the add box does with your wording. One of ask, always, never.
current_workspace_id id Optional The workspace you are looking at.

ai_enabled (and, on a workspace, capture_enabled) is accepted only from the app itself, on the web or on the phones; any other credential is refused with 403.

An example request

json
{
    "name": "Alex Rivera",
    "timezone": "Europe/London",
    "digest_hour": 8,
    "rewrite": "ask"
}
shell
curl -X PATCH "https://allmyducks.app/api/v1/me" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Alex Rivera",
    "timezone": "Europe/London",
    "digest_hour": 8,
    "rewrite": "ask"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000001",
        "name": "Alex Rivera",
        "email": "[email protected]",
        "avatar_url": null,
        "timezone": "Europe/London",
        "country": "GB",
        "timezone_country": "GB",
        "joined_on": "2026-10-01",
        "email_verified": true,
        "notify_email": true,
        "notify_slack": true,
        "email_updates": "instant",
        "digest_hour": 8,
        "ai_enabled": true,
        "rewrite": "ask",
        "needs_start": false,
        "two_factor_enabled": false,
        "has_password": true,
        "apple_connected": false,
        "current_workspace_id": "0199a000-0000-7000-8000-000000000014",
        "plan": {
            "name": "plus",
            "through": "team",
            "team_covers": false,
            "trial_ends_at": null,
            "interval": null,
            "ends_at": null,
            "limits": {
                "open_tasks": 500,
                "steps": 100,
                "home_people": 6
            },
            "features": {
                "year_view": true,
                "calendar_feed": true,
                "integrations": true,
                "projects": true,
                "details": true
            },
            "can_buy": false,
            "currency": "gbp",
            "adding": {
                "allowed": true,
                "reason": null
            }
        },
        "workspaces": [
            {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null,
                "role": "admin",
                "email": "[email protected]",
                "member_count": 1,
                "slack_connected": false,
                "slack_linked": false,
                "slack_needs_reconnect": false,
                "ai_enabled": true,
                "capture_enabled": false,
                "plan": null,
                "invites": {
                    "allowed": true,
                    "reason": null,
                    "more_room_with_plus": false
                },
                "slack": {
                    "allowed": false,
                    "reason": null
                }
            },
            {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null,
                "role": "admin",
                "email": "[email protected]",
                "member_count": 3,
                "slack_connected": false,
                "slack_linked": false,
                "slack_needs_reconnect": false,
                "ai_enabled": true,
                "capture_enabled": false,
                "plan": {
                    "active": true,
                    "through": "gift",
                    "seats": 10,
                    "interval": null,
                    "past_due": false,
                    "ends_at": null,
                    "smaller_band_fits": false,
                    "custom_offer": null,
                    "can_buy": false
                },
                "invites": {
                    "allowed": true,
                    "reason": null
                },
                "slack": {
                    "allowed": true,
                    "reason": null
                }
            }
        ]
    }
}
POST /me/avatar Set your photo (an image up to 5 MB, squared and resized here)
Request and responseHide request and response
Field Type Needed What it means
avatar file Yes The picture. It is centre-cropped to a square and resized here, so the name and format on disk are ours. JPEG, PNG or WebP, up to 5 MB.

It answers 10 calls a minute.

shell
curl -X POST "https://allmyducks.app/api/v1/me/avatar" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -F '[email protected]'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000001",
        "name": "Alex Rivera",
        "email": "[email protected]",
        "avatar_url": "https://allmyducks.app/storage/avatars/example.webp",
        "timezone": "Europe/London",
        "country": "GB",
        "timezone_country": "GB",
        "joined_on": "2026-10-01",
        "email_verified": true,
        "notify_email": true,
        "notify_slack": true,
        "email_updates": "instant",
        "digest_hour": 8,
        "ai_enabled": true,
        "rewrite": "ask",
        "needs_start": false,
        "two_factor_enabled": false,
        "has_password": true,
        "apple_connected": false,
        "current_workspace_id": "0199a000-0000-7000-8000-000000000014",
        "plan": {
            "name": "plus",
            "through": "team",
            "team_covers": false,
            "trial_ends_at": null,
            "interval": null,
            "ends_at": null,
            "limits": {
                "open_tasks": 500,
                "steps": 100,
                "home_people": 6
            },
            "features": {
                "year_view": true,
                "calendar_feed": true,
                "integrations": true,
                "projects": true,
                "details": true
            },
            "can_buy": false,
            "currency": "gbp",
            "adding": {
                "allowed": true,
                "reason": null
            }
        },
        "workspaces": [
            {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null,
                "role": "admin",
                "email": "[email protected]",
                "member_count": 1,
                "slack_connected": false,
                "slack_linked": false,
                "slack_needs_reconnect": false,
                "ai_enabled": true,
                "capture_enabled": false,
                "plan": null,
                "invites": {
                    "allowed": true,
                    "reason": null,
                    "more_room_with_plus": false
                },
                "slack": {
                    "allowed": false,
                    "reason": null
                }
            },
            {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null,
                "role": "admin",
                "email": "[email protected]",
                "member_count": 3,
                "slack_connected": false,
                "slack_linked": false,
                "slack_needs_reconnect": false,
                "ai_enabled": true,
                "capture_enabled": false,
                "plan": {
                    "active": true,
                    "through": "gift",
                    "seats": 10,
                    "interval": null,
                    "past_due": false,
                    "ends_at": null,
                    "smaller_band_fits": false,
                    "custom_offer": null,
                    "can_buy": false
                },
                "invites": {
                    "allowed": true,
                    "reason": null
                },
                "slack": {
                    "allowed": true,
                    "reason": null
                }
            }
        ]
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "Choose a photo to upload.",
    "errors": {
        "avatar": [
            "Choose a photo to upload."
        ]
    }
}
DELETE /me/avatar Remove your photo and go back to initials
Request and responseHide request and response

It takes nothing.

It answers 10 calls a minute.

shell
curl -X DELETE "https://allmyducks.app/api/v1/me/avatar" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000001",
        "name": "Alex Rivera",
        "email": "[email protected]",
        "avatar_url": null,
        "timezone": "Europe/London",
        "country": "GB",
        "timezone_country": "GB",
        "joined_on": "2026-10-01",
        "email_verified": true,
        "notify_email": true,
        "notify_slack": true,
        "email_updates": "instant",
        "digest_hour": 8,
        "ai_enabled": true,
        "rewrite": "ask",
        "needs_start": false,
        "two_factor_enabled": false,
        "has_password": true,
        "apple_connected": false,
        "current_workspace_id": "0199a000-0000-7000-8000-000000000014",
        "plan": {
            "name": "plus",
            "through": "team",
            "team_covers": false,
            "trial_ends_at": null,
            "interval": null,
            "ends_at": null,
            "limits": {
                "open_tasks": 500,
                "steps": 100,
                "home_people": 6
            },
            "features": {
                "year_view": true,
                "calendar_feed": true,
                "integrations": true,
                "projects": true,
                "details": true
            },
            "can_buy": false,
            "currency": "gbp",
            "adding": {
                "allowed": true,
                "reason": null
            }
        },
        "workspaces": [
            {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null,
                "role": "admin",
                "email": "[email protected]",
                "member_count": 1,
                "slack_connected": false,
                "slack_linked": false,
                "slack_needs_reconnect": false,
                "ai_enabled": true,
                "capture_enabled": false,
                "plan": null,
                "invites": {
                    "allowed": true,
                    "reason": null,
                    "more_room_with_plus": false
                },
                "slack": {
                    "allowed": false,
                    "reason": null
                }
            },
            {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null,
                "role": "admin",
                "email": "[email protected]",
                "member_count": 3,
                "slack_connected": false,
                "slack_linked": false,
                "slack_needs_reconnect": false,
                "ai_enabled": true,
                "capture_enabled": false,
                "plan": {
                    "active": true,
                    "through": "gift",
                    "seats": 10,
                    "interval": null,
                    "past_due": false,
                    "ends_at": null,
                    "smaller_band_fits": false,
                    "custom_offer": null,
                    "can_buy": false
                },
                "invites": {
                    "allowed": true,
                    "reason": null
                },
                "slack": {
                    "allowed": true,
                    "reason": null
                }
            }
        ]
    }
}
POST /me/export Take a copy of your data (account password required)
Request and responseHide request and response
Field Type Needed What it means
password string Yes Your account password, because this one matters.

It answers 5 calls a minute.

An example request

json
{
    "password": "your account password"
}
shell
curl -X POST "https://allmyducks.app/api/v1/me/export" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "password": "your account password"
}'

200, and this comes back

json
{
    "exported_at": "2026-10-01T09:00:00+00:00",
    "profile": {
        "name": "Alex Rivera",
        "email": "[email protected]",
        "emails": [
            {
                "email": "[email protected]",
                "primary": true,
                "verified": true,
                "added_on": "2026-10-01"
            },
            {
                "email": "[email protected]",
                "primary": false,
                "verified": true,
                "added_on": "2026-10-01"
            },
            {
                "email": "[email protected]",
                "primary": false,
                "verified": false,
                "added_on": "2026-10-01"
            }
        ],
        "avatar_url": null,
        "timezone": "Europe/London",
        "notify_email": true,
        "notify_slack": true,
        "email_updates": "instant",
        "digest_hour": 8,
        "ai_enabled": true,
        "rewrite": "ask"
    },
    "workspaces": [
        {
            "name": "Home",
            "role": "admin",
            "type": "home",
            "email": "[email protected]",
            "capture_enabled": false,
            "projects": []
        },
        {
            "name": "Acme",
            "role": "admin",
            "type": "team",
            "email": "[email protected]",
            "capture_enabled": false,
            "projects": [
                {
                    "name": "Launch",
                    "description": "Everything for the launch in October."
                }
            ]
        }
    ],
    "teams": [
        {
            "name": "Launch crew"
        }
    ],
    "commitments": [
        {
            "id": "0199a000-0000-7000-8000-000000000020",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": {
                "id": "0199a000-0000-7000-8000-000000000058",
                "name": "Launch",
                "tag": "launch"
            },
            "description": "Send the launch copy",
            "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
            "details_changed": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-15",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [
                {
                    "id": "0199a000-0000-7000-8000-000000000053",
                    "text": "Draft the hero line",
                    "done": true
                },
                {
                    "id": "0199a000-0000-7000-8000-000000000054",
                    "text": "Check it with Priya",
                    "done": false
                },
                {
                    "id": "0199a000-0000-7000-8000-000000000055",
                    "text": "Send it to design",
                    "done": false
                }
            ],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "details_changed",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                },
                {
                    "type": "noted",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000003",
                        "name": "Sam Okafor"
                    },
                    "message": "Whenever suits, no rush.",
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                },
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000022",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Book the launch review",
            "details": null,
            "details_changed": null,
            "state": "done",
            "source": "manual",
            "due_date": "2026-09-29",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "closed",
                "group": null
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "done",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                },
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000025",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Draft the launch FAQ",
            "details": null,
            "details_changed": null,
            "state": "released",
            "source": "manual",
            "due_date": "2026-09-24",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "closed",
                "group": null
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "released",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000003",
                        "name": "Sam Okafor"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                },
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000028",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Send the launch metrics",
            "details": null,
            "details_changed": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-13",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": true,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "placement": {
                "list": "waiting_on_others",
                "group": "needs_your_answer"
            },
            "viewer": {
                "is_promiser": false,
                "is_promisee": true,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "release_requested",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000003",
                        "name": "Sam Okafor"
                    },
                    "message": "The launch took my week. Can this go?",
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                },
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000003",
                        "name": "Sam Okafor"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000031",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Send the launch slides",
            "details": null,
            "details_changed": null,
            "state": "requested",
            "source": "manual",
            "due_date": "2026-10-14",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": "2026-10-08T09:00:00+00:00",
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "needs_your_attention"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "requested",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000003",
                        "name": "Sam Okafor"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000033",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Send the launch numbers",
            "details": null,
            "details_changed": null,
            "state": "requested",
            "source": "manual",
            "due_date": "2026-10-17",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": "2026-10-08T09:00:00+00:00",
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "placement": {
                "list": "waiting_on_others",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": false,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "requested",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000035",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Tidy the launch folder",
            "details": null,
            "details_changed": null,
            "state": "active",
            "source": "manual",
            "due_date": null,
            "end_date": null,
            "due_timezone": null,
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "no_date_yet"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000038",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Renew example.com",
            "details": null,
            "details_changed": null,
            "state": "active",
            "source": "schedule",
            "due_date": "2026-10-20",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "workspace",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "module_trouble": "Can't reach the registry at the moment.",
            "schedule": {
                "id": "0199a000-0000-7000-8000-000000000037",
                "template": "domain",
                "icon": "globe",
                "rule_words": "Every year on 20 October",
                "next_due_date": "2026-10-20",
                "next_label": null,
                "following": {
                    "date": "2027-10-20",
                    "label": null
                },
                "occurrence_no": 1,
                "ended": false
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000040",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null
            },
            "project": null,
            "description": "Water the plants",
            "details": null,
            "details_changed": null,
            "state": "released",
            "source": "schedule",
            "due_date": "2026-10-03",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "closed",
                "group": null
            },
            "schedule": {
                "id": "0199a000-0000-7000-8000-000000000039",
                "template": "custom",
                "icon": "repeat",
                "rule_words": "Every week on Saturday",
                "next_due_date": "2026-10-03",
                "next_label": null,
                "following": null,
                "occurrence_no": 1,
                "ended": true
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "released",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                },
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000041",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Order the launch stickers",
            "details": null,
            "details_changed": null,
            "state": "active",
            "source": "manual",
            "due_date": null,
            "end_date": null,
            "due_timezone": null,
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "no_date_yet"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000048",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null
            },
            "project": null,
            "description": "Bins: Recycling",
            "details": null,
            "details_changed": null,
            "state": "active",
            "source": "schedule",
            "due_date": "2026-10-06",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "schedule": {
                "id": "0199a000-0000-7000-8000-000000000047",
                "template": "bins",
                "icon": "bin",
                "rule_words": "Every week on Tuesday",
                "next_due_date": "2026-10-06",
                "next_label": "Recycling",
                "following": {
                    "date": "2026-10-13",
                    "label": "General waste"
                },
                "occurrence_no": 1,
                "ended": false
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000049",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Call the printers about the proofs",
            "details": null,
            "details_changed": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-08",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": "15:00",
            "due_at": "2026-10-08T14:00:00+00:00",
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000050",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Sam is on holiday",
            "details": null,
            "details_changed": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-12",
            "end_date": "2026-10-18",
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "workspace",
            "seen_by": [],
            "fyi": true,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "shared",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000051",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Book the team lunch",
            "details": null,
            "details_changed": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-23",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "chosen",
            "seen_by": [
                {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000005",
                    "name": "Jo Marsh"
                },
                {
                    "type": "team",
                    "id": "0199a000-0000-7000-8000-000000000015",
                    "name": "Launch crew"
                }
            ],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-10-01T09:00:00+00:00"
                }
            ],
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000052",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Renew the parking permit",
            "details": null,
            "details_changed": null,
            "state": "done",
            "source": "manual",
            "due_date": "2026-09-10",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 21,
            "placement": {
                "list": "closed",
                "group": null
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "events": [
                {
                    "type": "done",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-09-10T09:00:00+00:00"
                },
                {
                    "type": "created",
                    "actor": {
                        "id": "0199a000-0000-7000-8000-000000000001",
                        "name": "Alex Rivera"
                    },
                    "message": null,
                    "reason": null,
                    "team": null,
                    "from": null,
                    "to": null,
                    "source": null,
                    "from_workspace": null,
                    "to_workspace": null,
                    "created_at": "2026-09-10T09:00:00+00:00"
                }
            ],
            "created_at": "2026-09-10T09:00:00+00:00"
        }
    ]
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The password field is required.",
    "errors": {
        "password": [
            "The password field is required."
        ]
    }
}
DELETE /me Delete your account (your password, or for an account with no password a code from POST /me/deletion-code)
Request and responseHide request and response
Field Type Needed What it means
password string Optional Your account password, because this one matters. Needed when the account has one (has_password on GET /me).
code string Optional For an account with no password: the 6-digit code POST /me/deletion-code emailed to your primary address.

It answers 5 calls a minute.

An example request

json
{
    "password": "your account password"
}
shell
curl -X DELETE "https://allmyducks.app/api/v1/me" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "password": "your account password"
}'

204, and no body.

POST /me/deletion-code Email a 6-digit code to delete an account that has no password; it lasts fifteen minutes, and a new one replaces the last
Request and responseHide request and response

It takes nothing.

It answers 3 calls every 10 minutes.

shell
curl -X POST "https://allmyducks.app/api/v1/me/deletion-code" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

202, and this comes back

json
{
    "message": "A code is on its way."
}
GET /me/emails Any of your addresses signs you in: this lists them, primary first
Request and responseHide request and response

It takes nothing.

In the app only. A key gets 403 here.

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000002",
            "email": "[email protected]",
            "primary": true,
            "verified": true,
            "added_on": "2026-10-01"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000009",
            "email": "[email protected]",
            "primary": false,
            "verified": true,
            "added_on": "2026-10-01"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000010",
            "email": "[email protected]",
            "primary": false,
            "verified": false,
            "added_on": "2026-10-01"
        }
    ]
}
POST /me/emails Add an address and send a 6-digit code to it (account password required)
Request and responseHide request and response
Field Type Needed What it means
email string Yes The address to add and send a code to.
password string Yes Your account password, because this one matters.

It answers 5 calls every 60 minutes.

An example request

json
{
    "email": "[email protected]",
    "password": "your account password"
}

In the app only. A key gets 403 here.

201, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000900002",
        "email": "[email protected]",
        "primary": false,
        "verified": false,
        "added_on": "2026-10-01"
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The email field is required.",
    "errors": {
        "email": [
            "The email field is required."
        ]
    }
}
POST /me/emails/{id}/verify Type the code to prove the address
Request and responseHide request and response
Field Type Needed What it means
id in the path id Yes The email’s id.
code string Yes The 6-digit code sent to the address.

It answers 10 calls a minute.

An example request

json
{
    "code": "123456"
}

In the app only. A key gets 403 here.

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000009",
        "email": "[email protected]",
        "primary": false,
        "verified": true,
        "added_on": "2026-10-01"
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The code field is required.",
    "errors": {
        "code": [
            "The code field is required."
        ]
    }
}
POST /me/emails/{id}/verify/send Send a fresh code
Request and responseHide request and response
Field Type Needed What it means
id in the path id Yes The email’s id.

It answers 3 calls every 10 minutes.

In the app only. A key gets 403 here.

202, and this comes back

json
{
    "message": "A new code is on its way."
}
POST /me/emails/{id}/make-primary Make another proved address your primary: account email goes there, and workspaces you make from now on start on it
Request and responseHide request and response
Field Type Needed What it means
id in the path id Yes The email’s id.

It answers 10 calls a minute.

In the app only. A key gets 403 here.

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000009",
            "email": "[email protected]",
            "primary": true,
            "verified": true,
            "added_on": "2026-10-01"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000002",
            "email": "[email protected]",
            "primary": false,
            "verified": true,
            "added_on": "2026-10-01"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000010",
            "email": "[email protected]",
            "primary": false,
            "verified": false,
            "added_on": "2026-10-01"
        }
    ]
}
DELETE /me/emails/{id} Remove an address: a workspace that used it moves to your primary
Request and responseHide request and response
Field Type Needed What it means
id in the path id Yes The email’s id.

It answers 10 calls a minute.

In the app only. A key gets 403 here.

204, and no body.

PUT /me/workspaces/{workspace}/email Choose which of your verified addresses this workspace emails and shows to its members
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace’s id.
email string Yes One of your verified addresses.

It answers 10 calls a minute.

An example request

json
{
    "email": "[email protected]"
}

In the app only. A key gets 403 here.

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null,
        "role": "admin",
        "email": "[email protected]",
        "slack_connected": false,
        "ai_enabled": true,
        "capture_enabled": false
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The email field is required.",
    "errors": {
        "email": [
            "The email field is required."
        ]
    }
}
POST /me/email/verify Prove the address you signed up with: the 6-digit code from the email
Request and responseHide request and response
Field Type Needed What it means
code string Yes The 6-digit code sent to the address.

It answers 10 calls a minute.

An example request

json
{
    "code": "123456"
}
shell
curl -X POST "https://allmyducks.app/api/v1/me/email/verify" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "123456"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000001",
        "name": "Alex Rivera",
        "email": "[email protected]",
        "avatar_url": null,
        "timezone": "Europe/London",
        "country": "GB",
        "timezone_country": "GB",
        "joined_on": "2026-10-01",
        "email_verified": true,
        "notify_email": true,
        "notify_slack": true,
        "email_updates": "instant",
        "digest_hour": 8,
        "ai_enabled": true,
        "rewrite": "ask",
        "needs_start": false,
        "two_factor_enabled": false,
        "has_password": true,
        "apple_connected": false,
        "current_workspace_id": "0199a000-0000-7000-8000-000000000014",
        "plan": {
            "name": "plus",
            "through": "team",
            "team_covers": false,
            "trial_ends_at": null,
            "interval": null,
            "ends_at": null,
            "limits": {
                "open_tasks": 500,
                "steps": 100,
                "home_people": 6
            },
            "features": {
                "year_view": true,
                "calendar_feed": true,
                "integrations": true,
                "projects": true,
                "details": true
            },
            "can_buy": false,
            "currency": "gbp",
            "adding": {
                "allowed": true,
                "reason": null
            }
        },
        "workspaces": [
            {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null,
                "role": "admin",
                "email": "[email protected]",
                "member_count": 1,
                "slack_connected": false,
                "slack_linked": false,
                "slack_needs_reconnect": false,
                "ai_enabled": true,
                "capture_enabled": false,
                "plan": null,
                "invites": {
                    "allowed": true,
                    "reason": null,
                    "more_room_with_plus": false
                },
                "slack": {
                    "allowed": false,
                    "reason": null
                }
            },
            {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null,
                "role": "admin",
                "email": "[email protected]",
                "member_count": 3,
                "slack_connected": false,
                "slack_linked": false,
                "slack_needs_reconnect": false,
                "ai_enabled": true,
                "capture_enabled": false,
                "plan": {
                    "active": true,
                    "through": "gift",
                    "seats": 10,
                    "interval": null,
                    "past_due": false,
                    "ends_at": null,
                    "smaller_band_fits": false,
                    "custom_offer": null,
                    "can_buy": false
                },
                "invites": {
                    "allowed": true,
                    "reason": null
                },
                "slack": {
                    "allowed": true,
                    "reason": null
                }
            }
        ]
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The code field is required.",
    "errors": {
        "code": [
            "The code field is required."
        ]
    }
}
POST /me/email/verify/send Send that code again
Request and responseHide request and response

It takes nothing.

It answers 3 calls every 10 minutes.

shell
curl -X POST "https://allmyducks.app/api/v1/me/email/verify/send" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

202, and this comes back

json
{
    "message": "A new code is on its way."
}
POST /me/start Answer the first-run question: whether this account starts at home or at work
Request and responseHide request and response
Field Type Needed What it means
choice enum Yes Which kind of workspace this account starts with. One of just_me, home, team.
name string Optional The team’s name, needed only when choice is team.

It answers 10 calls a minute.

An example request

json
{
    "choice": "team",
    "name": "Acme"
}
shell
curl -X POST "https://allmyducks.app/api/v1/me/start" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "choice": "team",
    "name": "Acme"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000001",
        "name": "Alex Rivera",
        "email": "[email protected]",
        "avatar_url": null,
        "timezone": "Europe/London",
        "country": "GB",
        "timezone_country": "GB",
        "joined_on": "2026-10-01",
        "email_verified": true,
        "notify_email": true,
        "notify_slack": true,
        "email_updates": "instant",
        "digest_hour": 8,
        "ai_enabled": true,
        "rewrite": "ask",
        "needs_start": false,
        "two_factor_enabled": false,
        "has_password": true,
        "apple_connected": false,
        "current_workspace_id": "0199a000-0000-7000-8000-000000000014",
        "plan": {
            "name": "plus",
            "through": "team",
            "team_covers": false,
            "trial_ends_at": null,
            "interval": null,
            "ends_at": null,
            "limits": {
                "open_tasks": 500,
                "steps": 100,
                "home_people": 6
            },
            "features": {
                "year_view": true,
                "calendar_feed": true,
                "integrations": true,
                "projects": true,
                "details": true
            },
            "can_buy": false,
            "currency": "gbp",
            "adding": {
                "allowed": true,
                "reason": null
            }
        },
        "workspaces": [
            {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null,
                "role": "admin",
                "email": "[email protected]",
                "member_count": 1,
                "slack_connected": false,
                "slack_linked": false,
                "slack_needs_reconnect": false,
                "ai_enabled": true,
                "capture_enabled": false,
                "plan": null,
                "invites": {
                    "allowed": true,
                    "reason": null,
                    "more_room_with_plus": false
                },
                "slack": {
                    "allowed": false,
                    "reason": null
                }
            },
            {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null,
                "role": "admin",
                "email": "[email protected]",
                "member_count": 3,
                "slack_connected": false,
                "slack_linked": false,
                "slack_needs_reconnect": false,
                "ai_enabled": true,
                "capture_enabled": false,
                "plan": {
                    "active": true,
                    "through": "gift",
                    "seats": 10,
                    "interval": null,
                    "past_due": false,
                    "ends_at": null,
                    "smaller_band_fits": false,
                    "custom_offer": null,
                    "can_buy": false
                },
                "invites": {
                    "allowed": true,
                    "reason": null
                },
                "slack": {
                    "allowed": true,
                    "reason": null
                }
            }
        ]
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The choice field is required.",
    "errors": {
        "choice": [
            "The choice field is required."
        ]
    }
}
GET /me/trusted-devices The browsers that skip your two-factor code, most recently used first
Request and responseHide request and response

It takes nothing.

In the app only. A key gets 403 here.

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000011",
            "name": "Chrome on macOS",
            "current": false,
            "last_used_at": "2026-10-01T09:00:00.000000Z",
            "expires_at": "2026-10-31T09:00:00.000000Z"
        }
    ]
}
DELETE /me/trusted-devices Forget every one of them: each asks for a code next time
Request and responseHide request and response

It takes nothing.

It answers 10 calls a minute.

In the app only. A key gets 403 here.

204, and no body.

DELETE /me/trusted-devices/{id} Forget one of them
Request and responseHide request and response
Field Type Needed What it means
id in the path id Yes The device’s id.

It answers 10 calls a minute.

In the app only. A key gets 403 here.

204, and no body.

POST /me/devices Register a phone so notices can reach it
Request and responseHide request and response
Field Type Needed What it means
platform enum Yes Which kind of phone it is. One of android, ios.
token string Yes The push token the phone was given. Posting the same one again keeps one registration rather than making a second.
name string Yes What you’d recognise the phone by.

It answers 20 calls a minute.

An example request

json
{
    "platform": "android",
    "token": "docs-push-token-for-the-example-phone-000000000000000",
    "name": "Pixel 8"
}
shell
curl -X POST "https://allmyducks.app/api/v1/me/devices" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "android",
    "token": "docs-push-token-for-the-example-phone-000000000000000",
    "name": "Pixel 8"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000012",
        "platform": "android",
        "name": "Pixel 8",
        "last_seen_at": "2026-10-01T09:00:00+00:00"
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The platform field is required. (and 2 more errors)",
    "errors": {
        "platform": [
            "The platform field is required."
        ],
        "token": [
            "The token field is required."
        ],
        "name": [
            "The name field is required."
        ]
    }
}
DELETE /me/devices/{device} Stop sending notices to a phone
Request and responseHide request and response
Field Type Needed What it means
device in the path id Yes The phone’s id.

It answers 20 calls a minute.

shell
curl -X DELETE "https://allmyducks.app/api/v1/me/devices/0199a000-0000-7000-8000-000000000012" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

204, and no body.

DELETE /me/token Sign out: the app’s own token, and the refresh token behind it, stop working, and only the app whose token it is can call it
Request and responseHide request and response

It takes nothing.

It answers 20 calls a minute.

GET /workspaces Your workspaces
Request and responseHide request and response

It takes nothing.

shell
curl -X GET "https://allmyducks.app/api/v1/workspaces" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000013",
            "name": "Home",
            "type": "home",
            "colour": null,
            "role": "admin",
            "email": "[email protected]",
            "slack_connected": false,
            "ai_enabled": true,
            "capture_enabled": false
        },
        {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null,
            "role": "admin",
            "email": "[email protected]",
            "slack_connected": false,
            "ai_enabled": true,
            "capture_enabled": false
        }
    ]
}
POST /workspaces Create a workspace
Request and responseHide request and response
Field Type Needed What it means
name string Yes What people will call it, up to 255 characters.
type enum Optional Home or team; leaving it out makes a team. One of home, team.

A person is in one home at a time, made or joined; a second is refused, 402, with limit second_home.

An example request

json
{
    "name": "Acme marketing",
    "type": "team"
}
shell
curl -X POST "https://allmyducks.app/api/v1/workspaces" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme marketing",
    "type": "team"
}'

201, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000900002",
        "name": "Acme marketing",
        "type": "team",
        "colour": null,
        "role": "admin",
        "email": "[email protected]",
        "slack_connected": false,
        "ai_enabled": true,
        "capture_enabled": false
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The name field is required.",
    "errors": {
        "name": [
            "The name field is required."
        ]
    }
}
PATCH /workspaces/{workspace} Rename it, turn the workspace AI (ai_enabled) and Slack suggestions (capture_enabled) switches on and off, or change its colour to sky, emerald, lime, violet, fuchsia or stone, or to null for the one chosen for it (admin, not the personal workspace)
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to update.
name string Optional What people will call it, up to 255 characters. The personal workspace keeps its own.
ai_enabled boolean Optional The workspace AI switch, alongside anyone’s own.
capture_enabled boolean Optional Whether the app reads what people say in this workspace's Slack channels for suggestions. Off until its admins turn it on.
colour enum Optional The mark it wears, or null for the one chosen for it. One of sky, emerald, lime, violet, fuchsia, stone.

ai_enabled (and, on a workspace, capture_enabled) is accepted only from the app itself, on the web or on the phones; any other credential is refused with 403. A member who is not an admin is refused, 403, with “Only a workspace admin can change it.” Somebody outside the workspace is answered 404.

An example request

json
{
    "name": "Acme",
    "colour": "emerald"
}
shell
curl -X PATCH "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme",
    "colour": "emerald"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": "emerald",
        "role": "admin",
        "email": "[email protected]",
        "slack_connected": false,
        "ai_enabled": true,
        "capture_enabled": false
    }
}
GET /workspaces/{workspace}/calendar-feed Whether your ICS feed link exists
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to check.

served is whether the link is answered: a link is kept while its owner is without Plus, but its address answers 404, as any address that was never made does, until Plus is back.

shell
curl -X GET "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/calendar-feed" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "active": false,
        "served": true
    }
}
POST /workspaces/{workspace}/calendar-feed Make (or rotate) your secret ICS feed link
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to make a link for. The url the response answers with is the secret: keep it to yourself, and mint a fresh one if it is ever shared.

Making a link comes with Plus; without it the call is refused, 402, with limit calendar_feed. Turning one off always works.

shell
curl -X POST "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/calendar-feed" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

201, and this comes back

json
{
    "data": {
        "url": "https://allmyducks.app/feeds/calendar/f6af2ee68354281bbc8c634e23980cbde284a8565dedcf1065ebc47f23c1042b.ics"
    }
}
DELETE /workspaces/{workspace}/calendar-feed Turn your ICS feed off
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to turn it off for.
shell
curl -X DELETE "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/calendar-feed" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

204, and no body.

GET /workspaces/{workspace}/members Members and roles
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to list.
shell
curl -X GET "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/members" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera",
            "email": "[email protected]",
            "avatar_url": null,
            "role": "admin"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000005",
            "name": "Jo Marsh",
            "email": "[email protected]",
            "avatar_url": null,
            "role": "admin"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000003",
            "name": "Sam Okafor",
            "email": "[email protected]",
            "avatar_url": null,
            "role": "member"
        }
    ]
}
PATCH /workspaces/{workspace}/members/{user} Change a role (admin)
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace the member belongs to.
user in the path id Yes The member to change.
role enum Yes The role to give them. One of admin, member.

A member who is not an admin is refused, 403, with “Only a workspace admin can change roles.” Somebody outside the workspace is answered 404.

An example request

json
{
    "role": "admin"
}
shell
curl -X PATCH "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/members/0199a000-0000-7000-8000-000000000003" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "admin"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000003",
        "name": "Sam Okafor",
        "email": "[email protected]",
        "avatar_url": null,
        "role": "admin"
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The role field is required.",
    "errors": {
        "role": [
            "The role field is required."
        ]
    }
}
DELETE /workspaces/{workspace}/members/{user} Remove a member (admin) or leave
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to remove them from.
user in the path id Yes The member to remove; the signed-in person may remove themselves.

Leaving is anyone’s own to do. A member who is not an admin, removing someone else, is refused, 403, with “Only a workspace admin can remove people.” Somebody outside the workspace is answered 404.

shell
curl -X DELETE "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/members/0199a000-0000-7000-8000-000000000005" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

204, and no body.

GET /workspaces/{workspace}/teams Teams
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to list.
shell
curl -X GET "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/teams" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000015",
            "name": "Launch crew",
            "members": [
                {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "role": "owner"
                },
                {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "role": "member"
                }
            ]
        }
    ]
}
POST /workspaces/{workspace}/teams Create a team
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace the team belongs to: a team workspace. A personal workspace or a home refuses one with a 422.
name string Yes What people will call it, up to 255 characters. It must be unique in the workspace.

An example request

json
{
    "name": "Support"
}
shell
curl -X POST "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/teams" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Support"
}'

201, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000900002",
        "name": "Support",
        "members": [
            {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "role": "owner"
            }
        ]
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The name field is required.",
    "errors": {
        "name": [
            "The name field is required."
        ]
    }
}
PATCH /teams/{team} Rename a team (an admin or one of its owners)
Request and responseHide request and response
Field Type Needed What it means
team in the path id Yes The team to rename.
name string Yes What people will call it, up to 255 characters. It must be unique in the workspace.

A member who is neither one of its owners nor a workspace admin is refused, 403, with “Only a team owner or a workspace admin can rename it.” Somebody outside the workspace is answered 404.

An example request

json
{
    "name": "Launch team"
}
shell
curl -X PATCH "https://allmyducks.app/api/v1/teams/0199a000-0000-7000-8000-000000000015" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Launch team"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000015",
        "name": "Launch team",
        "members": [
            {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "role": "owner"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "role": "member"
            }
        ]
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The name field is required.",
    "errors": {
        "name": [
            "The name field is required."
        ]
    }
}
DELETE /teams/{team} Remove a team: open asks to it end, promises taken on stay with the person
Request and responseHide request and response
Field Type Needed What it means
team in the path id Yes The team to remove.

A member who is neither one of its owners nor a workspace admin is refused, 403, with “Only a team owner or a workspace admin can remove it.” Somebody outside the workspace is answered 404.

shell
curl -X DELETE "https://allmyducks.app/api/v1/teams/0199a000-0000-7000-8000-000000000015" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

204, and no body.

POST /teams/{team}/members Put a workspace member on a team (one of its owners or a workspace admin)
Request and responseHide request and response
Field Type Needed What it means
team in the path id Yes The team to add them to.
email string Yes The address of an existing workspace member. They join as a plain member; make them an owner afterwards with PATCH.

A member who is neither one of its owners nor a workspace admin is refused, 403, with “Only a team owner or a workspace admin can add people to it.” Somebody outside the workspace is answered 404.

An example request

json
{
    "email": "[email protected]"
}
shell
curl -X POST "https://allmyducks.app/api/v1/teams/0199a000-0000-7000-8000-000000000015/members" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]"
}'

201, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000005",
        "name": "Jo Marsh",
        "email": "[email protected]",
        "avatar_url": null,
        "role": "member"
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The email field is required.",
    "errors": {
        "email": [
            "The email field is required."
        ]
    }
}
PATCH /teams/{team}/members/{user} Make someone one of a team’s owners, or a member again (one of its owners or a workspace admin)
Request and responseHide request and response
Field Type Needed What it means
team in the path id Yes The team the person belongs to.
user in the path id Yes The person to change.
role enum Yes Owner or member. A team always keeps at least one owner. One of owner, member.

A member who is neither one of its owners nor a workspace admin is refused, 403, with “Only a team owner or a workspace admin can change roles on it.” Somebody outside the workspace is answered 404.

An example request

json
{
    "role": "owner"
}
shell
curl -X PATCH "https://allmyducks.app/api/v1/teams/0199a000-0000-7000-8000-000000000015/members/0199a000-0000-7000-8000-000000000003" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "owner"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000003",
        "name": "Sam Okafor",
        "email": "[email protected]",
        "avatar_url": null,
        "role": "owner"
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The role field is required.",
    "errors": {
        "role": [
            "The role field is required."
        ]
    }
}
DELETE /teams/{team}/members/{user} Take someone off a team (one of its owners or a workspace admin): a team is never left without an owner
Request and responseHide request and response
Field Type Needed What it means
team in the path id Yes The team to remove them from.
user in the path id Yes The person to remove; the signed-in person may remove themselves.

Stepping off is anyone’s own to do. A member who is neither one of its owners nor a workspace admin, taking someone else off, is refused, 403, with “Only a team owner or a workspace admin can take someone else off it.” Somebody outside the workspace is answered 404.

shell
curl -X DELETE "https://allmyducks.app/api/v1/teams/0199a000-0000-7000-8000-000000000015/members/0199a000-0000-7000-8000-000000000003" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

204, and no body.

GET /workspaces/{workspace}/invites Invites sent here and not yet accepted, with when each one runs out (admin)
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to list.

A member who is not an admin is refused, 403, with “Only a workspace admin can do that.” Somebody outside the workspace is answered 404.

shell
curl -X GET "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/invites" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000043",
            "email": "[email protected]",
            "role": "member",
            "accepted": false,
            "expires_at": "2026-10-15T09:00:00+00:00",
            "created_at": "2026-10-01T09:00:00+00:00"
        }
    ]
}
POST /workspaces/{workspace}/invites Invite by email (admin)
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to invite them into.
email string Yes The address to send the invite to.

A home has room for as many people as its admins’ plans give, counting invites still out. Past that the invite is refused, 402, with limit home_people. The workspace’s invites field in GET /me says so beforehand. A member who is not an admin is refused, 403, with “Only a workspace admin can invite people.” Somebody outside the workspace is answered 404.

An example request

json
{
    "email": "[email protected]"
}
shell
curl -X POST "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/invites" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]"
}'

201, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000900002",
        "email": "[email protected]",
        "role": null,
        "accepted": false,
        "expires_at": "2026-10-08T09:00:00+00:00",
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The email field is required.",
    "errors": {
        "email": [
            "The email field is required."
        ]
    }
}
DELETE /workspaces/{workspace}/invites/{invite} Take an invite back before it is accepted (admin)
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace the invite belongs to.
invite in the path id Yes The invite to take back.

A member who is not an admin is refused, 403, with “Only a workspace admin can do that.” Somebody outside the workspace is answered 404.

shell
curl -X DELETE "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/invites/0199a000-0000-7000-8000-000000000043" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

204, and no body.

POST /workspaces/{workspace}/billing/checkout A Stripe link to start paying for this workspace (admin)
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace being paid for: your personal workspace for Plus, or a team.
interval enum Yes Monthly or yearly. One of month, year.
seats integer Optional A team’s band, the most people its plan has room for: 10 or 25. Not asked of Plus, nor of a team with an arranged plan, which is sold at its own price.

A home has no plan of its own: 422. A workspace already paying: 409. This route is for the web: the phones never call it.

In the app only. A key gets 403 here.

This response is written by hand: the link is made through Stripe’s own SDK, so the generator that plays every other example has nothing to record.

200, and this comes back

json
{
    "data": {
        "url": "https://checkout.stripe.com/c/pay/cs_test_a1B2c3D4e5F6g7H8i9J0"
    }
}
PATCH /workspaces/{workspace}/billing Change a plan’s interval, or a team’s band (admin)
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace whose plan this changes: your personal workspace for Plus, or a team.
interval enum Optional Monthly or yearly. Left out, it stays as it is. One of month, year.
seats integer Optional A team’s band: 10 or 25. Left out, it stays as it is.

What comes back, under data

Field Type What it means
active boolean Whether the team has a plan now.
through string How: paid, gift, or custom for an arranged plan.
seats integer The most people the plan has room for, counting invites still out.
interval string month or year; null for a gift or an arranged plan.
past_due boolean Whether Stripe is retrying a payment.
ends_at string The last day of a plan that has been cancelled and still runs; null otherwise.
smaller_band_fits boolean Whether the band below fits everyone here and every invite still out, so a move down can be offered; false for a member, a gift, an arranged plan and the smallest band.
custom_offer object An arranged plan ready to buy, with its seats; null otherwise.
can_buy boolean Whether buying is possible for this team on this install: false until billing is set up; an arranged plan counts by its own Price. A client leaves its buy buttons out while it is false.

The change is made at once and prorated onto the next invoice. Moving down a band waits, 422, while more people and invites are here than it has room for. An arranged plan changes by getting in touch, 422. With no plan, or one that won’t renew, 409. When the payment for a change needs one more step, 402, with no limit: the change is made and billing finishes it. A personal workspace answers your plan, as GET /me shows it. This route is for the web: the phones never call it.

An example request

json
{
    "interval": "month",
    "seats": 10
}

In the app only. A key gets 403 here.

200, and this comes back

json
{
    "data": {
        "active": true,
        "through": "paid",
        "seats": 10,
        "interval": "month",
        "past_due": false,
        "ends_at": null,
        "smaller_band_fits": false,
        "custom_offer": null,
        "can_buy": false
    }
}
POST /workspaces/{workspace}/billing/portal A Stripe link to the card, the invoices and cancelling (admin)
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace whose billing this manages.

This route is for the web: the phones never call it.

In the app only. A key gets 403 here.

This response is written by hand: the link is made through Stripe’s own SDK, so the generator that plays every other example has nothing to record.

200, and this comes back

json
{
    "data": {
        "url": "https://billing.stripe.com/p/session/test_YWNjdF8xMjM0NTY3ODkw"
    }
}

Every example on this page is a real call, played against this version of the API, apart from four that say so where they sit: the two Stripe links, and two curl lines written by hand.

email_updates on /me is instant, digest or off, and digest_hour is 0 to 23, the local hour the morning email is sent. They cover news about promises and asks only: an ask for you, a request to drop something, a date that has passed, a promise that needs a new plan and a heads-up that something might slip are always sent.

Commitment endpoints

EndpointWhat it does
GET /workspaces/{workspace}/commitments Everything written down that involves you
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to list.
closed in the query enum Optional Which closed rows to include: a recent window, or every one there has ever been. One of recent, all.
project in the query id Optional A project in this workspace: only what is in it. One from anywhere else is refused with 422, and GET /commitments takes none.
shell
curl -X GET "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/commitments?closed=recent" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000049",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Call the printers about the proofs",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-08",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": "15:00",
            "due_at": "2026-10-08T14:00:00+00:00",
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000050",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Sam is on holiday",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-12",
            "end_date": "2026-10-18",
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "workspace",
            "seen_by": [],
            "fyi": true,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "shared",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000028",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Send the launch metrics",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-13",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": true,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "placement": {
                "list": "waiting_on_others",
                "group": "needs_your_answer"
            },
            "viewer": {
                "is_promiser": false,
                "is_promisee": true,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000031",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Send the launch slides",
            "details": null,
            "state": "requested",
            "source": "manual",
            "due_date": "2026-10-14",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": "2026-10-08T09:00:00+00:00",
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "needs_your_attention"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000020",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": {
                "id": "0199a000-0000-7000-8000-000000000058",
                "name": "Launch",
                "tag": "launch"
            },
            "description": "Send the launch copy",
            "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-15",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [
                {
                    "id": "0199a000-0000-7000-8000-000000000053",
                    "text": "Draft the hero line",
                    "done": true
                },
                {
                    "id": "0199a000-0000-7000-8000-000000000054",
                    "text": "Check it with Priya",
                    "done": false
                },
                {
                    "id": "0199a000-0000-7000-8000-000000000055",
                    "text": "Send it to design",
                    "done": false
                }
            ],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000033",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Send the launch numbers",
            "details": null,
            "state": "requested",
            "source": "manual",
            "due_date": "2026-10-17",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": "2026-10-08T09:00:00+00:00",
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "placement": {
                "list": "waiting_on_others",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": false,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000038",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Renew example.com",
            "details": null,
            "state": "active",
            "source": "schedule",
            "due_date": "2026-10-20",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "workspace",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "module_trouble": "Can't reach the registry at the moment.",
            "schedule": {
                "id": "0199a000-0000-7000-8000-000000000037",
                "template": "domain",
                "icon": "globe",
                "rule_words": "Every year on 20 October",
                "next_due_date": "2026-10-20",
                "next_label": null,
                "following": {
                    "date": "2027-10-20",
                    "label": null
                },
                "occurrence_no": 1,
                "ended": false
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000051",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Book the team lunch",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-23",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "chosen",
            "seen_by": [
                {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000005",
                    "name": "Jo Marsh"
                },
                {
                    "type": "team",
                    "id": "0199a000-0000-7000-8000-000000000015",
                    "name": "Launch crew"
                }
            ],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000041",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Order the launch stickers",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": null,
            "end_date": null,
            "due_timezone": null,
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "no_date_yet"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000035",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Tidy the launch folder",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": null,
            "end_date": null,
            "due_timezone": null,
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "no_date_yet"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000025",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Draft the launch FAQ",
            "details": null,
            "state": "released",
            "source": "manual",
            "due_date": "2026-09-24",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "closed",
                "group": null
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000022",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Book the launch review",
            "details": null,
            "state": "done",
            "source": "manual",
            "due_date": "2026-09-29",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "closed",
                "group": null
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        }
    ],
    "links": {
        "first": "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/commitments?closed=recent&page=1",
        "last": "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/commitments?closed=recent&page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "page": null,
                "active": false
            },
            {
                "url": "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/commitments?closed=recent&page=1",
                "label": "1",
                "page": 1,
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "page": null,
                "active": false
            }
        ],
        "path": "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/commitments",
        "per_page": 100,
        "to": 12,
        "total": 12,
        "older_closed": true
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

GET /commitments The same feed across every workspace you are in: add workspaces={ids} to narrow it
Request and responseHide request and response
Field Type Needed What it means
scope in the query enum Yes Ask for the union on purpose, rather than by leaving a workspace out. One of all.
workspaces in the query string Optional A comma-separated list of workspace ids to narrow the union to, or leave it out for every one you are in.
closed in the query enum Optional Which closed rows to include: a recent window, or every one there has ever been. One of recent, all.
shell
curl -X GET "https://allmyducks.app/api/v1/commitments?scope=all" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000048",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null
            },
            "project": null,
            "description": "Bins: Recycling",
            "details": null,
            "state": "active",
            "source": "schedule",
            "due_date": "2026-10-06",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "schedule": {
                "id": "0199a000-0000-7000-8000-000000000047",
                "template": "bins",
                "icon": "bin",
                "rule_words": "Every week on Tuesday",
                "next_due_date": "2026-10-06",
                "next_label": "Recycling",
                "following": {
                    "date": "2026-10-13",
                    "label": "General waste"
                },
                "occurrence_no": 1,
                "ended": false
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000049",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Call the printers about the proofs",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-08",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": "15:00",
            "due_at": "2026-10-08T14:00:00+00:00",
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000050",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Sam is on holiday",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-12",
            "end_date": "2026-10-18",
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "workspace",
            "seen_by": [],
            "fyi": true,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "shared",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000028",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Send the launch metrics",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-13",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": true,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "placement": {
                "list": "waiting_on_others",
                "group": "needs_your_answer"
            },
            "viewer": {
                "is_promiser": false,
                "is_promisee": true,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000031",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Send the launch slides",
            "details": null,
            "state": "requested",
            "source": "manual",
            "due_date": "2026-10-14",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": "2026-10-08T09:00:00+00:00",
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "needs_your_attention"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000020",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": {
                "id": "0199a000-0000-7000-8000-000000000058",
                "name": "Launch",
                "tag": "launch"
            },
            "description": "Send the launch copy",
            "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-15",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [
                {
                    "id": "0199a000-0000-7000-8000-000000000053",
                    "text": "Draft the hero line",
                    "done": true
                },
                {
                    "id": "0199a000-0000-7000-8000-000000000054",
                    "text": "Check it with Priya",
                    "done": false
                },
                {
                    "id": "0199a000-0000-7000-8000-000000000055",
                    "text": "Send it to design",
                    "done": false
                }
            ],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000033",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Send the launch numbers",
            "details": null,
            "state": "requested",
            "source": "manual",
            "due_date": "2026-10-17",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": "2026-10-08T09:00:00+00:00",
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "placement": {
                "list": "waiting_on_others",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": false,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000038",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Renew example.com",
            "details": null,
            "state": "active",
            "source": "schedule",
            "due_date": "2026-10-20",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "workspace",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "module_trouble": "Can't reach the registry at the moment.",
            "schedule": {
                "id": "0199a000-0000-7000-8000-000000000037",
                "template": "domain",
                "icon": "globe",
                "rule_words": "Every year on 20 October",
                "next_due_date": "2026-10-20",
                "next_label": null,
                "following": {
                    "date": "2027-10-20",
                    "label": null
                },
                "occurrence_no": 1,
                "ended": false
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000051",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Book the team lunch",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-23",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "chosen",
            "seen_by": [
                {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000005",
                    "name": "Jo Marsh"
                },
                {
                    "type": "team",
                    "id": "0199a000-0000-7000-8000-000000000015",
                    "name": "Launch crew"
                }
            ],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000041",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Order the launch stickers",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": null,
            "end_date": null,
            "due_timezone": null,
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "no_date_yet"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000035",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Tidy the launch folder",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": null,
            "end_date": null,
            "due_timezone": null,
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "no_date_yet"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000040",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null
            },
            "project": null,
            "description": "Water the plants",
            "details": null,
            "state": "released",
            "source": "schedule",
            "due_date": "2026-10-03",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "closed",
                "group": null
            },
            "schedule": {
                "id": "0199a000-0000-7000-8000-000000000039",
                "template": "custom",
                "icon": "repeat",
                "rule_words": "Every week on Saturday",
                "next_due_date": "2026-10-03",
                "next_label": null,
                "following": null,
                "occurrence_no": 1,
                "ended": true
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000025",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Draft the launch FAQ",
            "details": null,
            "state": "released",
            "source": "manual",
            "due_date": "2026-09-24",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "closed",
                "group": null
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000022",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Book the launch review",
            "details": null,
            "state": "done",
            "source": "manual",
            "due_date": "2026-09-29",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "closed",
                "group": null
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        }
    ],
    "links": {
        "first": "https://allmyducks.app/api/v1/commitments?scope=all&page=1",
        "last": "https://allmyducks.app/api/v1/commitments?scope=all&page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "page": null,
                "active": false
            },
            {
                "url": "https://allmyducks.app/api/v1/commitments?scope=all&page=1",
                "label": "1",
                "page": 1,
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "page": null,
                "active": false
            }
        ],
        "path": "https://allmyducks.app/api/v1/commitments",
        "per_page": 100,
        "to": 14,
        "total": 14,
        "older_closed": true
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

GET /search Find one by its words, across every workspace you are in
Request and responseHide request and response
Field Type Needed What it means
q in the query string Yes The words to look for. Leading and trailing whitespace is trimmed and does not count, so at least two letters must be left.
state in the query enum Optional Which ones to search: open, closed, or all of them. One of open, closed, all.
workspace in the query id Optional One workspace to search, or leave it out to search every one you are in.
per_page in the query integer Optional How many rows to answer with at a time. The ceiling is 100.

It answers 60 calls a minute.

A workspace key searches its own workspace and no further: naming another workspace is refused, 403, with “This key only works inside its workspace.”

shell
curl -X GET "https://allmyducks.app/api/v1/search?q=launch&state=open" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000028",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Send the launch metrics",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-13",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": true,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "placement": {
                "list": "waiting_on_others",
                "group": "needs_your_answer"
            },
            "viewer": {
                "is_promiser": false,
                "is_promisee": true,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000031",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Send the launch slides",
            "details": null,
            "state": "requested",
            "source": "manual",
            "due_date": "2026-10-14",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": "2026-10-08T09:00:00+00:00",
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "needs_your_attention"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": false,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000020",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": {
                "id": "0199a000-0000-7000-8000-000000000058",
                "name": "Launch",
                "tag": "launch"
            },
            "description": "Send the launch copy",
            "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
            "state": "active",
            "source": "manual",
            "due_date": "2026-10-15",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [
                {
                    "id": "0199a000-0000-7000-8000-000000000053",
                    "text": "Draft the hero line",
                    "done": true
                },
                {
                    "id": "0199a000-0000-7000-8000-000000000054",
                    "text": "Check it with Priya",
                    "done": false
                },
                {
                    "id": "0199a000-0000-7000-8000-000000000055",
                    "text": "Send it to design",
                    "done": false
                }
            ],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": false,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000033",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Send the launch numbers",
            "details": null,
            "state": "requested",
            "source": "manual",
            "due_date": "2026-10-17",
            "end_date": null,
            "due_timezone": "Europe/London",
            "due_time": null,
            "due_at": null,
            "is_private": false,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": "2026-10-08T09:00:00+00:00",
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "placement": {
                "list": "waiting_on_others",
                "group": "coming_up"
            },
            "viewer": {
                "is_promiser": false,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000041",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Order the launch stickers",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": null,
            "end_date": null,
            "due_timezone": null,
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "no_date_yet"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000035",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "description": "Tidy the launch folder",
            "details": null,
            "state": "active",
            "source": "manual",
            "due_date": null,
            "end_date": null,
            "due_timezone": null,
            "due_time": null,
            "due_at": null,
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "release_requested": false,
            "request_expires_at": null,
            "is_slipped": false,
            "in_grace_window": false,
            "grace_closed": false,
            "at_risk": false,
            "dormant": false,
            "quiet_days": 0,
            "placement": {
                "list": "yours_to_do",
                "group": "no_date_yet"
            },
            "viewer": {
                "is_promiser": true,
                "is_promisee": true,
                "can_reword": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "promiser": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "email": "[email protected]",
                    "avatar_url": null,
                    "active": true
                },
                "asked_team": null
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        }
    ],
    "links": {
        "first": "https://allmyducks.app/api/v1/search?q=launch&state=open&page=1",
        "last": "https://allmyducks.app/api/v1/search?q=launch&state=open&page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "page": null,
                "active": false
            },
            {
                "url": "https://allmyducks.app/api/v1/search?q=launch&state=open&page=1",
                "label": "1",
                "page": 1,
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "page": null,
                "active": false
            }
        ],
        "path": "https://allmyducks.app/api/v1/search",
        "per_page": 25,
        "to": 6,
        "total": 6
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

POST /workspaces/{workspace}/commitments Make a promise or ask for one; a task for yourself takes visibility and fyi
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace it belongs to.
kind enum Yes Whether this is a promise you make or an ask you send. One of promise, request.
party.type enum Yes Whether the other party is a person or a team. One of user, team.
party.id id Yes The person or team it is for.
description string Yes What it is, up to 10,000 characters.
due_date date Optional The date it is due, or leave it out for none.
due_time string Optional HH:MM, 24-hour, on the promiser’s clock. Needs due_date.
visibility enum Optional Who can see a task for yourself: kept to you (owner), shared with the workspace (workspace), or shown to the people and teams in seen_by (chosen). Refused once there are two parties. One of owner, workspace, chosen.
seen_by array Optional With visibility chosen, who can see it: a list of {"type": "user" or "team", "id": the person’s or team’s id}, each one in this workspace, at least one besides you. You are left off, since you always see your own. Refused with any other visibility.
fyi boolean Optional Something to know: a task for yourself with nothing to tick off, on a day. Needs party to be you and a due_date of today or later in your time zone. Visibility works as for any task.
end_date date Optional The last day of something to know that lasts several days, like a holiday: due_date is the first. Only with fyi, at most a year after due_date, and with no due_time. The same day as due_date, null or left out is one day. It can have started already, as long as the last day is today or later in your time zone.
project_id id Optional A project in this workspace to put it in, or leave it out for none. Putting something in a project comes with Plus; without it nothing is made and the call is refused, 402, with limit projects.
details string Optional What it involves, in Markdown: bold, italic, a heading, lists and links, up to 10,000 characters as stored. Writing one comes with Plus; without it nothing is made and the call is refused, 402, with limit details.

An example request

json
{
    "kind": "promise",
    "party": {
        "type": "user",
        "id": "0199a000-0000-7000-8000-000000000003"
    },
    "description": "Send the pricing page copy",
    "due_date": "2026-10-09"
}
shell
curl -X POST "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/commitments" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "promise",
    "party": {
        "type": "user",
        "id": "0199a000-0000-7000-8000-000000000003"
    },
    "description": "Send the pricing page copy",
    "due_date": "2026-10-09"
}'

201, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000900002",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Send the pricing page copy",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-09",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The kind field is required. (and 3 more errors)",
    "errors": {
        "kind": [
            "The kind field is required."
        ],
        "party.type": [
            "The party.type field is required."
        ],
        "party.id": [
            "The party.id field is required."
        ],
        "description": [
            "The description field is required."
        ]
    }
}
GET /commitments/{commitment} One commitment, with its history
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The commitment to show.

details is the description as stored, or null, and goes to everyone who can see the item. details_changed is who last changed it and when, or null, and is on every answer about one item and the export, never in a list: it is null for the person who made the change, for somebody who is only shown the item, and while it is an ask, waiting or said no to. Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

shell
curl -X GET "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000020" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000020",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": {
            "id": "0199a000-0000-7000-8000-000000000058",
            "name": "Launch",
            "tag": "launch"
        },
        "description": "Send the launch copy",
        "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-15",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000053",
                "text": "Draft the hero line",
                "done": true
            },
            {
                "id": "0199a000-0000-7000-8000-000000000054",
                "text": "Check it with Priya",
                "done": false
            },
            {
                "id": "0199a000-0000-7000-8000-000000000055",
                "text": "Send it to design",
                "done": false
            }
        ],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "details_changed",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "noted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "Whenever suits, no rush.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

As the promisee

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000020",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": {
            "id": "0199a000-0000-7000-8000-000000000058",
            "name": "Launch",
            "tag": "launch"
        },
        "description": "Send the launch copy",
        "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
        "details_changed": {
            "by": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera"
            },
            "at": "2026-10-01T09:00:00+00:00"
        },
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-15",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000053",
                "text": "Draft the hero line",
                "done": true
            },
            {
                "id": "0199a000-0000-7000-8000-000000000054",
                "text": "Check it with Priya",
                "done": false
            },
            {
                "id": "0199a000-0000-7000-8000-000000000055",
                "text": "Send it to design",
                "done": false
            }
        ],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "placement": {
            "list": "waiting_on_others",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": false,
            "is_promisee": true,
            "can_reword": false,
            "can_change_steps": false,
            "can_change_project": true,
            "can_change_details": false
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "details_changed",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "noted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "Whenever suits, no rush.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

PATCH /commitments/{commitment} Change the wording (the promiser, or whoever asked while it is still an ask), its description, or who can see a task for yourself, or whether it is something to know
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The commitment to update.
description string Optional The new wording, up to 10,000 characters. Needed unless visibility, seen_by, fyi, project_id or details is sent instead.
visibility enum Optional Who can see a task for yourself: kept to you (owner), shared with the workspace (workspace), or shown to the people and teams in seen_by (chosen). Moving to owner or workspace clears the list. One of owner, workspace, chosen.
seen_by array Optional With visibility chosen, who can see it: a list of {"type": "user" or "team", "id": the person’s or team’s id}, each one in this workspace. Sent alone, on something already chosen, it replaces the list. Nobody is told, nothing goes on the timeline, and visibility_changed goes to you and whoever can see it now.
fyi boolean Optional Switch a task for yourself to something to know, or back to a task. Only the person whose task it is, only while it is active; switching on needs a due_date of today or later, and switching off makes it one day, its first. It never changes who can see it, and sent with visibility the two are written together or not at all.
project_id id Optional A project in its workspace to put it in, or null to take it out. Anyone on either side of it can, unless it is deleted. On an item of a series it puts the series in too. Taking it out works on any plan; putting it in comes with Plus, and without it the call is refused, 402, with limit projects.
details string Optional The whole description, in Markdown, up to 10,000 characters as stored. Null or an empty string removes it; left out, it stays as it is. Only the asker while it is still an ask, the person doing it while it is active, and nobody once it has ended. Taking it away works on any plan; writing or changing one comes with Plus, and without it the call is refused, 402, with limit details. Nobody is told, and its history says that it changed.

Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

An example request

json
{
    "description": "Send the launch copy, with the screenshots"
}
shell
curl -X PATCH "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000020" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Send the launch copy, with the screenshots"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000020",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": {
            "id": "0199a000-0000-7000-8000-000000000058",
            "name": "Launch",
            "tag": "launch"
        },
        "description": "Send the launch copy, with the screenshots",
        "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-15",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000053",
                "text": "Draft the hero line",
                "done": true
            },
            {
                "id": "0199a000-0000-7000-8000-000000000054",
                "text": "Check it with Priya",
                "done": false
            },
            {
                "id": "0199a000-0000-7000-8000-000000000055",
                "text": "Send it to design",
                "done": false
            }
        ],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "reworded",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": "Send the launch copy",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "details_changed",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "noted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "Whenever suits, no rush.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

DELETE /commitments/{commitment} Delete a task for yourself: shared promises are wrapped up, never erased
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The task to delete.

restorable says whether POST /commitments/{commitment}/restore would succeed now, which is what to offer an undo on. It is false only for an open item of a series that has opened its next one: a series has one open at a time. Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

shell
curl -X DELETE "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000035" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "restorable": true
    }
}
POST /workspaces/{workspace}/quick-add/parse Read a typed line into the parts of a commitment without saving it: a convenience for human UIs
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to parse it for.
text string Yes The line to read, up to 2,000 characters.

What comes back, under data

Field Type What it means
available boolean Whether the line was read. False when AI is switched off for you or in this workspace, or no reading came back, and then every other field is null.
member object The person in this workspace the line names, as {"id", "name"}, or null when it names nobody here. Never you.
due_date date The date the line gives, in your time zone, or null. For a stretch of days, its first day.
end_date date The last day of a stretch of days the line states, like a holiday, or null for one day. Only a line that reads as something to know has one, and never more than a year after due_date.
due_time string The time the line gives, HH:MM, 24-hour, or null.
date_words string The words of the line that due_date was read from, exactly as typed, so a UI can mark them. Null when due_date is, or when the words are not the line’s own.
title string The line as it reads on its card, with the date and the person taken out, or null when nothing would be left.

It answers 30 calls a minute.

An example request

json
{
    "text": "Send Sam the launch copy on Thursday"
}
shell
curl -X POST "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/quick-add/parse" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Send Sam the launch copy on Thursday"
}'

200, and this comes back

json
{
    "data": {
        "available": true,
        "member": {
            "id": "0199a000-0000-7000-8000-000000000003",
            "name": "Sam Okafor"
        },
        "due_date": "2026-10-08",
        "end_date": null,
        "due_time": null,
        "date_words": "on Thursday",
        "title": "Send the launch copy"
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The text field is required.",
    "errors": {
        "text": [
            "The text field is required."
        ]
    }
}
GET /commitments/{commitment}/draft A message about this one, drafted for a person to edit and send: a convenience for human UIs
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The commitment to draft a message about.
type in the query enum Yes Which kind of message: renegotiating, releasing, or declining. One of renegotiate, release, decline.
due_date in the query date Optional The date to mention, needed only when the type is renegotiate.

It answers 30 calls a minute.

shell
curl -X GET "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000020/draft?type=renegotiate&due_date=2026-10-22" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "message": "I am moving the launch copy to the 22nd so the review has it in good time. Does that work for you?",
        "source": "ai"
    }
}

Creating one takes a kind (promise: you’ll do it; request: you’re asking them), the other party, a description and an optional due_date, with an optional due_time. Its row above carries a real one, with the answer it came back with.

Lists come back in one order: open work first, soonest date first, dateless work after it newest first, then closed items, most recently finished first. Open work stays however old it gets; closed items are the last two weeks of them, and ?closed=all on the list asks for every one of them instead. Every commitment also carries a placement: where it sits for whoever asked.

json
"placement": { "list": "yours_to_do", "group": "needs_your_attention" }

list is yours_to_do, waiting_on_others or closed. group says why: needs_your_attention (a decision that is yours to make), needs_your_answer (a promise to you waiting on you), coming_up, no_date_yet, or null on anything closed. The same commitment places differently for each party, so build your view from this rather than working it out again.

Search

GET /search?q=launch copy looks for words in descriptions across every workspace you belong to, and answers with the same shape and the same order as a list. Add state=open or state=closed to narrow it (the default is all), workspace={id} to search one workspace, and per_page (up to 100) with page to walk the results. Two letters is the floor, whitespace not counted, and the endpoint takes 60 searches a minute. You only ever see commitments you are part of. A workspace key searches its own workspace and no further: naming another workspace answers 403, “This key only works inside its workspace.”

shell
curl -G https://allmyducks.app/api/v1/search \
  --data-urlencode "q=launch copy" --data-urlencode "state=open" \
  -H "Authorization: Bearer <your key>" \
  -H "Accept: application/json"

This one is written by hand too: -G with --data-urlencode is how a query with spaces in it goes on the end of a URL.

Sharing a task for yourself

A task for yourself can be shown to everyone in the workspace, or to the people and teams you choose. Send visibility as owner (the default), workspace or chosen when you add it, or change it later with PATCH /commitments/{commitment}. Only a task for yourself takes it, and only in a home or a workspace with other people in it; a promise, an ask and the personal workspace each answer 422. Everyone in the workspace then sees it in their list, in search, on the calendar and in the calendar feed, with placement.list of shared. They can read it and leave a note; everything else answers 403 and says whose it is, by first name: “That’s Sam’s to change.” (with no one to name, it says “Only the person whose task this is can change it.”). Somebody outside the workspace still gets a 404. Nobody is emailed or messaged, and nothing is written to the timeline. A series takes the same field, and every occurrence it opens inherits it.

chosen comes with seen_by: the people and teams who can see it, each as {"type": "user", "id": …} or {"type": "team", "id": …} with the person’s or team’s id, all from this workspace. You are left off, since you always see your own. Each person chosen, and everyone in a chosen team while they are in it, sees it the way everyone does with workspace, and nobody else does. seen_by sent alone on something already chosen replaces the list, and moving to owner or workspace clears it. Every commitment and series carries seen_by for every viewer, with each one’s type, id and name, and an empty list unless it is chosen.

When someone chosen leaves the workspace or is removed from it, or a chosen team is deleted, they come off the list. With nobody left on it, it goes back to Only you: visibility is owner again.

Something to know

Some things on a day are for people to know, not to do. Send fyi: true on POST /workspaces/{workspace}/commitments or POST /workspaces/{workspace}/schedules and the task for yourself has nothing to tick off. Only a task for yourself takes it, and a promise or an ask answers 422 with the reason in a sentence. On a commitment it also needs a date of today or later in your time zone, and no date or a day that has gone answers 422 too; a series always has dates, and switching one on leaves an open item whose day has gone a task rather than refusing. Switch it either way with PATCH /commitments/{commitment} or PATCH /schedules/{schedule}; a switch is a setting, so it writes nothing to the timeline and leaves who can see it alone. It has no checkbox: POST /commitments/{commitment}/done answers 409 with nothing_to_tick. It is never slipped, in grace or at risk, and nothing is sent when it is added, switched or fades; its only place in a message is a line in the morning digest of everyone who can see it. After the end of its day the system closes it as expired, once, and commitment.expired goes to everyone who can see it. Who can see it is visibility, exactly as above, starting at owner. Every commitment and series carries fyi for every viewer.

Something to know can last several days, like a holiday. Send end_date with it: the last day, with due_date the first. It can last up to a year, and it has no time, so a due_time sent with it answers 422. It can have started already, as long as its last day is today or later in your time zone, and it fades after its last day rather than its first. To change the days, use POST /commitments/{commitment}/renegotiate: end_date left out keeps the last day it has, null makes it one day, and a date sets it. A series of things to know is one day each time. Every commitment carries end_date, or null for one day.

Acting on a commitment

All actions are POST /commitments/{commitment}/… and follow the same rules as the buttons in the app: the state machine allows an action or it doesn’t (409/403 when it doesn’t).

EndpointWhat it does
POST /commitments/{commitment}/accept Commit to an ask
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The ask to accept.

Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000031/accept" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000031",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Send the launch slides",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-14",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "accepted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "requested",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

POST /commitments/{commitment}/counter Accept with a different date
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The ask to accept.
due_date date Yes The date to accept it for instead.
due_time string Optional HH:MM to set the time, null to drop it, left out to keep the time it has.
message string Optional A note about why, if you want to leave one.

Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

An example request

json
{
    "due_date": "2026-10-16",
    "message": "The Friday after works better for me."
}
shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000031/counter" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "due_date": "2026-10-16",
    "message": "The Friday after works better for me."
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000031",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Send the launch slides",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-16",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "countered",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": "The Friday after works better for me.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "requested",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The due date field is required.",
    "errors": {
        "due_date": [
            "The due date field is required."
        ]
    }
}
POST /commitments/{commitment}/decline Say no, with an optional note: a clear no beats a quiet miss
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The ask to decline.
message string Optional A note about why, if you want to leave one.

Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

An example request

json
{
    "message": "I am on the launch this week, so not this one."
}
shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000031/decline" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "I am on the launch this week, so not this one."
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000031",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Send the launch slides",
        "details": null,
        "details_changed": null,
        "state": "declined",
        "source": "manual",
        "due_date": "2026-10-14",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "closed",
            "group": null
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": false,
            "can_change_steps": false,
            "can_change_project": true,
            "can_change_details": false
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "declined",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": "I am on the launch this week, so not this one.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "requested",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

POST /commitments/{commitment}/withdraw Take back an ask you made
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The ask to withdraw.

Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000033/withdraw" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000033",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Send the launch numbers",
        "details": null,
        "details_changed": null,
        "state": "withdrawn",
        "source": "manual",
        "due_date": "2026-10-17",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "placement": {
            "list": "closed",
            "group": null
        },
        "viewer": {
            "is_promiser": false,
            "is_promisee": true,
            "can_reword": false,
            "can_change_steps": false,
            "can_change_project": true,
            "can_change_details": false
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "withdrawn",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "requested",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

POST /commitments/{commitment}/done It’s done
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The commitment to mark done.

Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000020/done" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000020",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": {
            "id": "0199a000-0000-7000-8000-000000000058",
            "name": "Launch",
            "tag": "launch"
        },
        "description": "Send the launch copy",
        "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
        "details_changed": null,
        "state": "done",
        "source": "manual",
        "due_date": "2026-10-15",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000053",
                "text": "Draft the hero line",
                "done": true
            },
            {
                "id": "0199a000-0000-7000-8000-000000000054",
                "text": "Check it with Priya",
                "done": false
            },
            {
                "id": "0199a000-0000-7000-8000-000000000055",
                "text": "Send it to design",
                "done": false
            }
        ],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "closed",
            "group": null
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": false,
            "can_change_steps": false,
            "can_change_project": true,
            "can_change_details": false
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "done",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "details_changed",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "noted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "Whenever suits, no rush.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

POST /commitments/{commitment}/reopen Reopen a done commitment (promiser only)
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The commitment to reopen.

On an item of a series, the next one goes if nothing has happened to it. Otherwise this is refused with 409 and series_moved_on, and while another one of the series is open the message names it. Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000022/reopen" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000022",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Book the launch review",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-09-29",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": true,
        "in_grace_window": false,
        "grace_closed": true,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "needs_your_attention"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "reopened",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "done",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

POST /commitments/{commitment}/renegotiate Pick a new date, with a note
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The commitment to move.
due_date date Yes The new date.
due_time string Optional HH:MM to set the time, null to drop it, left out to keep the time it has.
end_date date Optional The last day of something to know that lasts several days: due_date is the first. A date sets it, null makes it one day, and left out keeps the last day it has. The same rules as when it was added; a time it had goes when it gets a last day, and one sent with it is refused.
message string Optional A note about why, if you want to leave one.

Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

An example request

json
{
    "due_date": "2026-10-22",
    "due_time": "15:00",
    "message": "The review moved, so this moves with it."
}
shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000020/renegotiate" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "due_date": "2026-10-22",
    "due_time": "15:00",
    "message": "The review moved, so this moves with it."
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000020",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": {
            "id": "0199a000-0000-7000-8000-000000000058",
            "name": "Launch",
            "tag": "launch"
        },
        "description": "Send the launch copy",
        "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-22",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": "15:00",
        "due_at": "2026-10-22T14:00:00+00:00",
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000053",
                "text": "Draft the hero line",
                "done": true
            },
            {
                "id": "0199a000-0000-7000-8000-000000000054",
                "text": "Check it with Priya",
                "done": false
            },
            {
                "id": "0199a000-0000-7000-8000-000000000055",
                "text": "Send it to design",
                "done": false
            }
        ],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "renegotiated",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": "The review moved, so this moves with it.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "details_changed",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "noted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "Whenever suits, no rush.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The due date field is required.",
    "errors": {
        "due_date": [
            "The due date field is required."
        ]
    }
}
POST /commitments/{commitment}/notes Leave a note on the timeline: every party sees it
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The commitment to leave a note on.
message string Yes What to say on the timeline.

An example request

json
{
    "message": "First draft is with the designers."
}
shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000020/notes" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "First draft is with the designers."
}'

201, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000020",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": {
            "id": "0199a000-0000-7000-8000-000000000058",
            "name": "Launch",
            "tag": "launch"
        },
        "description": "Send the launch copy",
        "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-15",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000053",
                "text": "Draft the hero line",
                "done": true
            },
            {
                "id": "0199a000-0000-7000-8000-000000000054",
                "text": "Check it with Priya",
                "done": false
            },
            {
                "id": "0199a000-0000-7000-8000-000000000055",
                "text": "Send it to design",
                "done": false
            }
        ],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "noted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": "First draft is with the designers.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "details_changed",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "noted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "Whenever suits, no rush.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The message field is required.",
    "errors": {
        "message": [
            "The message field is required."
        ]
    }
}
POST /commitments/{commitment}/request-release Ask to be let off the hook
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The commitment to ask off.
message string Optional A note about why, if you want to leave one.

Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

An example request

json
{
    "message": "The launch took the week. Can this go?"
}
shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000020/request-release" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "The launch took the week. Can this go?"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000020",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": {
            "id": "0199a000-0000-7000-8000-000000000058",
            "name": "Launch",
            "tag": "launch"
        },
        "description": "Send the launch copy",
        "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-15",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000053",
                "text": "Draft the hero line",
                "done": true
            },
            {
                "id": "0199a000-0000-7000-8000-000000000054",
                "text": "Check it with Priya",
                "done": false
            },
            {
                "id": "0199a000-0000-7000-8000-000000000055",
                "text": "Send it to design",
                "done": false
            }
        ],
        "release_requested": true,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "release_requested",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": "The launch took the week. Can this go?",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "details_changed",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "noted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "Whenever suits, no rush.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

POST /commitments/{commitment}/release Let them off the hook
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The commitment to release.

Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000028/release" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000028",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Send the launch metrics",
        "details": null,
        "details_changed": null,
        "state": "released",
        "source": "manual",
        "due_date": "2026-10-13",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": true,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "placement": {
            "list": "closed",
            "group": null
        },
        "viewer": {
            "is_promiser": false,
            "is_promisee": true,
            "can_reword": false,
            "can_change_steps": false,
            "can_change_project": true,
            "can_change_details": false
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "released",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "release_requested",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "The launch took my week. Can this go?",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

POST /commitments/{commitment}/keep Keep a promise as it stands after a release ask
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The commitment to keep.

Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000028/keep" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000028",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Send the launch metrics",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-13",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "placement": {
            "list": "waiting_on_others",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": false,
            "is_promisee": true,
            "can_reword": false,
            "can_change_steps": false,
            "can_change_project": true,
            "can_change_details": false
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "release_declined",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "release_requested",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "The launch took my week. Can this go?",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

POST /commitments/{commitment}/move Move a todo to another of your workspaces
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The todo to move: one with just you in it.
workspace_id id Yes Where it goes: one of your workspaces, the personal one included.

Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

An example request

json
{
    "workspace_id": "0199a000-0000-7000-8000-000000000013"
}
shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000041/move" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "0199a000-0000-7000-8000-000000000013"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000041",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000013",
            "name": "Home",
            "type": "home",
            "colour": null
        },
        "project": null,
        "description": "Order the launch stickers",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": null,
        "end_date": null,
        "due_timezone": null,
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "no_date_yet"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "moved",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": {
                    "name": "Acme",
                    "type": "team"
                },
                "to_workspace": {
                    "name": "Home",
                    "type": "home"
                },
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "Say where it goes.",
    "errors": {
        "workspace_id": [
            "Say where it goes."
        ]
    }
}
POST /commitments/{commitment}/pick-up Pick a released promise back up (promiser only)
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The commitment to pick back up.

An item of a series is refused with 409 and series_moved_on while the series has another one open, and the message names it: a series has one open at a time. Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000025/pick-up" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000025",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Draft the launch FAQ",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-09-24",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": true,
        "in_grace_window": false,
        "grace_closed": true,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "needs_your_attention"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "picked_up",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "released",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

POST /commitments/{commitment}/restore Restore a deleted todo within 30 days
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The todo to restore.

An open item of a series is refused with 409 and series_moved_on while the series has another one open, and the message names it. The delete’s restorable says so ahead of time. Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000036/restore" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000036",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Cancel the old launch invite",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-06",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

POST /commitments/{commitment}/steps Add a step to something you are doing: one line
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The item the step is on.
text string Yes The step, one line of up to 200 characters. Blank, longer or with a line break is refused.
position integer Optional Where the step goes, counting the first as 0. Left out, or past the last, it goes last. For putting back a step that was removed.
done boolean Optional True adds it ticked. Left out, it is added unticked.

Only the person doing it, while it is active and not something to know. Past what the person’s plan holds it is refused, 402, in the words steps have always had. Nothing is sent to anyone and nothing goes on the timeline: steps are in the item’s body, wherever it is sent.

An example request

json
{
    "text": "Attach the screenshots"
}
shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000020/steps" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Attach the screenshots"
}'

201, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000020",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": {
            "id": "0199a000-0000-7000-8000-000000000058",
            "name": "Launch",
            "tag": "launch"
        },
        "description": "Send the launch copy",
        "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-15",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000053",
                "text": "Draft the hero line",
                "done": true
            },
            {
                "id": "0199a000-0000-7000-8000-000000000054",
                "text": "Check it with Priya",
                "done": false
            },
            {
                "id": "0199a000-0000-7000-8000-000000000055",
                "text": "Send it to design",
                "done": false
            },
            {
                "id": "0199a000-0000-7000-8000-000000900002",
                "text": "Attach the screenshots",
                "done": false
            }
        ],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "details_changed",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "noted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "Whenever suits, no rush.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "Say what the step is.",
    "errors": {
        "text": [
            "Say what the step is."
        ]
    }
}
PATCH /commitments/{commitment}/steps/{step} Tick a step, untick it, or reword it
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The item the step is on.
step in the path id Yes The step, from the item’s steps.
text string Optional The step, one line of up to 200 characters. Blank, longer or with a line break is refused.
done boolean Optional True ticks it, false unticks it.

An example request

json
{
    "done": true
}
shell
curl -X PATCH "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000020/steps/0199a000-0000-7000-8000-000000000054" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "done": true
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000020",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": {
            "id": "0199a000-0000-7000-8000-000000000058",
            "name": "Launch",
            "tag": "launch"
        },
        "description": "Send the launch copy",
        "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-15",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000053",
                "text": "Draft the hero line",
                "done": true
            },
            {
                "id": "0199a000-0000-7000-8000-000000000054",
                "text": "Check it with Priya",
                "done": true
            },
            {
                "id": "0199a000-0000-7000-8000-000000000055",
                "text": "Send it to design",
                "done": false
            }
        ],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "details_changed",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "noted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "Whenever suits, no rush.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

DELETE /commitments/{commitment}/steps/{step} Remove a step
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The item the step is on.
step in the path id Yes The step, from the item’s steps.
shell
curl -X DELETE "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000020/steps/0199a000-0000-7000-8000-000000000054" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000020",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": {
            "id": "0199a000-0000-7000-8000-000000000058",
            "name": "Launch",
            "tag": "launch"
        },
        "description": "Send the launch copy",
        "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-15",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000053",
                "text": "Draft the hero line",
                "done": true
            },
            {
                "id": "0199a000-0000-7000-8000-000000000055",
                "text": "Send it to design",
                "done": false
            }
        ],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "details_changed",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "noted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "Whenever suits, no rush.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

PUT /commitments/{commitment}/steps/order Put the steps in a new order
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The item the step is on.
steps array Yes Every step’s id, each once, in the new order. A list that is not the item’s steps as they are now is refused with 409.

An example request

json
{
    "steps": [
        "0199a000-0000-7000-8000-000000000055",
        "0199a000-0000-7000-8000-000000000054",
        "0199a000-0000-7000-8000-000000000053"
    ]
}
shell
curl -X PUT "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000020/steps/order" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "steps": [
        "0199a000-0000-7000-8000-000000000055",
        "0199a000-0000-7000-8000-000000000054",
        "0199a000-0000-7000-8000-000000000053"
    ]
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000020",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": {
            "id": "0199a000-0000-7000-8000-000000000058",
            "name": "Launch",
            "tag": "launch"
        },
        "description": "Send the launch copy",
        "details": "Two things to settle first:\n\n- the **opening line**\n- the *final* image\n\nThe brief is at <https://example.com/brief>.",
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-15",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": false,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000055",
                "text": "Send it to design",
                "done": false
            },
            {
                "id": "0199a000-0000-7000-8000-000000000054",
                "text": "Check it with Priya",
                "done": false
            },
            {
                "id": "0199a000-0000-7000-8000-000000000053",
                "text": "Draft the hero line",
                "done": true
            }
        ],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": false,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "details_changed",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "noted",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000003",
                    "name": "Sam Okafor"
                },
                "message": "Whenever suits, no rush.",
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The steps field is required.",
    "errors": {
        "steps": [
            "The steps field is required."
        ]
    }
}

Things that repeat

A schedule owns one live occurrence at a time. An occurrence is an ordinary commitment with a schedule block; done rolls the series forward; skip closes this one and brings the next.

EndpointWhat it does
GET /workspaces/{workspace}/schedules The series in a workspace
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to list.
shell
curl -X GET "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/schedules" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000037",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "kind": "todo",
            "template": "domain",
            "icon": "globe",
            "name": "Renew example.com",
            "details": null,
            "details_changed": null,
            "details_by": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera"
            },
            "rule": {
                "every": "year",
                "day": 20,
                "month": 10,
                "interval": 1
            },
            "rule_words": "Every year on 20 October",
            "lead_days": 30,
            "next_due_date": "2026-10-20",
            "next_due_timezone": "Europe/London",
            "upcoming": [
                {
                    "date": "2026-10-20",
                    "label": null,
                    "occurrence_id": "0199a000-0000-7000-8000-000000000038"
                },
                {
                    "date": "2027-10-20",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2028-10-20",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2029-10-20",
                    "label": null,
                    "occurrence_id": null
                }
            ],
            "is_private": true,
            "visibility": "workspace",
            "seen_by": [],
            "fyi": false,
            "steps": [
                {
                    "id": "0199a000-0000-7000-8000-000000000056",
                    "text": "Check the renewal price"
                },
                {
                    "id": "0199a000-0000-7000-8000-000000000057",
                    "text": "Update the card on file"
                }
            ],
            "ended_at": null,
            "viewer": {
                "is_owner": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "owner": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                }
            },
            "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
            "completions": [],
            "module": {
                "key": "domain",
                "input": "example.com",
                "label": "example.com",
                "icon": "globe",
                "refreshed_at": "2026-10-01T09:00:00+00:00",
                "dates": [
                    {
                        "key": "expiry",
                        "label": "Renewal due",
                        "date": "2026-10-20"
                    }
                ],
                "trouble": true,
                "trouble_line": "Can't reach the registry at the moment."
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000042",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "kind": "todo",
            "template": "custom",
            "icon": "repeat",
            "name": "Order the printer paper",
            "details": null,
            "details_changed": null,
            "details_by": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera"
            },
            "rule": {
                "every": "week",
                "weekday": 3,
                "interval": 1
            },
            "rule_words": "Every week on Wednesday",
            "lead_days": 0,
            "next_due_date": "2026-10-07",
            "next_due_timezone": "Europe/London",
            "upcoming": [
                {
                    "date": "2026-10-07",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-14",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-21",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-28",
                    "label": null,
                    "occurrence_id": null
                }
            ],
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "ended_at": null,
            "viewer": {
                "is_owner": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "owner": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                }
            },
            "open_occurrence_id": null,
            "completions": [],
            "module": null,
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000046",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "kind": "todo",
            "template": "custom",
            "icon": "repeat",
            "name": "Water the office plants",
            "details": null,
            "details_changed": null,
            "details_by": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera"
            },
            "rule": {
                "every": "week",
                "weekday": 5,
                "interval": 1
            },
            "rule_words": "Every week on Friday",
            "lead_days": 0,
            "next_due_date": "2026-10-02",
            "next_due_timezone": "Europe/London",
            "upcoming": [
                {
                    "date": "2026-10-02",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-09",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-16",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-23",
                    "label": null,
                    "occurrence_id": null
                }
            ],
            "is_private": true,
            "visibility": "workspace",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "ended_at": null,
            "viewer": {
                "is_owner": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "owner": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                }
            },
            "open_occurrence_id": null,
            "completions": [],
            "module": null,
            "created_at": "2026-10-01T09:00:00+00:00"
        }
    ],
    "links": {
        "next": null,
        "prev": null
    },
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "total": 3
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

GET /schedules The series across every workspace you are in
Request and responseHide request and response
Field Type Needed What it means
scope in the query enum Yes Ask for the union on purpose, rather than by leaving a workspace out. One of all.
workspaces in the query string Optional A comma-separated list of workspace ids to narrow the union to, or leave it out for every one you are in.
shell
curl -X GET "https://allmyducks.app/api/v1/schedules?scope=all" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000037",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "kind": "todo",
            "template": "domain",
            "icon": "globe",
            "name": "Renew example.com",
            "details": null,
            "details_changed": null,
            "details_by": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera"
            },
            "rule": {
                "every": "year",
                "day": 20,
                "month": 10,
                "interval": 1
            },
            "rule_words": "Every year on 20 October",
            "lead_days": 30,
            "next_due_date": "2026-10-20",
            "next_due_timezone": "Europe/London",
            "upcoming": [
                {
                    "date": "2026-10-20",
                    "label": null,
                    "occurrence_id": "0199a000-0000-7000-8000-000000000038"
                },
                {
                    "date": "2027-10-20",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2028-10-20",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2029-10-20",
                    "label": null,
                    "occurrence_id": null
                }
            ],
            "is_private": true,
            "visibility": "workspace",
            "seen_by": [],
            "fyi": false,
            "steps": [
                {
                    "id": "0199a000-0000-7000-8000-000000000056",
                    "text": "Check the renewal price"
                },
                {
                    "id": "0199a000-0000-7000-8000-000000000057",
                    "text": "Update the card on file"
                }
            ],
            "ended_at": null,
            "viewer": {
                "is_owner": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "owner": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                }
            },
            "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
            "completions": [],
            "module": {
                "key": "domain",
                "input": "example.com",
                "label": "example.com",
                "icon": "globe",
                "refreshed_at": "2026-10-01T09:00:00+00:00",
                "dates": [
                    {
                        "key": "expiry",
                        "label": "Renewal due",
                        "date": "2026-10-20"
                    }
                ],
                "trouble": true,
                "trouble_line": "Can't reach the registry at the moment."
            },
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000042",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "kind": "todo",
            "template": "custom",
            "icon": "repeat",
            "name": "Order the printer paper",
            "details": null,
            "details_changed": null,
            "details_by": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera"
            },
            "rule": {
                "every": "week",
                "weekday": 3,
                "interval": 1
            },
            "rule_words": "Every week on Wednesday",
            "lead_days": 0,
            "next_due_date": "2026-10-07",
            "next_due_timezone": "Europe/London",
            "upcoming": [
                {
                    "date": "2026-10-07",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-14",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-21",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-28",
                    "label": null,
                    "occurrence_id": null
                }
            ],
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "ended_at": null,
            "viewer": {
                "is_owner": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "owner": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                }
            },
            "open_occurrence_id": null,
            "completions": [],
            "module": null,
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000046",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            },
            "project": null,
            "kind": "todo",
            "template": "custom",
            "icon": "repeat",
            "name": "Water the office plants",
            "details": null,
            "details_changed": null,
            "details_by": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera"
            },
            "rule": {
                "every": "week",
                "weekday": 5,
                "interval": 1
            },
            "rule_words": "Every week on Friday",
            "lead_days": 0,
            "next_due_date": "2026-10-02",
            "next_due_timezone": "Europe/London",
            "upcoming": [
                {
                    "date": "2026-10-02",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-09",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-16",
                    "label": null,
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-23",
                    "label": null,
                    "occurrence_id": null
                }
            ],
            "is_private": true,
            "visibility": "workspace",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "ended_at": null,
            "viewer": {
                "is_owner": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "owner": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                }
            },
            "open_occurrence_id": null,
            "completions": [],
            "module": null,
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000047",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null
            },
            "project": null,
            "kind": "todo",
            "template": "bins",
            "icon": "bin",
            "name": "Bins",
            "details": null,
            "details_changed": null,
            "details_by": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera"
            },
            "rule": {
                "every": "week",
                "weekday": 2,
                "interval": 1,
                "cycle": [
                    "Recycling",
                    "General waste"
                ],
                "cycle_anchor": "2026-10-05"
            },
            "rule_words": "Every week on Tuesday",
            "lead_days": 7,
            "next_due_date": "2026-10-06",
            "next_due_timezone": "Europe/London",
            "upcoming": [
                {
                    "date": "2026-10-06",
                    "label": "Recycling",
                    "occurrence_id": "0199a000-0000-7000-8000-000000000048"
                },
                {
                    "date": "2026-10-13",
                    "label": "General waste",
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-20",
                    "label": "Recycling",
                    "occurrence_id": null
                },
                {
                    "date": "2026-10-27",
                    "label": "General waste",
                    "occurrence_id": null
                }
            ],
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "ended_at": null,
            "viewer": {
                "is_owner": true,
                "can_change_steps": true,
                "can_add_step": true,
                "step_limit_reason": null,
                "can_change_project": true,
                "can_change_details": true
            },
            "parties": {
                "owner": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                }
            },
            "open_occurrence_id": "0199a000-0000-7000-8000-000000000048",
            "completions": [],
            "module": null,
            "created_at": "2026-10-01T09:00:00+00:00"
        },
        {
            "id": "0199a000-0000-7000-8000-000000000039",
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null
            },
            "project": null,
            "kind": "todo",
            "template": "custom",
            "icon": "repeat",
            "name": "Water the plants",
            "details": null,
            "details_changed": null,
            "details_by": null,
            "rule": {
                "every": "week",
                "weekday": 6,
                "interval": 1
            },
            "rule_words": "Every week on Saturday",
            "lead_days": 7,
            "next_due_date": "2026-10-03",
            "next_due_timezone": "Europe/London",
            "upcoming": [],
            "is_private": true,
            "visibility": "owner",
            "seen_by": [],
            "fyi": false,
            "steps": [],
            "ended_at": "2026-10-01T09:00:00+00:00",
            "viewer": {
                "is_owner": true,
                "can_change_steps": false,
                "can_change_project": true,
                "can_change_details": false
            },
            "parties": {
                "owner": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                },
                "promisee": {
                    "type": "user",
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera",
                    "avatar_url": null
                }
            },
            "open_occurrence_id": null,
            "completions": [],
            "module": null,
            "created_at": "2026-10-01T09:00:00+00:00"
        }
    ],
    "links": {
        "next": null,
        "prev": null
    },
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "total": 5
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

GET /calendar Projected dates across every workspace you are in
Request and responseHide request and response
Field Type Needed What it means
scope in the query enum Yes Ask for the union on purpose, rather than by leaving a workspace out. One of all.
workspaces in the query string Optional A comma-separated list of workspace ids to narrow the union to, or leave it out for every one you are in.
from in the query date Yes The window’s start date.
to in the query date Yes The window’s end date, at most a year after from, and at most six weeks after it without the year view (Plus).

Each row carries label, the rotation’s name for that date, or null for a series that does not take turns. A row is a date, so it never carries the item’s words. Past six weeks without the year view the window is refused, 402, with limit year_view; every month grid is within it.

shell
curl -X GET "https://allmyducks.app/api/v1/calendar?scope=all&from=2026-10-01&to=2026-10-31" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000047",
            "name": "Bins",
            "icon": "bin",
            "date": "2026-10-13",
            "label": "General waste",
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000047",
            "name": "Bins",
            "icon": "bin",
            "date": "2026-10-20",
            "label": "Recycling",
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000047",
            "name": "Bins",
            "icon": "bin",
            "date": "2026-10-27",
            "label": "General waste",
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000013",
                "name": "Home",
                "type": "home",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000042",
            "name": "Order the printer paper",
            "icon": "repeat",
            "date": "2026-10-07",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000042",
            "name": "Order the printer paper",
            "icon": "repeat",
            "date": "2026-10-14",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000042",
            "name": "Order the printer paper",
            "icon": "repeat",
            "date": "2026-10-21",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000042",
            "name": "Order the printer paper",
            "icon": "repeat",
            "date": "2026-10-28",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000046",
            "name": "Water the office plants",
            "icon": "repeat",
            "date": "2026-10-02",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000046",
            "name": "Water the office plants",
            "icon": "repeat",
            "date": "2026-10-09",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000046",
            "name": "Water the office plants",
            "icon": "repeat",
            "date": "2026-10-16",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000046",
            "name": "Water the office plants",
            "icon": "repeat",
            "date": "2026-10-23",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000046",
            "name": "Water the office plants",
            "icon": "repeat",
            "date": "2026-10-30",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        }
    ]
}
POST /workspaces/{workspace}/schedules Start a series: what repeats, how often, who it is with
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace it belongs to.
kind enum Yes Whether this series makes a private todo, a promise or an ask, each occurrence repeating. One of todo, promise, request.
party.type enum Optional Whether the other party is a person or a team. Required unless kind is todo. One of user, team.
party.id id Optional The person or team it is for. Required unless kind is todo.
template string Yes Which entry from the catalogue this series starts from, as GET /templates lists it.
name string Yes What to call it, up to 500 characters.
rule object Yes How it repeats: weekly, monthly, yearly, every so many days, or a cycle of labelled weeks. The response says the same rule in words, as rule_words. A cycle sent without cycle_anchor starts with its first label on the next date.
lead_days integer Optional How many days before the due date the occurrence is raised, from 0 to 730. Leave it out for the template’s own default.
module_input string Optional What to look up, for a template whose source needs one: a plate, a domain, a hostname, a company number. The same value POST /modules/{module}/identify takes.
both boolean Optional Also start the paired series from the same lookup, for a template that has one (car tax and MOT on one plate).
visibility enum Optional Who can see a todo series: kept to you (owner), shared with the workspace (workspace), or shown to the people and teams in seen_by (chosen). Refused once there are two parties. One of owner, workspace, chosen.
seen_by array Optional With visibility chosen, who can see it: a list of {"type": "user" or "team", "id": the person’s or team’s id}, each one in this workspace, at least one besides you. Every item the series opens is seen by the same list. Refused with any other visibility.
fyi boolean Optional Something to know: every item the series opens has nothing to tick off, and goes by itself after its day. Only for kind todo. Who can see it is visibility, as for any todo series.
project_id id Optional A project in this workspace to put the series in, or leave it out for none. Every item it opens goes in too. Putting something in a project comes with Plus; without it nothing is made and the call is refused, 402, with limit projects.
details string Optional What each one involves, in Markdown, up to 10,000 characters as stored. Every item the series opens starts with a copy. Writing one comes with Plus; without it nothing is made and the call is refused, 402, with limit details. With both, only the series you named gets it.

An example request

json
{
    "kind": "todo",
    "template": "custom",
    "name": "Water the plants",
    "rule": {
        "every": "week",
        "weekday": 6
    },
    "lead_days": 7,
    "visibility": "owner"
}
shell
curl -X POST "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/schedules" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "todo",
    "template": "custom",
    "name": "Water the plants",
    "rule": {
        "every": "week",
        "weekday": 6
    },
    "lead_days": 7,
    "visibility": "owner"
}'

201, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000900002",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "custom",
        "icon": "repeat",
        "name": "Water the plants",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "week",
            "weekday": 6,
            "interval": 1
        },
        "rule_words": "Every week on Saturday",
        "lead_days": 7,
        "next_due_date": "2026-10-03",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-03",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000900004"
            },
            {
                "date": "2026-10-10",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2026-10-17",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2026-10-24",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000900004",
        "completions": [],
        "module": null,
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The kind field is required. (and 4 more errors)",
    "errors": {
        "kind": [
            "The kind field is required."
        ],
        "party": [
            "Say who it is for."
        ],
        "template": [
            "The template field is required."
        ],
        "name": [
            "The name field is required."
        ],
        "rule": [
            "Say how often it repeats."
        ]
    }
}
GET /schedules/{schedule} One series, with its recent occurrences
Request and responseHide request and response
Field Type Needed What it means
schedule in the path id Yes The series to show.

upcoming is what is coming up, the same for everyone who can see the series: the item on the list now first, with its id, then the dates after it, each with its label when the series takes turns. There are at least four, and every label appears once. It is empty once the series has ended. Each entry in completions carries description, the done item’s words, when you may read that item, and null when you may not. The dates are there either way. details_changed is who last changed the description and when, on the same terms as an item’s, and details_by is the person whose it is to change now, or null once the series has ended.

shell
curl -X GET "https://allmyducks.app/api/v1/schedules/0199a000-0000-7000-8000-000000000037" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 30,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-20",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000000038"
            },
            {
                "date": "2027-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2028-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2029-10-20",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000056",
                "text": "Check the renewal price"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            }
        ],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": true,
            "trouble_line": "Can't reach the registry at the moment."
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

PATCH /schedules/{schedule} Change the name, the description, the rule, how far ahead it is raised, who can see it, or whether it is something to know
Request and responseHide request and response
Field Type Needed What it means
schedule in the path id Yes The series to update.
name string Optional What to call it, up to 500 characters.
rule object Optional How it repeats, in the same words the response answers with as rule_words. A cycle sent without cycle_anchor starts with its first label on the next date.
lead_days integer Optional How many days before the due date the occurrence is raised, from 0 to 730.
visibility enum Optional Who can see a todo series: kept to you (owner), shared with the workspace (workspace), or shown to the people and teams in seen_by (chosen). The open item changes with it, and closed ones keep what they had. One of owner, workspace, chosen.
seen_by array Optional With visibility chosen, who can see it: a list of {"type": "user" or "team", "id": the person’s or team’s id}, each one in this workspace. Sent alone, on a series already chosen, it replaces the list, on the series and on its open item.
fyi boolean Optional Switch a todo series to something to know, or back to a task. The open item changes at once and closed ones keep what they had. It never changes who can see it.
project_id id Optional A project in its workspace to put the series in, or null to take it out. The open item goes with it and closed ones keep what they had. Sent alone, anyone on either side of the series can; every other field stays the owner’s. Taking it out works on any plan; putting it in comes with Plus, and without it the call is refused, 402, with limit projects.
details string Optional The series’ description, in Markdown, up to 10,000 characters as stored. Null or an empty string removes it; left out, it stays as it is. Items the series opens from now on start with a copy, and one already open keeps its own. Sent alone, either party to the series can send it, and the series’ rule decides: the owner, or on a series of asks someone has said yes to, the person who said yes while they are still in the team (or the workspace); otherwise the asker. Sent with any other field it stays the owner’s, and a refusal writes nothing. Taking it away works on any plan; writing or changing one comes with Plus, and without it the call is refused, 402, with limit details. Refused on a series that has ended.

The other party to a promise is refused, 403, with “Only the person this repeats for can change it.” Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.” Somebody who cannot see the series at all is answered 404. A body of project_id alone, or of details alone, is the exception: either party may send it, and then only somebody who is merely shown the series is refused.

An example request

json
{
    "name": "Renew example.com",
    "lead_days": 21
}
shell
curl -X PATCH "https://allmyducks.app/api/v1/schedules/0199a000-0000-7000-8000-000000000037" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Renew example.com",
    "lead_days": 21
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 21,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-20",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000000038"
            },
            {
                "date": "2027-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2028-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2029-10-20",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000056",
                "text": "Check the renewal price"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            }
        ],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": true,
            "trouble_line": "Can't reach the registry at the moment."
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

DELETE /schedules/{schedule} Delete a private series: its open occurrence goes with it, restorable for thirty days
Request and responseHide request and response
Field Type Needed What it means
schedule in the path id Yes The series to delete.

The other party to a promise is refused, 403, with “Only the person this repeats for can change it.” Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.” Somebody who cannot see the series at all is answered 404.

shell
curl -X DELETE "https://allmyducks.app/api/v1/schedules/0199a000-0000-7000-8000-000000000037" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

204, and no body.

POST /schedules/{schedule}/end End a series: the open one is let go and no more are made
Request and responseHide request and response
Field Type Needed What it means
schedule in the path id Yes The series to end.

Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.” Either party to a promise may end it.

shell
curl -X POST "https://allmyducks.app/api/v1/schedules/0199a000-0000-7000-8000-000000000037/end" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": null,
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 30,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000056",
                "text": "Check the renewal price"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            }
        ],
        "ended_at": "2026-10-01T09:00:00+00:00",
        "viewer": {
            "is_owner": true,
            "can_change_steps": false,
            "can_change_project": true,
            "can_change_details": false
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": null,
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": true,
            "trouble_line": "Can't reach the registry at the moment."
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

POST /schedules/{schedule}/restart Start raising them again from an ended series
Request and responseHide request and response
Field Type Needed What it means
schedule in the path id Yes The series to restart.

The other party to a promise is refused, 403, with “Only the person this repeats for can change it.” Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.” Somebody who cannot see the series at all is answered 404.

shell
curl -X POST "https://allmyducks.app/api/v1/schedules/0199a000-0000-7000-8000-000000000039/restart" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000039",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000013",
            "name": "Home",
            "type": "home",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "custom",
        "icon": "repeat",
        "name": "Water the plants",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "week",
            "weekday": 6,
            "interval": 1
        },
        "rule_words": "Every week on Saturday",
        "lead_days": 7,
        "next_due_date": "2026-10-03",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-03",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000900003"
            },
            {
                "date": "2026-10-10",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2026-10-17",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2026-10-24",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000900003",
        "completions": [],
        "module": null,
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

POST /schedules/{schedule}/move Move a series, and every item it made, to another of your workspaces
Request and responseHide request and response
Field Type Needed What it means
schedule in the path id Yes The series to move: one with just you in it.
workspace_id id Yes Where it goes: one of your workspaces, the personal one included.

The items it made, open, closed and deleted, go with it, and the next one opens there. Who could see it before is no longer shown it: it arrives for you alone, whatever it was. If an item is open, the move is written on that item’s history; with none, nothing is written. The other party to a promise is refused, 403, with “Only the person this repeats for can change it.” Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.” Somebody who cannot see the series at all is answered 404.

An example request

json
{
    "workspace_id": "0199a000-0000-7000-8000-000000000013"
}
shell
curl -X POST "https://allmyducks.app/api/v1/schedules/0199a000-0000-7000-8000-000000000042/move" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "0199a000-0000-7000-8000-000000000013"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000042",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000013",
            "name": "Home",
            "type": "home",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "custom",
        "icon": "repeat",
        "name": "Order the printer paper",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "week",
            "weekday": 3,
            "interval": 1
        },
        "rule_words": "Every week on Wednesday",
        "lead_days": 0,
        "next_due_date": "2026-10-07",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-07",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2026-10-14",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2026-10-21",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2026-10-28",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": null,
        "completions": [],
        "module": null,
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "Say where it goes.",
    "errors": {
        "workspace_id": [
            "Say where it goes."
        ]
    }
}
POST /schedules/{schedule}/steps Add a step for every time: each item the series opens starts with it, unticked
Request and responseHide request and response
Field Type Needed What it means
schedule in the path id Yes The series the step is for.
text string Yes The step, one line of up to 200 characters. Blank, longer or with a line break is refused.
position integer Optional Where the step goes, counting the first as 0. Left out, or past the last, it goes last. For putting back a step that was removed.

Each item the series opens from now on starts with these, unticked. An item already open keeps its own. Not on a series of asks or of something to know. The other party to a promise is refused, 403, with “Only the person this repeats for can change it.” Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.” Somebody who cannot see the series at all is answered 404.

An example request

json
{
    "text": "Note the new expiry date"
}
shell
curl -X POST "https://allmyducks.app/api/v1/schedules/0199a000-0000-7000-8000-000000000037/steps" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Note the new expiry date"
}'

201, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 30,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-20",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000000038"
            },
            {
                "date": "2027-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2028-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2029-10-20",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000056",
                "text": "Check the renewal price"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            },
            {
                "id": "0199a000-0000-7000-8000-000000900002",
                "text": "Note the new expiry date"
            }
        ],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": true,
            "trouble_line": "Can't reach the registry at the moment."
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "Say what the step is.",
    "errors": {
        "text": [
            "Say what the step is."
        ]
    }
}
PATCH /schedules/{schedule}/steps/{step} Reword a step for every time
Request and responseHide request and response
Field Type Needed What it means
schedule in the path id Yes The series the step is for.
step in the path id Yes The step, from the series’ steps.
text string Yes The step, one line of up to 200 characters. Blank, longer or with a line break is refused.

The other party to a promise is refused, 403, with “Only the person this repeats for can change it.” Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.” Somebody who cannot see the series at all is answered 404.

An example request

json
{
    "text": "Check the renewal price against last year"
}
shell
curl -X PATCH "https://allmyducks.app/api/v1/schedules/0199a000-0000-7000-8000-000000000037/steps/0199a000-0000-7000-8000-000000000056" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Check the renewal price against last year"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 30,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-20",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000000038"
            },
            {
                "date": "2027-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2028-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2029-10-20",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000056",
                "text": "Check the renewal price against last year"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            }
        ],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": true,
            "trouble_line": "Can't reach the registry at the moment."
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "Say what the step is.",
    "errors": {
        "text": [
            "Say what the step is."
        ]
    }
}
DELETE /schedules/{schedule}/steps/{step} Remove a step for every time
Request and responseHide request and response
Field Type Needed What it means
schedule in the path id Yes The series the step is for.
step in the path id Yes The step, from the series’ steps.

The other party to a promise is refused, 403, with “Only the person this repeats for can change it.” Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.” Somebody who cannot see the series at all is answered 404.

shell
curl -X DELETE "https://allmyducks.app/api/v1/schedules/0199a000-0000-7000-8000-000000000037/steps/0199a000-0000-7000-8000-000000000056" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 30,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-20",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000000038"
            },
            {
                "date": "2027-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2028-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2029-10-20",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            }
        ],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": true,
            "trouble_line": "Can't reach the registry at the moment."
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

PUT /schedules/{schedule}/steps/order Put the steps for every time in a new order
Request and responseHide request and response
Field Type Needed What it means
schedule in the path id Yes The series the step is for.
steps array Yes Every step’s id, each once, in the new order. A list that is not the series’ steps as they are now is refused with 409.

The other party to a promise is refused, 403, with “Only the person this repeats for can change it.” Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.” Somebody who cannot see the series at all is answered 404.

An example request

json
{
    "steps": [
        "0199a000-0000-7000-8000-000000000057",
        "0199a000-0000-7000-8000-000000000056"
    ]
}
shell
curl -X PUT "https://allmyducks.app/api/v1/schedules/0199a000-0000-7000-8000-000000000037/steps/order" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "steps": [
        "0199a000-0000-7000-8000-000000000057",
        "0199a000-0000-7000-8000-000000000056"
    ]
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 30,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-20",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000000038"
            },
            {
                "date": "2027-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2028-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2029-10-20",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000056",
                "text": "Check the renewal price"
            }
        ],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": true,
            "trouble_line": "Can't reach the registry at the moment."
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The steps field is required.",
    "errors": {
        "steps": [
            "The steps field is required."
        ]
    }
}
POST /commitments/{commitment}/skip Skip this occurrence and bring the next one on
Request and responseHide request and response
Field Type Needed What it means
commitment in the path id Yes The occurrence to skip.

On an occurrence, schedule.next_label is the label for the series’ next date, null for a series that does not take turns and once it has ended. schedule.following is the one after this occurrence, with its label. Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.”

shell
curl -X POST "https://allmyducks.app/api/v1/commitments/0199a000-0000-7000-8000-000000000038/skip" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "released",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "closed",
            "group": null
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2027-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": false,
            "can_change_steps": false,
            "can_change_project": true,
            "can_change_details": false
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "skipped",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the promiser receives: at_risk, dormant, quiet_days, module_trouble.

GET /templates The catalogue for your country and this workspace, with what is available
Request and responseHide request and response
Field Type Needed What it means
workspace in the query id Yes The workspace to check availability against.

Each entry carries words, the other words that find it, and common, its place among the six shown first for this workspace and your country (1 to 6), or null. A workspace key reads it for its own workspace only: any other id, or none, is refused, 403, with “This key only works inside its workspace.”

shell
curl -X GET "https://allmyducks.app/api/v1/templates?workspace=0199a000-0000-7000-8000-000000000014" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "key": "domain",
            "name": "Domain renewal",
            "group": "internet",
            "icon": "globe",
            "rule": {
                "every": "year"
            },
            "asks": [
                "month",
                "day"
            ],
            "lead_days": 30,
            "module": "domain",
            "module_date": "expiry",
            "available": true,
            "lookup": true,
            "input_label": "Domain name",
            "input_hint": "example.com",
            "about": "The expiry date, looked up from the domain.",
            "words": [
                "domain"
            ],
            "common": 4
        },
        {
            "key": "ssl",
            "name": "SSL certificate",
            "group": "internet",
            "icon": "padlock",
            "rule": {
                "every": "month",
                "interval": 3,
                "day": 1
            },
            "asks": [
                "from"
            ],
            "lead_days": 14,
            "module": "ssl",
            "module_date": "not_after",
            "available": true,
            "lookup": true,
            "input_label": "Hostname",
            "input_hint": "www.example.com",
            "about": "The certificate on a hostname, checked for you.",
            "words": [
                "ssl",
                "tls"
            ],
            "common": null
        },
        {
            "key": "subscription",
            "name": "Subscription",
            "group": "internet",
            "icon": "coin",
            "rule": {
                "every": "month",
                "day": 1
            },
            "asks": [
                "day"
            ],
            "lead_days": 3,
            "module": null,
            "module_date": null,
            "available": true,
            "lookup": false,
            "input_label": null,
            "input_hint": null,
            "about": "Anything that bills you on a day of the month.",
            "words": [
                "subscriptions"
            ],
            "common": null
        },
        {
            "key": "backups_check",
            "name": "Check the backups",
            "group": "internet",
            "icon": "server",
            "rule": {
                "every": "month",
                "day": 1
            },
            "asks": [
                "day"
            ],
            "lead_days": 3,
            "module": null,
            "module_date": null,
            "available": true,
            "lookup": false,
            "input_label": null,
            "input_hint": null,
            "about": "Open one and make sure it restores.",
            "words": [
                "test the backups",
                "restore test"
            ],
            "common": null
        },
        {
            "key": "password_rotation",
            "name": "Rotate passwords",
            "group": "internet",
            "icon": "key",
            "rule": {
                "every": "month",
                "interval": 3,
                "day": 1
            },
            "asks": [
                "from"
            ],
            "lead_days": 7,
            "module": null,
            "module_date": null,
            "available": true,
            "lookup": false,
            "input_label": null,
            "input_hint": null,
            "about": "The shared ones, every quarter.",
            "words": [
                "passwords",
                "password"
            ],
            "common": null
        },
        {
            "key": "vat_quarter_uk",
            "name": "VAT return",
            "group": "money",
            "icon": "coin",
            "rule": {
                "every": "month",
                "interval": 3,
                "day": 7
            },
            "asks": [
                "from"
            ],
            "lead_days": 21,
            "module": null,
            "module_date": null,
            "available": true,
            "lookup": false,
            "input_label": null,
            "input_hint": null,
            "about": "Due a month and seven days after the quarter ends. Set the first one.",
            "words": [
                "vat"
            ],
            "common": 6
        },
        {
            "key": "company_filings_uk",
            "name": "Confirmation statement",
            "group": "money",
            "icon": "building",
            "rule": {
                "every": "year"
            },
            "asks": [
                "month",
                "day"
            ],
            "lead_days": 30,
            "module": "uk_company",
            "module_date": "confirmation_statement",
            "available": true,
            "lookup": false,
            "input_label": null,
            "input_hint": "8 characters, on Companies House",
            "about": "Confirmation statement, from the company number.",
            "words": [],
            "common": null
        },
        {
            "key": "company_accounts_uk",
            "name": "Annual accounts",
            "group": "money",
            "icon": "building",
            "rule": {
                "every": "year"
            },
            "asks": [
                "month",
                "day"
            ],
            "lead_days": 30,
            "module": "uk_company",
            "module_date": "accounts",
            "available": true,
            "lookup": false,
            "input_label": null,
            "input_hint": "8 characters, on Companies House",
            "about": "Annual accounts, from the company number.",
            "words": [
                "company accounts"
            ],
            "common": null
        },
        {
            "key": "public_holiday",
            "name": "Public holiday",
            "group": "people",
            "icon": "gift",
            "rule": {
                "every": "year"
            },
            "asks": [
                "month",
                "day"
            ],
            "lead_days": 7,
            "module": "calendars",
            "module_date": "next_holiday",
            "available": true,
            "lookup": true,
            "input_label": "Where",
            "input_hint": null,
            "about": "The next one on your calendar, so plans are made in time.",
            "words": [
                "bank holiday"
            ],
            "common": null
        },
        {
            "key": "timesheet",
            "name": "Timesheet",
            "group": "rhythm",
            "icon": "repeat",
            "rule": {
                "every": "week",
                "weekday": 5
            },
            "asks": [
                "weekday"
            ],
            "lead_days": 7,
            "module": null,
            "module_date": null,
            "available": true,
            "lookup": false,
            "input_label": null,
            "input_hint": null,
            "about": "In by the end of the week.",
            "words": [
                "timesheets",
                "time sheet"
            ],
            "common": 2
        },
        {
            "key": "expenses",
            "name": "Expenses",
            "group": "rhythm",
            "icon": "coin",
            "rule": {
                "every": "month",
                "day": "last"
            },
            "asks": [
                "day"
            ],
            "lead_days": 7,
            "module": null,
            "module_date": null,
            "available": true,
            "lookup": false,
            "input_label": null,
            "input_hint": null,
            "about": "Claimed before the month closes.",
            "words": [
                "expense claim"
            ],
            "common": 3
        },
        {
            "key": "one_to_one",
            "name": "One to one",
            "group": "rhythm",
            "icon": "repeat",
            "rule": {
                "every": "week"
            },
            "asks": [
                "weekday"
            ],
            "lead_days": 7,
            "module": null,
            "module_date": null,
            "available": true,
            "lookup": false,
            "input_label": null,
            "input_hint": null,
            "about": "Prepared, not just attended.",
            "words": [
                "1:1",
                "one on one"
            ],
            "common": 1
        },
        {
            "key": "backups",
            "name": "Backups",
            "group": "rhythm",
            "icon": "server",
            "rule": {
                "every": "week",
                "weekday": 5
            },
            "asks": [
                "weekday"
            ],
            "lead_days": 7,
            "module": null,
            "module_date": null,
            "available": true,
            "lookup": false,
            "input_label": null,
            "input_hint": null,
            "about": "Taken, and somewhere else.",
            "words": [
                "backup",
                "back up"
            ],
            "common": 5
        },
        {
            "key": "custom",
            "name": "Something else",
            "group": "custom",
            "icon": "repeat",
            "rule": {
                "every": "week"
            },
            "asks": [
                "every",
                "weekday"
            ],
            "lead_days": 7,
            "module": null,
            "module_date": null,
            "available": true,
            "lookup": false,
            "input_label": null,
            "input_hint": null,
            "about": "Any name, any rhythm.",
            "words": [],
            "common": null
        }
    ]
}
POST /modules/{module}/identify Look something up the way the form does: a plate, a domain, a hostname, a company number
Request and responseHide request and response
Field Type Needed What it means
module in the path string Yes Which module to ask.
input string Yes The thing to look up: a plate, a domain, a hostname, a company number, whatever this module reads.

It answers 20 calls a minute.

An example request

json
{
    "input": "example.com"
}
shell
curl -X POST "https://allmyducks.app/api/v1/modules/domain/identify" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "input": "example.com"
}'

200, and this comes back

json
{
    "data": {
        "input": "example.com",
        "label": "example.com",
        "icon": "globe",
        "dates": [
            {
                "key": "expiry",
                "label": "Renewal due",
                "date": "2026-10-20"
            }
        ],
        "data": {
            "registrar": "Example Registrar"
        }
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The input field is required.",
    "errors": {
        "input": [
            "The input field is required."
        ]
    }
}
POST /schedules/{schedule}/refresh Check the source again now, once an hour
Request and responseHide request and response
Field Type Needed What it means
schedule in the path id Yes The series to check again.

The other party to a promise is refused, 403, with “Only the person this repeats for can change it.” Somebody who is only shown it is refused, 403, with “That’s Sam’s to change.” Somebody who cannot see the series at all is answered 404.

shell
curl -X POST "https://allmyducks.app/api/v1/schedules/0199a000-0000-7000-8000-000000000037/refresh" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 30,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-20",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000000038"
            },
            {
                "date": "2027-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2028-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2029-10-20",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000056",
                "text": "Check the renewal price"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            }
        ],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": false,
            "trouble_line": null
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

Only the owner has a value for: module.input, module.trouble, module.trouble_line.

GET /workspaces/{workspace}/calendar Projected dates for the month view: series and dates, never commitment rows
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to project.
from in the query date Yes The window’s start date.
to in the query date Yes The window’s end date, at most a year after from, and at most six weeks after it without the year view (Plus).
project in the query id Optional A project in this workspace: only the dates of series in it. One from anywhere else is refused with 422, and GET /calendar takes none.

Each row carries label, the rotation’s name for that date, or null for a series that does not take turns. A row is a date, so it never carries the item’s words. Past six weeks without the year view the window is refused, 402, with limit year_view; every month grid is within it.

shell
curl -X GET "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/calendar?from=2026-10-01&to=2026-10-31" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000042",
            "name": "Order the printer paper",
            "icon": "repeat",
            "date": "2026-10-07",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000042",
            "name": "Order the printer paper",
            "icon": "repeat",
            "date": "2026-10-14",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000042",
            "name": "Order the printer paper",
            "icon": "repeat",
            "date": "2026-10-21",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000042",
            "name": "Order the printer paper",
            "icon": "repeat",
            "date": "2026-10-28",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000046",
            "name": "Water the office plants",
            "icon": "repeat",
            "date": "2026-10-02",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000046",
            "name": "Water the office plants",
            "icon": "repeat",
            "date": "2026-10-09",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000046",
            "name": "Water the office plants",
            "icon": "repeat",
            "date": "2026-10-16",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000046",
            "name": "Water the office plants",
            "icon": "repeat",
            "date": "2026-10-23",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        },
        {
            "schedule_id": "0199a000-0000-7000-8000-000000000046",
            "name": "Water the office plants",
            "icon": "repeat",
            "date": "2026-10-30",
            "label": null,
            "project_id": null,
            "workspace": {
                "id": "0199a000-0000-7000-8000-000000000014",
                "name": "Acme",
                "type": "team",
                "colour": null
            }
        }
    ]
}

Projects

A project belongs to one workspace, and anyone in that workspace can list, make, rename, describe and delete its projects; anyone else is answered 404, as on every workspace route. A workspace key reaches only its own workspace’s projects. Something is put in a project, or taken out, with project_id on its own routes, by anyone on either side of it, and project narrows the feed and the calendar to one. Every commitment and every series carries a project object with its id, name and tag, or null.

EndpointWhat it does
GET /workspaces/{workspace}/projects Projects, in name order, each with whether it is done and what comes next for you
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace to list.

Not paginated: a workspace holds at most 100. done, empty and next are worked out from the items you can see, and nothing says how many items a project holds. empty is true when nothing in it is visible to you.

shell
curl -X GET "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/projects" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000058",
            "name": "Launch",
            "tag": "launch",
            "description": "Everything for the launch in October.",
            "done": false,
            "empty": false,
            "next": {
                "id": "0199a000-0000-7000-8000-000000000020",
                "description": "Send the launch copy",
                "due_date": "2026-10-15",
                "end_date": null,
                "due_time": null,
                "fyi": false
            }
        }
    ]
}
POST /workspaces/{workspace}/projects Make a project (anyone in the workspace)
Request and responseHide request and response
Field Type Needed What it means
workspace in the path id Yes The workspace the project belongs to.
name string Yes What people will call it, up to 60 characters, with a letter or a number in it. Its tag is the name lowercased with everything but letters and numbers taken out, and no two projects in a workspace share a tag.
description string Optional What it is for, up to 500 characters, line breaks kept.

Making a project comes with Plus; without it the call is refused, 402, with limit projects. A name already taken here, or a workspace that already holds 100, is refused with 422.

An example request

json
{
    "name": "Press kit",
    "description": "Logos, photos and the founders’ bios."
}
shell
curl -X POST "https://allmyducks.app/api/v1/workspaces/0199a000-0000-7000-8000-000000000014/projects" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Press kit",
    "description": "Logos, photos and the founders’ bios."
}'

201, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000900002",
        "name": "Press kit",
        "tag": "presskit",
        "description": "Logos, photos and the founders’ bios.",
        "done": false,
        "empty": true,
        "next": null
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "Give the project a name.",
    "errors": {
        "name": [
            "Give the project a name."
        ]
    }
}
GET /projects/{project} A project, with whether it is done and what comes next for you
Request and responseHide request and response
Field Type Needed What it means
project in the path id Yes The project to read.

empty is true when nothing in it is visible to you.

shell
curl -X GET "https://allmyducks.app/api/v1/projects/0199a000-0000-7000-8000-000000000058" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000058",
        "name": "Launch",
        "tag": "launch",
        "description": "Everything for the launch in October.",
        "done": false,
        "empty": false,
        "next": {
            "id": "0199a000-0000-7000-8000-000000000020",
            "description": "Send the launch copy",
            "due_date": "2026-10-15",
            "end_date": null,
            "due_time": null,
            "fyi": false
        }
    }
}
PATCH /projects/{project} Rename a project or change its description (anyone in the workspace)
Request and responseHide request and response
Field Type Needed What it means
project in the path id Yes The project to change.
name string Optional Its new name, by the same rules as making one. Left out, it stays as it is.
description string Optional Its new description, up to 500 characters. Null or an empty string clears it; left out, it stays as it is.

Works on any plan. A name already taken here is refused with 422, as are a name or a description that break the rules for making one.

An example request

json
{
    "name": "October launch"
}
shell
curl -X PATCH "https://allmyducks.app/api/v1/projects/0199a000-0000-7000-8000-000000000058" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "October launch"
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000058",
        "name": "October launch",
        "tag": "octoberlaunch",
        "description": "Everything for the launch in October.",
        "done": false,
        "empty": false,
        "next": {
            "id": "0199a000-0000-7000-8000-000000000020",
            "description": "Send the launch copy",
            "due_date": "2026-10-15",
            "end_date": null,
            "due_time": null,
            "fyi": false
        }
    }
}
DELETE /projects/{project} Delete a project (anyone in the workspace): everything in it stays, just out of the project
Request and responseHide request and response
Field Type Needed What it means
project in the path id Yes The project to delete.

Works on any plan. No item or series is deleted, changed or told; there is no undo.

shell
curl -X DELETE "https://allmyducks.app/api/v1/projects/0199a000-0000-7000-8000-000000000058" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {}
}

Descriptions

A todo, a promise or an ask can carry a description, and so can a series: a longer note on what it involves, kept apart from its wording. Send it as details on POST /workspaces/{workspace}/commitments, PATCH /commitments/{commitment}, POST /workspaces/{workspace}/schedules and PATCH /schedules/{schedule}. It is up to 10,000 characters as stored. Null or an empty string removes it, and left out it stays as it is. Every item and series carries details, the description as stored or null, for everyone who can see it.

It is Markdown, and the set is small: bold, italic, one level of heading, bulleted and numbered lists of one level, and links. Links are [text](address) or <address>, to http, https and mailto addresses only. Whatever you send is read to that set and written back in one form, on every write, so what comes back is the stored form. Saying what is already there in another spelling changes nothing and writes nothing.

Who can change it follows whose it is. On an item it is the asker while it is still an ask, the person doing it while it is active, and nobody once it has ended. On a series it is its owner, and on a series of asks someone has said yes to, the person who said yes while they are still in the team (or the workspace); otherwise the asker. Everyone who can see an item or a series can read its description. A body with only details on PATCH /schedules/{schedule} is open to either party to the series, and the series’ rule decides; with any other field it stays the owner’s. A refusal is 403, 409 or 422 (402 on the plan, below), with the reason in a sentence, and nothing in the body is written. viewer.can_change_details says whether you can, so a client never has to work it out.

Writing or changing one comes with Plus; without it the call is refused, 402, with limit details, and nothing is made or changed. Taking one away, and reading one, work on any plan. features.details on GET /plans and GET /me says whether a plan has it, and viewer.details_reason carries the sentence to show when you could change it and your plan has not.

Changing a description is not a transition and tells nobody. The timeline gets one line, details_changed, saying that it changed and never what it said, and webhooks get commitment.details_changed. A series has no timeline: a change to its description sends schedule.changed. On an item’s own read, details_changed is {by: {id, name}, at}, or null: who changed it last and when, never how often. A series carries the same in details_changed, and details_by names whose it is to change now. Only the parties to an item or a series are given the mark or the reason; somebody who is only shown it gets neither.

Webhooks

Tell us a URL and we will post what happens to it: a promise made, a date moved, something done. A webhook sees exactly what you see, through the same serializers this API answers with, so the signals only you can see stay only yours. Set one up in the app on the API and webhooks page, with your personal key, or with an OAuth token approved for webhooks. A workspace key can’t: it is shared between admins and outlives whoever made it, so a URL registered with one would be a URL nobody owns. A webhook stops delivering the moment the credential behind it goes: revoke the personal key that set it up, or disconnect the app that did, and it pauses and says so on the page. Turning it back on is a deliberate act, so reconnecting an app never restarts one by itself.

EndpointWhat it does
GET /webhooks Your subscriptions, newest first
Request and responseHide request and response

It takes nothing.

Subscriptions come with Plus. Without it they are kept and sent nothing, and each says so in paused_for_plan until Plus is back.

shell
curl -X GET "https://allmyducks.app/api/v1/webhooks" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000044",
            "url": "https://hooks.example.com/duck",
            "events": [
                "*"
            ],
            "workspace": null,
            "paused": false,
            "paused_for_plan": false,
            "created_at": "2026-10-01T09:00:00+00:00"
        }
    ]
}

If something is wrong

A workspace key answers 403. This key only works inside its workspace.

An app that was never given the webhooks permission answers 403. This app can’t manage webhooks: ask for that permission when you connect.

POST /webhooks Make a subscription: a URL, which events, and which workspace or every one you are in. The response carries the signing secret once
Request and responseHide request and response
Field Type Needed What it means
url string Yes Where events are delivered, by POST as JSON with a signature header. The response’s secret is shown once here and cannot be fetched again.
events array Yes Which event names to send, from GET /webhooks/events, or * for every one.
workspace_id id Optional One workspace to scope it to, or leave it out to cover every workspace you are in.

Without Plus the call is refused, 402, with limit integrations.

An example request

json
{
    "url": "https://hooks.example.com/duck",
    "events": [
        "commitment.created",
        "commitment.done"
    ],
    "workspace_id": "0199a000-0000-7000-8000-000000000014"
}
shell
curl -X POST "https://allmyducks.app/api/v1/webhooks" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.example.com/duck",
    "events": [
        "commitment.created",
        "commitment.done"
    ],
    "workspace_id": "0199a000-0000-7000-8000-000000000014"
}'

201, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000900002",
        "url": "https://hooks.example.com/duck",
        "events": [
            "commitment.created",
            "commitment.done"
        ],
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "paused": false,
        "paused_for_plan": false,
        "created_at": "2026-10-01T09:00:00+00:00",
        "secret": "55ffc4996d5cc1b8a4e5dc4c7ff4fbe29b8e08e14dda79f625f70ca707d34820"
    }
}

If something is wrong

A field missing or wrong answers 422.

json
{
    "message": "The url field is required. (and 1 more error)",
    "errors": {
        "url": [
            "The url field is required."
        ],
        "events": [
            "Pick at least one thing to send."
        ]
    }
}

A workspace key answers 403. This key only works inside its workspace.

An app that was never given the webhooks permission answers 403. This app can’t manage webhooks: ask for that permission when you connect.

GET /webhooks/events The catalogue: every event name, what it belongs to, and a line about it
Request and responseHide request and response

It takes nothing.

shell
curl -X GET "https://allmyducks.app/api/v1/webhooks/events" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "name": "commitment.created",
            "object": "commitment",
            "about": "Something was written down: a promise, a todo or an ask."
        },
        {
            "name": "commitment.accepted",
            "object": "commitment",
            "about": "An ask was taken on."
        },
        {
            "name": "commitment.countered",
            "object": "commitment",
            "about": "An ask was taken on with a different date."
        },
        {
            "name": "commitment.declined",
            "object": "commitment",
            "about": "Somebody said no to an ask."
        },
        {
            "name": "commitment.withdrawn",
            "object": "commitment",
            "about": "An ask was taken back."
        },
        {
            "name": "commitment.expired",
            "object": "commitment",
            "about": "An ask ran out before it was answered, or the day of something to know went by."
        },
        {
            "name": "commitment.done",
            "object": "commitment",
            "about": "Something was finished."
        },
        {
            "name": "commitment.reopened",
            "object": "commitment",
            "about": "Something finished was opened again."
        },
        {
            "name": "commitment.renegotiated",
            "object": "commitment",
            "about": "A new date was picked."
        },
        {
            "name": "commitment.redated",
            "object": "commitment",
            "about": "A lookup moved a date."
        },
        {
            "name": "commitment.release_asked",
            "object": "commitment",
            "about": "Somebody asked to drop a promise."
        },
        {
            "name": "commitment.released",
            "object": "commitment",
            "about": "A promise was dropped."
        },
        {
            "name": "commitment.kept",
            "object": "commitment",
            "about": "A promise stands as it is after a release ask."
        },
        {
            "name": "commitment.picked_up",
            "object": "commitment",
            "about": "A dropped promise was picked back up."
        },
        {
            "name": "commitment.reworded",
            "object": "commitment",
            "about": "The wording changed."
        },
        {
            "name": "commitment.noted",
            "object": "commitment",
            "about": "A note was added."
        },
        {
            "name": "commitment.deleted",
            "object": "commitment",
            "about": "A todo was deleted."
        },
        {
            "name": "commitment.restored",
            "object": "commitment",
            "about": "A deleted todo came back."
        },
        {
            "name": "commitment.visibility_changed",
            "object": "commitment",
            "about": "Who can see a todo changed, or it became something to know, or a task again."
        },
        {
            "name": "commitment.moved",
            "object": "commitment",
            "about": "A todo moved to another workspace."
        },
        {
            "name": "commitment.details_changed",
            "object": "commitment",
            "about": "The description changed."
        },
        {
            "name": "schedule.started",
            "object": "schedule",
            "about": "A series started."
        },
        {
            "name": "schedule.changed",
            "object": "schedule",
            "about": "A series changed: its name, its rhythm, its dates or its description."
        },
        {
            "name": "schedule.ended",
            "object": "schedule",
            "about": "A series ended."
        },
        {
            "name": "schedule.restarted",
            "object": "schedule",
            "about": "A series started again."
        },
        {
            "name": "schedule.deleted",
            "object": "schedule",
            "about": "A series was deleted."
        },
        {
            "name": "schedule.occurrence_opened",
            "object": "schedule",
            "about": "The next one in a series is here."
        },
        {
            "name": "schedule.occurrence_skipped",
            "object": "schedule",
            "about": "One in a series was skipped."
        },
        {
            "name": "schedule.moved",
            "object": "schedule",
            "about": "A series moved to another workspace."
        },
        {
            "name": "member.joined",
            "object": "member",
            "about": "Somebody joined a workspace."
        },
        {
            "name": "member.left",
            "object": "member",
            "about": "Somebody left a workspace."
        },
        {
            "name": "member.role_changed",
            "object": "member",
            "about": "Somebody’s role changed."
        },
        {
            "name": "workspace.renamed",
            "object": "workspace",
            "about": "A workspace was renamed."
        }
    ]
}

If something is wrong

A workspace key answers 403. This key only works inside its workspace.

An app that was never given the webhooks permission answers 403. This app can’t manage webhooks: ask for that permission when you connect.

GET /webhooks/{webhook} One subscription, without its secret
Request and responseHide request and response
Field Type Needed What it means
webhook in the path id Yes The subscription to show.
shell
curl -X GET "https://allmyducks.app/api/v1/webhooks/0199a000-0000-7000-8000-000000000044" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000044",
        "url": "https://hooks.example.com/duck",
        "events": [
            "*"
        ],
        "workspace": null,
        "paused": false,
        "paused_for_plan": false,
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

If something is wrong

A workspace key answers 403. This key only works inside its workspace.

An app that was never given the webhooks permission answers 403. This app can’t manage webhooks: ask for that permission when you connect.

PATCH /webhooks/{webhook} Change the address or what it sends, or pause and resume it
Request and responseHide request and response
Field Type Needed What it means
webhook in the path id Yes The subscription to change.
url string Optional Where events are delivered.
events array Optional Which event names to send, or * for every one.
paused boolean Optional Pause it, or turn it back on. Turning it back on is a fresh start: it forgets the failures that paused it.

Without Plus the call is refused, 402, with limit integrations.

An example request

json
{
    "url": "https://hooks.example.com/incoming",
    "events": [
        "commitment.done",
        "commitment.released"
    ]
}
shell
curl -X PATCH "https://allmyducks.app/api/v1/webhooks/0199a000-0000-7000-8000-000000000044" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.example.com/incoming",
    "events": [
        "commitment.done",
        "commitment.released"
    ]
}'

200, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000000044",
        "url": "https://hooks.example.com/incoming",
        "events": [
            "commitment.done",
            "commitment.released"
        ],
        "workspace": null,
        "paused": false,
        "paused_for_plan": false,
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}

If something is wrong

A workspace key answers 403. This key only works inside its workspace.

An app that was never given the webhooks permission answers 403. This app can’t manage webhooks: ask for that permission when you connect.

DELETE /webhooks/{webhook} Stop a subscription and remove its log
Request and responseHide request and response
Field Type Needed What it means
webhook in the path id Yes The subscription to stop.
shell
curl -X DELETE "https://allmyducks.app/api/v1/webhooks/0199a000-0000-7000-8000-000000000044" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

204, and no body.

If something is wrong

A workspace key answers 403. This key only works inside its workspace.

An app that was never given the webhooks permission answers 403. This app can’t manage webhooks: ask for that permission when you connect.

POST /webhooks/{webhook}/ping Send one test event, so you can see it arrive
Request and responseHide request and response
Field Type Needed What it means
webhook in the path id Yes The subscription to test.

Without Plus the call is refused, 402, with limit integrations.

shell
curl -X POST "https://allmyducks.app/api/v1/webhooks/0199a000-0000-7000-8000-000000000044/ping" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

202, and this comes back

json
{
    "data": {
        "id": "0199a000-0000-7000-8000-000000900002",
        "event": "ping",
        "status": "pending",
        "attempts": 0,
        "response_code": null,
        "occurred_at": "2026-10-01T09:00:00+00:00",
        "last_attempt_at": null,
        "delivered_at": null
    }
}

If something is wrong

A workspace key answers 403. This key only works inside its workspace.

An app that was never given the webhooks permission answers 403. This app can’t manage webhooks: ask for that permission when you connect.

GET /webhooks/{webhook}/deliveries The last fifty attempts, newest first: never what was sent
Request and responseHide request and response
Field Type Needed What it means
webhook in the path id Yes The subscription to show the log for.
shell
curl -X GET "https://allmyducks.app/api/v1/webhooks/0199a000-0000-7000-8000-000000000044/deliveries" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <your key>"

200, and this comes back

json
{
    "data": [
        {
            "id": "0199a000-0000-7000-8000-000000000045",
            "event": "commitment.done",
            "status": "delivered",
            "attempts": 1,
            "response_code": 200,
            "occurred_at": "2026-10-01T08:55:00+00:00",
            "last_attempt_at": "2026-10-01T08:55:00+00:00",
            "delivered_at": "2026-10-01T08:55:00+00:00"
        }
    ]
}

If something is wrong

A workspace key answers 403. This key only works inside its workspace.

An app that was never given the webhooks permission answers 403. This app can’t manage webhooks: ask for that permission when you connect.

Every delivery is a POST, signed and stamped with the event that caused it, carrying the object as this API answers you for it. Each event in the table below has a real delivery under it, headers and body.

X-Webhook-Signature: t=<unix seconds>,v1=<hex> is an HMAC-SHA256 of t and the raw body, hex-encoded. Recompute it over the raw body you read, compare with a constant-time check, and refuse anything whose t is more than five minutes from your own clock:

php
[$t, $v1] = sscanf($request->header('X-Webhook-Signature'), 't=%d,v1=%s');

abort_unless(
    abs(time() - $t) < 300
        && hash_equals(hash_hmac('sha256', $t.'.'.$request->getContent(), $secret), $v1),
    401,
);

Each request also carries an Idempotency-Key that stays the same across retries, so a second copy of one you have already handled is safe to ignore. We try six times: straight away, then after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours. Answer with any 2xx. After five deliveries in a row that never got a 2xx we pause the webhook and email you; turn it back on and the next event goes through. Redirects aren’t followed, and the address has to be https and reachable on the internet.

EventWhat it means
commitment.created Something was written down: a promise, a todo or an ask.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.created",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=fe5abf57ea64afea27a88c857d811542dbddfa0efc87d6a6bbfef81ae345485a"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.created",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.accepted An ask was taken on.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.accepted",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=f58ffc4b927cbb246b210f5643d54355a6302aaedd584d5014eb47e6967acca4"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.accepted",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.countered An ask was taken on with a different date.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.countered",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=d7e14f607a94aff49aebb3aa18f08475abb73fce41c1e7641ae2f66fa1273cf1"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.countered",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.declined Somebody said no to an ask.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.declined",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=e66bf38389d9e7f050d57a974599fa1881e6b7d6148116374190e6c811d1f65e"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.declined",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.withdrawn An ask was taken back.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.withdrawn",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=7e016b89dabcd771ecb65b3f5c37879adcb87ea961b800781d8e40de4cc01bbc"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.withdrawn",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.expired An ask ran out before it was answered, or the day of something to know went by.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.expired",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=47e808cf70318e7f44646260694b0675d04611b15b58446a84ae4f7742ec4644"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.expired",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.done Something was finished.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.done",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=bc58ee33920a8097f84f399f8ad6de63e3fc3a591ac9b312377ab09d6c3eb97c"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.done",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.reopened Something finished was opened again.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.reopened",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=5014351a16f48110335dbc3d57acd8e6fa48cf79078f182a1a997e6a765c6853"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.reopened",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.renegotiated A new date was picked.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.renegotiated",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=90fc246fb8847b131f46d0441affbb190065e606078d9ffe2d805e0e87a39574"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.renegotiated",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.redated A lookup moved a date.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.redated",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=8e0a1d88fd15e55d3654b73ba6b1208d44e61aa60381f63b15085631bfd038ea"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.redated",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.release_asked Somebody asked to drop a promise.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.release_asked",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=a0fbbb875c1f1bf339ecaefcd306647b4a0d39d18fa276271597ab2ae3c8ed9c"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.release_asked",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.released A promise was dropped.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.released",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=a123bd52ca39c6bdb6b4b2be303fad2c12b2c7670e1c999f36a7baffbe796e64"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.released",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.kept A promise stands as it is after a release ask.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.kept",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=f8aef0673ce8ab01bba6bfa06b4c4cc1237e4da9b849931353976aa95444752f"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.kept",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.picked_up A dropped promise was picked back up.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.picked_up",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=6dfce433759afbf70ba45e0bf1c07a91f765d81f80e284d5ac60ad749b1cc95d"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.picked_up",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.reworded The wording changed.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.reworded",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=f9566bbdbe98641529680f4b56a1a3607b4bfbc075a320626e4d76c46afd74c8"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.reworded",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.noted A note was added.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.noted",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=762f83210410c10f22c2e8705ad2fd8c81f63a00a54135aa131abb3086349523"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.noted",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.deleted A todo was deleted.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.deleted",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=a90ba4cd749d6b62033d022ff0206162bd43ffd43f685e4ac946a2497a13e610"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.deleted",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000036",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Cancel the old launch invite",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": "2026-10-06",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": false,
            "can_change_project": false,
            "can_change_details": false
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.restored A deleted todo came back.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.restored",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=9aabdd54cb6761cc0c2636d1304ca3923814b762c3dc6da0d016f9c0f535db16"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.restored",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.visibility_changed Who can see a todo changed, or it became something to know, or a task again.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.visibility_changed",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=751f43753bd750790902084128de1fc594385ed1327dbabd65e8563739d971b3"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.visibility_changed",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "chosen",
        "seen_by": [
            {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000003",
                "name": "Sam Okafor"
            },
            {
                "type": "team",
                "id": "0199a000-0000-7000-8000-000000000015",
                "name": "Launch crew"
            }
        ],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.moved A todo moved to another workspace.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.moved",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900002",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900002",
    "X-Webhook-Signature": "t=1790845200,v1=26b2027bf8b07620093368cb804d1ac9fd668bbc8be86301b6f8430c0878df0e"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900002",
    "event": "commitment.moved",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000013",
        "name": "Home",
        "type": "home",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000041",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000013",
            "name": "Home",
            "type": "home",
            "colour": null
        },
        "project": null,
        "description": "Order the launch stickers",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "manual",
        "due_date": null,
        "end_date": null,
        "due_timezone": null,
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "no_date_yet"
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            },
            {
                "type": "moved",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": {
                    "name": "Acme",
                    "type": "team"
                },
                "to_workspace": {
                    "name": "Home",
                    "type": "home"
                },
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
commitment.details_changed The description changed.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "commitment.details_changed",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=4c628271be7d46c8550dff34252397bfa135e5d89ec78d644a87118a9d48a0c6"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "commitment.details_changed",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
schedule.started A series started.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "schedule.started",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=3076e592e6df1f8c19df8adf5368d692504aad0e676be646029f7ca3f1324876"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "schedule.started",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 30,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-20",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000000038"
            },
            {
                "date": "2027-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2028-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2029-10-20",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000056",
                "text": "Check the renewal price"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            }
        ],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": true,
            "trouble_line": "Can't reach the registry at the moment."
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
schedule.changed A series changed: its name, its rhythm, its dates or its description.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "schedule.changed",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=327a5b4c4a8491e24fec0d1e512c82359d795d19acb53019bf12c3e9594331c5"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "schedule.changed",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 30,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-20",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000000038"
            },
            {
                "date": "2027-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2028-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2029-10-20",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000056",
                "text": "Check the renewal price"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            }
        ],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": true,
            "trouble_line": "Can't reach the registry at the moment."
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
schedule.ended A series ended.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "schedule.ended",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=79c12479e5b1edd96f36ebb108b357141719e8884fa8ef481a605874cfdcb1a1"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "schedule.ended",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 30,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-20",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000000038"
            },
            {
                "date": "2027-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2028-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2029-10-20",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000056",
                "text": "Check the renewal price"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            }
        ],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": true,
            "trouble_line": "Can't reach the registry at the moment."
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
schedule.restarted A series started again.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "schedule.restarted",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=6558f02cf88e549f5600023cf98f5abcfabd4052a4c7a3afa103c77b55ad6de5"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "schedule.restarted",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 30,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-20",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000000038"
            },
            {
                "date": "2027-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2028-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2029-10-20",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000056",
                "text": "Check the renewal price"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            }
        ],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": true,
            "trouble_line": "Can't reach the registry at the moment."
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
schedule.deleted A series was deleted.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "schedule.deleted",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=6f7d3f941f895520316ee8846405073c6e3e95e7f5e25ac2e90521bd34c0156d"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "schedule.deleted",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000037",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "domain",
        "icon": "globe",
        "name": "Renew example.com",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "year",
            "day": 20,
            "month": 10,
            "interval": 1
        },
        "rule_words": "Every year on 20 October",
        "lead_days": 30,
        "next_due_date": "2026-10-20",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-20",
                "label": null,
                "occurrence_id": "0199a000-0000-7000-8000-000000000038"
            },
            {
                "date": "2027-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2028-10-20",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2029-10-20",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [
            {
                "id": "0199a000-0000-7000-8000-000000000056",
                "text": "Check the renewal price"
            },
            {
                "id": "0199a000-0000-7000-8000-000000000057",
                "text": "Update the card on file"
            }
        ],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": "0199a000-0000-7000-8000-000000000038",
        "completions": [],
        "module": {
            "key": "domain",
            "input": "example.com",
            "label": "example.com",
            "icon": "globe",
            "refreshed_at": "2026-10-01T09:00:00+00:00",
            "dates": [
                {
                    "key": "expiry",
                    "label": "Renewal due",
                    "date": "2026-10-20"
                }
            ],
            "trouble": true,
            "trouble_line": "Can't reach the registry at the moment."
        },
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
schedule.occurrence_opened The next one in a series is here.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "schedule.occurrence_opened",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=5a2f84886c27b6c6b207c926b9c9b038ec0ba271f6ea4868b3548700dd78cddf"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "schedule.occurrence_opened",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
schedule.occurrence_skipped One in a series was skipped.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "schedule.occurrence_skipped",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=d3653dc877fa711c9eedb14aefe9afe9ada78954b80d8e501bdc2456e66d9f30"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "schedule.occurrence_skipped",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000038",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000014",
            "name": "Acme",
            "type": "team",
            "colour": null
        },
        "project": null,
        "description": "Renew example.com",
        "details": null,
        "details_changed": null,
        "state": "active",
        "source": "schedule",
        "due_date": "2026-10-20",
        "end_date": null,
        "due_timezone": "Europe/London",
        "due_time": null,
        "due_at": null,
        "is_private": true,
        "visibility": "workspace",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "release_requested": false,
        "request_expires_at": null,
        "is_slipped": false,
        "in_grace_window": false,
        "grace_closed": false,
        "at_risk": false,
        "dormant": false,
        "quiet_days": 0,
        "placement": {
            "list": "yours_to_do",
            "group": "coming_up"
        },
        "module_trouble": "Can't reach the registry at the moment.",
        "schedule": {
            "id": "0199a000-0000-7000-8000-000000000037",
            "template": "domain",
            "icon": "globe",
            "rule_words": "Every year on 20 October",
            "next_due_date": "2026-10-20",
            "next_label": null,
            "following": {
                "date": "2027-10-20",
                "label": null
            },
            "occurrence_no": 1,
            "ended": false
        },
        "viewer": {
            "is_promiser": true,
            "is_promisee": true,
            "can_reword": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "promiser": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "email": "[email protected]",
                "avatar_url": null,
                "active": true
            },
            "asked_team": null
        },
        "events": [
            {
                "type": "created",
                "actor": {
                    "id": "0199a000-0000-7000-8000-000000000001",
                    "name": "Alex Rivera"
                },
                "message": null,
                "reason": null,
                "team": null,
                "from": null,
                "to": null,
                "source": null,
                "from_workspace": null,
                "to_workspace": null,
                "created_at": "2026-10-01T09:00:00+00:00"
            }
        ],
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
schedule.moved A series moved to another workspace.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "schedule.moved",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900002",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900002",
    "X-Webhook-Signature": "t=1790845200,v1=5e59a0b859df091a98a317f4a701f54acf2856942c887b2b2d99fd1a7ac7a511"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900002",
    "event": "schedule.moved",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000013",
        "name": "Home",
        "type": "home",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000042",
        "workspace": {
            "id": "0199a000-0000-7000-8000-000000000013",
            "name": "Home",
            "type": "home",
            "colour": null
        },
        "project": null,
        "kind": "todo",
        "template": "custom",
        "icon": "repeat",
        "name": "Order the printer paper",
        "details": null,
        "details_changed": null,
        "details_by": {
            "id": "0199a000-0000-7000-8000-000000000001",
            "name": "Alex Rivera"
        },
        "rule": {
            "every": "week",
            "weekday": 3,
            "interval": 1
        },
        "rule_words": "Every week on Wednesday",
        "lead_days": 0,
        "next_due_date": "2026-10-07",
        "next_due_timezone": "Europe/London",
        "upcoming": [
            {
                "date": "2026-10-07",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2026-10-14",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2026-10-21",
                "label": null,
                "occurrence_id": null
            },
            {
                "date": "2026-10-28",
                "label": null,
                "occurrence_id": null
            }
        ],
        "is_private": true,
        "visibility": "owner",
        "seen_by": [],
        "fyi": false,
        "steps": [],
        "ended_at": null,
        "viewer": {
            "is_owner": true,
            "can_change_steps": true,
            "can_add_step": true,
            "step_limit_reason": null,
            "can_change_project": true,
            "can_change_details": true
        },
        "parties": {
            "owner": {
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            },
            "promisee": {
                "type": "user",
                "id": "0199a000-0000-7000-8000-000000000001",
                "name": "Alex Rivera",
                "avatar_url": null
            }
        },
        "open_occurrence_id": null,
        "completions": [],
        "module": null,
        "created_at": "2026-10-01T09:00:00+00:00"
    }
}
member.joined Somebody joined a workspace.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "member.joined",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=f4cc353f8becbb0f7898f096f5e42c48e80dfe040072ab49508ac62de3455d77"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "member.joined",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000003",
        "name": "Sam Okafor",
        "email": "[email protected]",
        "avatar_url": null,
        "role": "member"
    }
}
member.left Somebody left a workspace.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "member.left",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=d3387ce9040cbd05c30cac31df8179aea09c3e258b4d19840cf67f2eeebf2c7c"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "member.left",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000007",
        "name": "Robin Shaw",
        "email": "[email protected]",
        "avatar_url": null,
        "role": null
    }
}
member.role_changed Somebody’s role changed.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "member.role_changed",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=f3205ec041cb8ff483052d430266a4f0292a0ee87b6c710bb480fe68fbf09d2b"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "member.role_changed",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000003",
        "name": "Sam Okafor",
        "email": "[email protected]",
        "avatar_url": null,
        "role": "member"
    }
}
workspace.renamed A workspace was renamed.
Show example deliveryHide example delivery

The headers it arrives with

json
{
    "Content-Type": "application/json",
    "Accept": "application/json",
    "User-Agent": "All My Ducks webhooks",
    "X-Webhook-Event": "workspace.renamed",
    "X-Webhook-Id": "0199a000-0000-7000-8000-000000900001",
    "Idempotency-Key": "0199a000-0000-7000-8000-000000900001",
    "X-Webhook-Signature": "t=1790845200,v1=f886736d2a80ec5497b70653fa7f754cc973ef764484ad6a466145c1df93e2b1"
}

The body they were signed over

json
{
    "id": "0199a000-0000-7000-8000-000000900001",
    "event": "workspace.renamed",
    "occurred_at": "2026-10-01T09:00:00+00:00",
    "workspace": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null
    },
    "data": {
        "id": "0199a000-0000-7000-8000-000000000014",
        "name": "Acme",
        "type": "team",
        "colour": null,
        "slack_connected": false,
        "ai_enabled": true,
        "capture_enabled": false
    }
}

There is no event for a private signal: the quiet heads-up about a date still ahead, and the prompts about something that has gone quiet, are the promiser’s alone and leave the app through no door.

Before anyone is signed in

These routes need no key. Each one is rate limited.

EndpointWhat it does
GET /special-days The special days from one date to another, each date with the theme it wears
Request and responseHide request and response
Field Type Needed What it means
from in the query date Optional The first date, as YYYY-MM-DD. Leave it out for today: in your profile’s time zone when a person is asking, otherwise in timezone, otherwise in UTC.
to in the query date Optional The last date, on or after from and at most 400 days from it. Leave it out for from alone.
timezone in the query string Optional A time zone name such as Europe/London, used only when no person is asking: a person’s own profile time zone always governs. A name it does not know is ignored.
country in the query string Optional A two-letter country code (ISO 3166-1) from GET /countries, in any case, whose national days to include. A country with no national days, or anything else, is ignored, and without it the answer uses your profile’s country when it has national days, then your time zone’s.
joined_on in the query date Optional A date, as YYYY-MM-DD, to stand in for the joining date whose anniversary the answer shows.

It answers 60 calls a minute.

Only dates with a special day are listed, so a date or range with none answers {"data": []}.

No key needed. A key is accepted too. With a personal key, an app’s token or the app’s own session, the answer follows your profile: its time zone, and its country when that country has national days. A workspace key is answered as no key is.

shell
curl -X GET "https://allmyducks.app/api/v1/special-days?from=2026-12-20&to=2026-12-31" \
  -H "Accept: application/json"

200, and this comes back

json
{
    "data": [
        {
            "date": "2026-12-21",
            "theme": "wintersolstice",
            "days": [
                {
                    "name": "December solstice",
                    "about": "The shortest day of the year in the northern hemisphere and the longest in the south. At Newgrange in Ireland, built five thousand years ago, the rising sun lights the inner chamber for a few minutes on this morning alone."
                }
            ]
        },
        {
            "date": "2026-12-24",
            "theme": "christmas",
            "days": [
                {
                    "name": "Christmas Eve",
                    "about": "The evening before Christmas, and in much of Europe and Latin America the main event: the big meal and the presents come tonight, not tomorrow. The carol Silent Night was first sung on this evening in 1818, in a village church near Salzburg, to a guitar because the organ was out of action."
                }
            ]
        },
        {
            "date": "2026-12-25",
            "theme": "christmas",
            "days": [
                {
                    "name": "Christmas Day",
                    "about": "The Christian festival of the birth of Jesus, and a public holiday in much of the world. The earliest record of it being kept on 25 December is in Rome in the year 336. Christmas cards date from 1843, the same year as A Christmas Carol."
                }
            ]
        },
        {
            "date": "2026-12-26",
            "theme": "boxingday",
            "days": [
                {
                    "name": "Boxing Day",
                    "about": "The day after Christmas, and St Stephen’s Day in the church calendar. The name comes from the Christmas box: the gift of money or leftovers given to servants, tradespeople and the poor on their day off after serving on the day itself. Today it is a holiday across Britain, Ireland, Australia, Canada and New Zealand, known for its sales and for the Boxing Day cricket Test in Melbourne."
                }
            ]
        },
        {
            "date": "2026-12-31",
            "theme": "newyear",
            "days": [
                {
                    "name": "New Year’s Eve",
                    "about": "The last day of the year, seen out with fireworks and a countdown to midnight. The Times Square ball has dropped every year since 1907, except for two wartime blackouts. Auld Lang Syne is a Scots song written down by Robert Burns in 1788."
                }
            ]
        }
    ]
}
GET /countries Every country a person can say they live in: its two-letter code, its name in English, and other names it goes by
Request and responseHide request and response

It takes nothing.

It answers 60 calls a minute.

No key needed. A key is accepted too.

shell
curl -X GET "https://allmyducks.app/api/v1/countries" \
  -H "Accept: application/json"

200, and this comes back

json
{
    "data": [
        {
            "code": "AF",
            "name": "Afghanistan",
            "aliases": []
        },
        {
            "code": "AX",
            "name": "Åland Islands",
            "aliases": []
        },
        {
            "code": "AL",
            "name": "Albania",
            "aliases": []
        },
        {
            "code": "DZ",
            "name": "Algeria",
            "aliases": []
        },
        {
            "code": "AS",
            "name": "American Samoa",
            "aliases": [
                "Samoa (American)"
            ]
        },
        {
            "code": "AD",
            "name": "Andorra",
            "aliases": []
        },
        {
            "code": "AO",
            "name": "Angola",
            "aliases": []
        },
        {
            "code": "AI",
            "name": "Anguilla",
            "aliases": []
        },
        {
            "code": "AQ",
            "name": "Antarctica",
            "aliases": []
        },
        {
            "code": "AG",
            "name": "Antigua & Barbuda",
            "aliases": []
        },
        {
            "code": "AR",
            "name": "Argentina",
            "aliases": []
        },
        {
            "code": "AM",
            "name": "Armenia",
            "aliases": []
        },
        {
            "code": "AW",
            "name": "Aruba",
            "aliases": []
        },
        {
            "code": "AU",
            "name": "Australia",
            "aliases": []
        },
        {
            "code": "AT",
            "name": "Austria",
            "aliases": []
        },
        {
            "code": "AZ",
            "name": "Azerbaijan",
            "aliases": []
        },
        {
            "code": "BS",
            "name": "Bahamas",
            "aliases": []
        },
        {
            "code": "BH",
            "name": "Bahrain",
            "aliases": []
        },
        {
            "code": "BD",
            "name": "Bangladesh",
            "aliases": []
        },
        {
            "code": "BB",
            "name": "Barbados",
            "aliases": []
        },
        {
            "code": "BY",
            "name": "Belarus",
            "aliases": []
        },
        {
            "code": "BE",
            "name": "Belgium",
            "aliases": []
        },
        {
            "code": "BZ",
            "name": "Belize",
            "aliases": []
        },
        {
            "code": "BJ",
            "name": "Benin",
            "aliases": []
        },
        {
            "code": "BM",
            "name": "Bermuda",
            "aliases": []
        },
        {
            "code": "BT",
            "name": "Bhutan",
            "aliases": []
        },
        {
            "code": "BO",
            "name": "Bolivia",
            "aliases": []
        },
        {
            "code": "BA",
            "name": "Bosnia & Herzegovina",
            "aliases": []
        },
        {
            "code": "BW",
            "name": "Botswana",
            "aliases": []
        },
        {
            "code": "BV",
            "name": "Bouvet Island",
            "aliases": []
        },
        {
            "code": "BR",
            "name": "Brazil",
            "aliases": []
        },
        {
            "code": "IO",
            "name": "British Indian Ocean Territory",
            "aliases": []
        },
        {
            "code": "VG",
            "name": "British Virgin Islands",
            "aliases": [
                "Virgin Islands (UK)"
            ]
        },
        {
            "code": "BN",
            "name": "Brunei",
            "aliases": []
        },
        {
            "code": "BG",
            "name": "Bulgaria",
            "aliases": []
        },
        {
            "code": "BF",
            "name": "Burkina Faso",
            "aliases": []
        },
        {
            "code": "BI",
            "name": "Burundi",
            "aliases": []
        },
        {
            "code": "KH",
            "name": "Cambodia",
            "aliases": []
        },
        {
            "code": "CM",
            "name": "Cameroon",
            "aliases": []
        },
        {
            "code": "CA",
            "name": "Canada",
            "aliases": []
        },
        {
            "code": "CV",
            "name": "Cape Verde",
            "aliases": []
        },
        {
            "code": "BQ",
            "name": "Caribbean Netherlands",
            "aliases": [
                "Caribbean NL"
            ]
        },
        {
            "code": "KY",
            "name": "Cayman Islands",
            "aliases": []
        },
        {
            "code": "CF",
            "name": "Central African Republic",
            "aliases": [
                "Central African Rep."
            ]
        },
        {
            "code": "TD",
            "name": "Chad",
            "aliases": []
        },
        {
            "code": "CL",
            "name": "Chile",
            "aliases": []
        },
        {
            "code": "CN",
            "name": "China",
            "aliases": []
        },
        {
            "code": "CX",
            "name": "Christmas Island",
            "aliases": []
        },
        {
            "code": "CC",
            "name": "Cocos (Keeling) Islands",
            "aliases": []
        },
        {
            "code": "CO",
            "name": "Colombia",
            "aliases": []
        },
        {
            "code": "KM",
            "name": "Comoros",
            "aliases": []
        },
        {
            "code": "CG",
            "name": "Congo - Brazzaville",
            "aliases": [
                "Congo (Rep.)"
            ]
        },
        {
            "code": "CD",
            "name": "Congo - Kinshasa",
            "aliases": [
                "Congo (Dem. Rep.)"
            ]
        },
        {
            "code": "CK",
            "name": "Cook Islands",
            "aliases": []
        },
        {
            "code": "CR",
            "name": "Costa Rica",
            "aliases": []
        },
        {
            "code": "CI",
            "name": "Côte d’Ivoire",
            "aliases": []
        },
        {
            "code": "HR",
            "name": "Croatia",
            "aliases": []
        },
        {
            "code": "CU",
            "name": "Cuba",
            "aliases": []
        },
        {
            "code": "CW",
            "name": "Curaçao",
            "aliases": []
        },
        {
            "code": "CY",
            "name": "Cyprus",
            "aliases": []
        },
        {
            "code": "CZ",
            "name": "Czechia",
            "aliases": [
                "Czech Republic"
            ]
        },
        {
            "code": "DK",
            "name": "Denmark",
            "aliases": []
        },
        {
            "code": "DJ",
            "name": "Djibouti",
            "aliases": []
        },
        {
            "code": "DM",
            "name": "Dominica",
            "aliases": []
        },
        {
            "code": "DO",
            "name": "Dominican Republic",
            "aliases": []
        },
        {
            "code": "EC",
            "name": "Ecuador",
            "aliases": []
        },
        {
            "code": "EG",
            "name": "Egypt",
            "aliases": []
        },
        {
            "code": "SV",
            "name": "El Salvador",
            "aliases": []
        },
        {
            "code": "GQ",
            "name": "Equatorial Guinea",
            "aliases": []
        },
        {
            "code": "ER",
            "name": "Eritrea",
            "aliases": []
        },
        {
            "code": "EE",
            "name": "Estonia",
            "aliases": []
        },
        {
            "code": "SZ",
            "name": "Eswatini",
            "aliases": [
                "Swaziland"
            ]
        },
        {
            "code": "ET",
            "name": "Ethiopia",
            "aliases": []
        },
        {
            "code": "FK",
            "name": "Falkland Islands",
            "aliases": []
        },
        {
            "code": "FO",
            "name": "Faroe Islands",
            "aliases": []
        },
        {
            "code": "FJ",
            "name": "Fiji",
            "aliases": []
        },
        {
            "code": "FI",
            "name": "Finland",
            "aliases": []
        },
        {
            "code": "FR",
            "name": "France",
            "aliases": []
        },
        {
            "code": "GF",
            "name": "French Guiana",
            "aliases": []
        },
        {
            "code": "PF",
            "name": "French Polynesia",
            "aliases": []
        },
        {
            "code": "TF",
            "name": "French Southern Territories",
            "aliases": [
                "French S. Terr."
            ]
        },
        {
            "code": "GA",
            "name": "Gabon",
            "aliases": []
        },
        {
            "code": "GM",
            "name": "Gambia",
            "aliases": []
        },
        {
            "code": "GE",
            "name": "Georgia",
            "aliases": []
        },
        {
            "code": "DE",
            "name": "Germany",
            "aliases": []
        },
        {
            "code": "GH",
            "name": "Ghana",
            "aliases": []
        },
        {
            "code": "GI",
            "name": "Gibraltar",
            "aliases": []
        },
        {
            "code": "GR",
            "name": "Greece",
            "aliases": []
        },
        {
            "code": "GL",
            "name": "Greenland",
            "aliases": []
        },
        {
            "code": "GD",
            "name": "Grenada",
            "aliases": []
        },
        {
            "code": "GP",
            "name": "Guadeloupe",
            "aliases": []
        },
        {
            "code": "GU",
            "name": "Guam",
            "aliases": []
        },
        {
            "code": "GT",
            "name": "Guatemala",
            "aliases": []
        },
        {
            "code": "GG",
            "name": "Guernsey",
            "aliases": []
        },
        {
            "code": "GN",
            "name": "Guinea",
            "aliases": []
        },
        {
            "code": "GW",
            "name": "Guinea-Bissau",
            "aliases": []
        },
        {
            "code": "GY",
            "name": "Guyana",
            "aliases": []
        },
        {
            "code": "HT",
            "name": "Haiti",
            "aliases": []
        },
        {
            "code": "HM",
            "name": "Heard & McDonald Islands",
            "aliases": [
                "Heard Island & McDonald Islands"
            ]
        },
        {
            "code": "HN",
            "name": "Honduras",
            "aliases": []
        },
        {
            "code": "HK",
            "name": "Hong Kong SAR China",
            "aliases": [
                "Hong Kong"
            ]
        },
        {
            "code": "HU",
            "name": "Hungary",
            "aliases": []
        },
        {
            "code": "IS",
            "name": "Iceland",
            "aliases": []
        },
        {
            "code": "IN",
            "name": "India",
            "aliases": []
        },
        {
            "code": "ID",
            "name": "Indonesia",
            "aliases": []
        },
        {
            "code": "IR",
            "name": "Iran",
            "aliases": []
        },
        {
            "code": "IQ",
            "name": "Iraq",
            "aliases": []
        },
        {
            "code": "IE",
            "name": "Ireland",
            "aliases": []
        },
        {
            "code": "IM",
            "name": "Isle of Man",
            "aliases": []
        },
        {
            "code": "IL",
            "name": "Israel",
            "aliases": []
        },
        {
            "code": "IT",
            "name": "Italy",
            "aliases": []
        },
        {
            "code": "JM",
            "name": "Jamaica",
            "aliases": []
        },
        {
            "code": "JP",
            "name": "Japan",
            "aliases": []
        },
        {
            "code": "JE",
            "name": "Jersey",
            "aliases": []
        },
        {
            "code": "JO",
            "name": "Jordan",
            "aliases": []
        },
        {
            "code": "KZ",
            "name": "Kazakhstan",
            "aliases": []
        },
        {
            "code": "KE",
            "name": "Kenya",
            "aliases": []
        },
        {
            "code": "KI",
            "name": "Kiribati",
            "aliases": []
        },
        {
            "code": "KW",
            "name": "Kuwait",
            "aliases": []
        },
        {
            "code": "KG",
            "name": "Kyrgyzstan",
            "aliases": []
        },
        {
            "code": "LA",
            "name": "Laos",
            "aliases": []
        },
        {
            "code": "LV",
            "name": "Latvia",
            "aliases": []
        },
        {
            "code": "LB",
            "name": "Lebanon",
            "aliases": []
        },
        {
            "code": "LS",
            "name": "Lesotho",
            "aliases": []
        },
        {
            "code": "LR",
            "name": "Liberia",
            "aliases": []
        },
        {
            "code": "LY",
            "name": "Libya",
            "aliases": []
        },
        {
            "code": "LI",
            "name": "Liechtenstein",
            "aliases": []
        },
        {
            "code": "LT",
            "name": "Lithuania",
            "aliases": []
        },
        {
            "code": "LU",
            "name": "Luxembourg",
            "aliases": []
        },
        {
            "code": "MO",
            "name": "Macao SAR China",
            "aliases": [
                "Macau"
            ]
        },
        {
            "code": "MG",
            "name": "Madagascar",
            "aliases": []
        },
        {
            "code": "MW",
            "name": "Malawi",
            "aliases": []
        },
        {
            "code": "MY",
            "name": "Malaysia",
            "aliases": []
        },
        {
            "code": "MV",
            "name": "Maldives",
            "aliases": []
        },
        {
            "code": "ML",
            "name": "Mali",
            "aliases": []
        },
        {
            "code": "MT",
            "name": "Malta",
            "aliases": []
        },
        {
            "code": "MH",
            "name": "Marshall Islands",
            "aliases": []
        },
        {
            "code": "MQ",
            "name": "Martinique",
            "aliases": []
        },
        {
            "code": "MR",
            "name": "Mauritania",
            "aliases": []
        },
        {
            "code": "MU",
            "name": "Mauritius",
            "aliases": []
        },
        {
            "code": "YT",
            "name": "Mayotte",
            "aliases": []
        },
        {
            "code": "MX",
            "name": "Mexico",
            "aliases": []
        },
        {
            "code": "FM",
            "name": "Micronesia",
            "aliases": []
        },
        {
            "code": "MD",
            "name": "Moldova",
            "aliases": []
        },
        {
            "code": "MC",
            "name": "Monaco",
            "aliases": []
        },
        {
            "code": "MN",
            "name": "Mongolia",
            "aliases": []
        },
        {
            "code": "ME",
            "name": "Montenegro",
            "aliases": []
        },
        {
            "code": "MS",
            "name": "Montserrat",
            "aliases": []
        },
        {
            "code": "MA",
            "name": "Morocco",
            "aliases": []
        },
        {
            "code": "MZ",
            "name": "Mozambique",
            "aliases": []
        },
        {
            "code": "MM",
            "name": "Myanmar (Burma)",
            "aliases": []
        },
        {
            "code": "NA",
            "name": "Namibia",
            "aliases": []
        },
        {
            "code": "NR",
            "name": "Nauru",
            "aliases": []
        },
        {
            "code": "NP",
            "name": "Nepal",
            "aliases": []
        },
        {
            "code": "NL",
            "name": "Netherlands",
            "aliases": [
                "Holland"
            ]
        },
        {
            "code": "NC",
            "name": "New Caledonia",
            "aliases": []
        },
        {
            "code": "NZ",
            "name": "New Zealand",
            "aliases": []
        },
        {
            "code": "NI",
            "name": "Nicaragua",
            "aliases": []
        },
        {
            "code": "NE",
            "name": "Niger",
            "aliases": []
        },
        {
            "code": "NG",
            "name": "Nigeria",
            "aliases": []
        },
        {
            "code": "NU",
            "name": "Niue",
            "aliases": []
        },
        {
            "code": "NF",
            "name": "Norfolk Island",
            "aliases": []
        },
        {
            "code": "KP",
            "name": "North Korea",
            "aliases": [
                "Korea (North)"
            ]
        },
        {
            "code": "MK",
            "name": "North Macedonia",
            "aliases": []
        },
        {
            "code": "MP",
            "name": "Northern Mariana Islands",
            "aliases": []
        },
        {
            "code": "NO",
            "name": "Norway",
            "aliases": []
        },
        {
            "code": "OM",
            "name": "Oman",
            "aliases": []
        },
        {
            "code": "PK",
            "name": "Pakistan",
            "aliases": []
        },
        {
            "code": "PW",
            "name": "Palau",
            "aliases": []
        },
        {
            "code": "PS",
            "name": "Palestinian Territories",
            "aliases": [
                "Palestine"
            ]
        },
        {
            "code": "PA",
            "name": "Panama",
            "aliases": []
        },
        {
            "code": "PG",
            "name": "Papua New Guinea",
            "aliases": []
        },
        {
            "code": "PY",
            "name": "Paraguay",
            "aliases": []
        },
        {
            "code": "PE",
            "name": "Peru",
            "aliases": []
        },
        {
            "code": "PH",
            "name": "Philippines",
            "aliases": []
        },
        {
            "code": "PN",
            "name": "Pitcairn Islands",
            "aliases": [
                "Pitcairn"
            ]
        },
        {
            "code": "PL",
            "name": "Poland",
            "aliases": []
        },
        {
            "code": "PT",
            "name": "Portugal",
            "aliases": []
        },
        {
            "code": "PR",
            "name": "Puerto Rico",
            "aliases": []
        },
        {
            "code": "QA",
            "name": "Qatar",
            "aliases": []
        },
        {
            "code": "RE",
            "name": "Réunion",
            "aliases": []
        },
        {
            "code": "RO",
            "name": "Romania",
            "aliases": []
        },
        {
            "code": "RU",
            "name": "Russia",
            "aliases": []
        },
        {
            "code": "RW",
            "name": "Rwanda",
            "aliases": []
        },
        {
            "code": "WS",
            "name": "Samoa",
            "aliases": []
        },
        {
            "code": "SM",
            "name": "San Marino",
            "aliases": []
        },
        {
            "code": "ST",
            "name": "São Tomé & Príncipe",
            "aliases": [
                "Sao Tome & Principe"
            ]
        },
        {
            "code": "SA",
            "name": "Saudi Arabia",
            "aliases": []
        },
        {
            "code": "SN",
            "name": "Senegal",
            "aliases": []
        },
        {
            "code": "RS",
            "name": "Serbia",
            "aliases": []
        },
        {
            "code": "SC",
            "name": "Seychelles",
            "aliases": []
        },
        {
            "code": "SL",
            "name": "Sierra Leone",
            "aliases": []
        },
        {
            "code": "SG",
            "name": "Singapore",
            "aliases": []
        },
        {
            "code": "SX",
            "name": "Sint Maarten",
            "aliases": [
                "St Maarten (Dutch)"
            ]
        },
        {
            "code": "SK",
            "name": "Slovakia",
            "aliases": []
        },
        {
            "code": "SI",
            "name": "Slovenia",
            "aliases": []
        },
        {
            "code": "SB",
            "name": "Solomon Islands",
            "aliases": []
        },
        {
            "code": "SO",
            "name": "Somalia",
            "aliases": []
        },
        {
            "code": "ZA",
            "name": "South Africa",
            "aliases": []
        },
        {
            "code": "GS",
            "name": "South Georgia & South Sandwich Islands",
            "aliases": [
                "South Georgia & the South Sandwich Islands"
            ]
        },
        {
            "code": "KR",
            "name": "South Korea",
            "aliases": [
                "Korea (South)"
            ]
        },
        {
            "code": "SS",
            "name": "South Sudan",
            "aliases": []
        },
        {
            "code": "ES",
            "name": "Spain",
            "aliases": []
        },
        {
            "code": "LK",
            "name": "Sri Lanka",
            "aliases": []
        },
        {
            "code": "BL",
            "name": "St. Barthélemy",
            "aliases": [
                "St Barthelemy"
            ]
        },
        {
            "code": "SH",
            "name": "St. Helena",
            "aliases": []
        },
        {
            "code": "KN",
            "name": "St. Kitts & Nevis",
            "aliases": []
        },
        {
            "code": "LC",
            "name": "St. Lucia",
            "aliases": []
        },
        {
            "code": "MF",
            "name": "St. Martin",
            "aliases": [
                "St Martin (French)"
            ]
        },
        {
            "code": "PM",
            "name": "St. Pierre & Miquelon",
            "aliases": []
        },
        {
            "code": "VC",
            "name": "St. Vincent & Grenadines",
            "aliases": [
                "St Vincent"
            ]
        },
        {
            "code": "SD",
            "name": "Sudan",
            "aliases": []
        },
        {
            "code": "SR",
            "name": "Suriname",
            "aliases": []
        },
        {
            "code": "SJ",
            "name": "Svalbard & Jan Mayen",
            "aliases": []
        },
        {
            "code": "SE",
            "name": "Sweden",
            "aliases": []
        },
        {
            "code": "CH",
            "name": "Switzerland",
            "aliases": []
        },
        {
            "code": "SY",
            "name": "Syria",
            "aliases": []
        },
        {
            "code": "TW",
            "name": "Taiwan",
            "aliases": []
        },
        {
            "code": "TJ",
            "name": "Tajikistan",
            "aliases": []
        },
        {
            "code": "TZ",
            "name": "Tanzania",
            "aliases": []
        },
        {
            "code": "TH",
            "name": "Thailand",
            "aliases": []
        },
        {
            "code": "TL",
            "name": "Timor-Leste",
            "aliases": [
                "East Timor"
            ]
        },
        {
            "code": "TG",
            "name": "Togo",
            "aliases": []
        },
        {
            "code": "TK",
            "name": "Tokelau",
            "aliases": []
        },
        {
            "code": "TO",
            "name": "Tonga",
            "aliases": []
        },
        {
            "code": "TT",
            "name": "Trinidad & Tobago",
            "aliases": []
        },
        {
            "code": "TN",
            "name": "Tunisia",
            "aliases": []
        },
        {
            "code": "TR",
            "name": "Türkiye",
            "aliases": [
                "Turkey"
            ]
        },
        {
            "code": "TM",
            "name": "Turkmenistan",
            "aliases": []
        },
        {
            "code": "TC",
            "name": "Turks & Caicos Islands",
            "aliases": [
                "Turks & Caicos Is"
            ]
        },
        {
            "code": "TV",
            "name": "Tuvalu",
            "aliases": []
        },
        {
            "code": "UM",
            "name": "U.S. Outlying Islands",
            "aliases": [
                "US minor outlying islands"
            ]
        },
        {
            "code": "VI",
            "name": "U.S. Virgin Islands",
            "aliases": [
                "Virgin Islands (US)"
            ]
        },
        {
            "code": "UG",
            "name": "Uganda",
            "aliases": []
        },
        {
            "code": "UA",
            "name": "Ukraine",
            "aliases": []
        },
        {
            "code": "AE",
            "name": "United Arab Emirates",
            "aliases": [
                "UAE"
            ]
        },
        {
            "code": "GB",
            "name": "United Kingdom",
            "aliases": [
                "UK",
                "Great Britain",
                "Britain",
                "England",
                "Scotland",
                "Wales",
                "Northern Ireland"
            ]
        },
        {
            "code": "US",
            "name": "United States",
            "aliases": [
                "USA",
                "America",
                "United States of America"
            ]
        },
        {
            "code": "UY",
            "name": "Uruguay",
            "aliases": []
        },
        {
            "code": "UZ",
            "name": "Uzbekistan",
            "aliases": []
        },
        {
            "code": "VU",
            "name": "Vanuatu",
            "aliases": []
        },
        {
            "code": "VA",
            "name": "Vatican City",
            "aliases": []
        },
        {
            "code": "VE",
            "name": "Venezuela",
            "aliases": []
        },
        {
            "code": "VN",
            "name": "Vietnam",
            "aliases": []
        },
        {
            "code": "WF",
            "name": "Wallis & Futuna",
            "aliases": []
        },
        {
            "code": "EH",
            "name": "Western Sahara",
            "aliases": []
        },
        {
            "code": "YE",
            "name": "Yemen",
            "aliases": []
        },
        {
            "code": "ZM",
            "name": "Zambia",
            "aliases": []
        },
        {
            "code": "ZW",
            "name": "Zimbabwe",
            "aliases": []
        }
    ]
}
GET /sign-in-options Which ways to sign in are switched on besides an email address: Google and Apple
Request and responseHide request and response

It takes nothing.

What comes back, under data

Field Type What it means
google boolean Whether Continue with Google is on.
apple boolean Whether Sign in with Apple is on.

It answers 60 calls a minute.

A sign-in page shows a button only for a way that is on, and names Apple nowhere while apple is false.

No key needed. A key is accepted too.

shell
curl -X GET "https://allmyducks.app/api/v1/sign-in-options" \
  -H "Accept: application/json"

200, and this comes back

json
{
    "data": {
        "google": true,
        "apple": true
    }
}
GET /plans Every plan’s limits and features, and every price in every currency
Request and responseHide request and response

It takes nothing.

What comes back, under data

Field Type What it means
free object Free’s limits (open_tasks, steps, home_people) and features (year_view, calendar_feed, integrations, each true or false).
plus object Plus’s limits and features, as Free’s, and its prices: month and year, each an amount in every currency.
team object The bands a team plan comes in: each band’s seats, the most people it has room for, and its prices, as Plus’s.
currencies array The currencies every price is given in, the one shown by default first.
contact string The address a team of more than the largest band writes to for a plan of its own.

It answers 60 calls a minute.

Amounts are in each currency’s smallest unit and include tax: 399 in usd is $3.99.

No key needed. A key is accepted too.

shell
curl -X GET "https://allmyducks.app/api/v1/plans" \
  -H "Accept: application/json"

200, and this comes back

json
{
    "data": {
        "free": {
            "limits": {
                "open_tasks": 30,
                "steps": 5,
                "home_people": 2
            },
            "features": {
                "year_view": false,
                "calendar_feed": false,
                "integrations": false,
                "projects": false,
                "details": false
            }
        },
        "plus": {
            "limits": {
                "open_tasks": 500,
                "steps": 100,
                "home_people": 6
            },
            "features": {
                "year_view": true,
                "calendar_feed": true,
                "integrations": true,
                "projects": true,
                "details": true
            },
            "prices": {
                "month": {
                    "usd": 399,
                    "gbp": 299,
                    "eur": 349
                },
                "year": {
                    "usd": 3999,
                    "gbp": 2999,
                    "eur": 3499
                }
            }
        },
        "team": {
            "bands": [
                {
                    "seats": 10,
                    "prices": {
                        "month": {
                            "usd": 3999,
                            "gbp": 2999,
                            "eur": 3499
                        },
                        "year": {
                            "usd": 39999,
                            "gbp": 29999,
                            "eur": 34999
                        }
                    }
                },
                {
                    "seats": 25,
                    "prices": {
                        "month": {
                            "usd": 7999,
                            "gbp": 5999,
                            "eur": 6999
                        },
                        "year": {
                            "usd": 79999,
                            "gbp": 59999,
                            "eur": 69999
                        }
                    }
                }
            ]
        },
        "currencies": [
            "usd",
            "gbp",
            "eur"
        ],
        "contact": "[email protected]"
    }
}

What a key can never do

Keys can’t create or revoke other keys: that stays in the app, signed in. And the privacy boundaries hold: signals only the promiser sees in the app (at-risk, quiet nudges) never appear in API responses to anyone else, key or no key.