{"openapi":"3.1.0","info":{"version":"2.0.0","title":"TaskRatchet API","description":"The public TaskRatchet API (v2). Set tasks with monetary stakes — miss the deadline and you are charged.\n\n**Rate limiting:** requests to `/api2/*` are limited to 60 per 10 seconds at the edge (Cloudflare); exceeding the limit returns HTTP 429."},"servers":[{"url":"https://api.taskratchet.com","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A Clerk session token (`Authorization: Bearer <token>`) or a TaskRatchet API key (`Authorization: ApiKey-v2 <token>`). Generate an API key under **API Token** on your account [Settings](https://app.taskratchet.com/settings) page."}},"schemas":{"ErrorResponse":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"UserOutput":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"timezone":{"type":"string"},"referral_source":{"type":"string"},"notification_preferences":{"type":"object","additionalProperties":{"type":"object","properties":{"enabled":{"type":"boolean"}},"additionalProperties":{}}},"integrations":{"type":"object","properties":{"beeminder":{"type":"object","properties":{"user":{"type":"string"},"goal_new_tasks":{"type":"string"}},"required":["user","goal_new_tasks"]}}},"has_stripe_customer":{"type":"boolean"},"has_calendar_token":{"type":"boolean"},"monthly_stake_limit_cents":{"type":["integer","null"],"minimum":0,"description":"Cap, in cents, on the total stakes of tasks created in a calendar month (UTC), counted regardless of whether those tasks were completed. Defaults to 20000 ($200). Enforced when a task is created — including recurring generation and Todoist import — which is rejected or skipped if it would push the month past the cap, and again when a task’s stake is raised, against the month that task was created in. `null` means no limit. Distinct from `monthly_charge_limit_cents`, which governs the account charge endpoint."},"monthly_charge_limit_cents":{"type":["integer","null"],"minimum":0,"description":"Cap, in cents, on the total successfully charged through `POST /me/charges` in a calendar month (UTC). Defaults to 10000 ($100). `0` disables that endpoint outright; `null` means no limit. Distinct from `monthly_stake_limit_cents`, which governs stakes on tasks — charges made here do not count against the stake limit, or vice versa."}},"required":["id","email","integrations","has_stripe_customer","has_calendar_token"]},"UserUpdate":{"type":"object","properties":{"email":{"type":"string"},"referral_source":{"type":"string","description":"How the user says they heard about TaskRatchet, captured once on the mandatory post-signup screen. Free text — the client sends either a fixed option label or, for \"Other\", whatever the user typed."},"monthly_stake_limit_cents":{"type":["integer","null"],"minimum":0,"description":"Cap, in cents, on the total stakes of tasks created in a calendar month (UTC), counted regardless of whether those tasks were completed. Defaults to 20000 ($200). Enforced when a task is created — including recurring generation and Todoist import — which is rejected or skipped if it would push the month past the cap, and again when a task’s stake is raised, against the month that task was created in. `null` means no limit. Distinct from `monthly_charge_limit_cents`, which governs the account charge endpoint."},"monthly_charge_limit_cents":{"type":["integer","null"],"minimum":0,"description":"Cap, in cents, on the total successfully charged through `POST /me/charges` in a calendar month (UTC). Defaults to 10000 ($100). `0` disables that endpoint outright; `null` means no limit. Distinct from `monthly_stake_limit_cents`, which governs stakes on tasks — charges made here do not count against the stake limit, or vice versa."},"name":{"type":"string"},"timezone":{"type":"string"},"email_global_unsubscribe":{"type":"boolean"},"notification_preferences":{"type":"object","additionalProperties":{"type":"object","properties":{"enabled":{"type":"boolean"}},"additionalProperties":{}}},"telegramReminders":{"type":"boolean"},"checkout_session_id":{"type":"string"},"beeminder_user":{"type":"string"},"beeminder_token":{"type":"string"},"beeminder_goal_new_tasks":{"type":"string"}},"additionalProperties":false,"minProperties":1},"IntegrationsOutput":{"type":"object","properties":{"integrations":{"type":"array","items":{"$ref":"#/components/schemas/Integration"}}},"required":["integrations"]},"Integration":{"type":"object","properties":{"id":{"type":"string"},"connected":{"type":"boolean"},"config":{"type":"object","additionalProperties":{"type":"string"}}},"required":["id","connected","config"]},"IntegrationItemsOutput":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationItem"}}},"required":["items"]},"IntegrationItem":{"type":"object","properties":{"source":{"type":"string","example":"beeminder"},"id":{"type":"string","description":"Identifies this occurrence of the item, unique within its source. Beeminder ids are `slug/losedate` — a goal that re-emergencies later is a new occurrence.","example":"dial/1752633540"},"title":{"type":"string"},"due":{"type":"integer","description":"Deadline as Unix seconds."},"pledge":{"type":"number","description":"Beeminder only: dollars currently pledged on the goal. Informational — stakes are never inferred from it."}},"required":["source","id","title","due"]},"TodoistConnect":{"type":"object","properties":{"code":{"type":"string","minLength":1},"redirect_uri":{"type":"string","format":"uri"}},"required":["code","redirect_uri"],"additionalProperties":false},"IntegrationUpdate":{"type":"object","properties":{"config":{"type":"object","additionalProperties":{"type":"string"}}},"required":["config"],"additionalProperties":false},"OAuthGrantsOutput":{"type":"object","properties":{"grants":{"type":"array","items":{"$ref":"#/components/schemas/OAuthGrant"}}},"required":["grants"]},"OAuthGrant":{"type":"object","properties":{"client_id":{"type":"string"},"client_name":{"type":["string","null"]},"scopes":{"type":"array","items":{"$ref":"#/components/schemas/OAuthGrantScope"}},"granted_at":{"type":"number"}},"required":["client_id","client_name","scopes","granted_at"]},"OAuthGrantScope":{"type":"object","properties":{"scope":{"type":"string"},"description":{"type":"string"}},"required":["scope","description"]},"TaskOutput":{"type":"object","properties":{"id":{"type":"string"},"task":{"type":"string"},"due":{"type":"number"},"created":{"type":"number","description":"Creation time, Unix seconds. Present on every task the API returns, including the one returned by `POST /me/tasks`."},"cents":{"type":"number"},"complete":{"type":"boolean"},"status":{"type":"string","enum":["pending","complete","expired"]},"chargeStatus":{"type":"string","enum":["notified","authorized","captured"]},"contested":{"type":"boolean"}},"required":["id","task","due","created","cents","complete","status"]},"TaskInput":{"type":"object","properties":{"task":{"type":"string","minLength":1},"due":{"type":"number"},"cents":{"type":"number","minimum":100},"recurrence":{"type":"object","properties":{"days":{"type":"integer","minimum":1}},"required":["days"]},"pulled_from":{"type":"object","properties":{"source":{"type":"string","minLength":1,"maxLength":64},"id":{"type":"string","minLength":1,"maxLength":255}},"required":["source","id"],"additionalProperties":false}},"required":["task","due","cents"],"additionalProperties":false},"TaskUpdateUser":{"type":"object","properties":{"due":{"type":"integer","exclusiveMinimum":0},"cents":{"type":"integer","minimum":100,"maximum":10000000},"complete":{"type":"boolean"},"uncle":{"type":"boolean"}},"additionalProperties":false,"minProperties":1},"AccountChargeOutput":{"type":"object","properties":{"id":{"type":"string"},"cents":{"type":"number"},"note":{"type":["string","null"]},"status":{"type":"string","enum":["succeeded","failed"]},"created":{"type":"number"}},"required":["id","cents","note","status","created"],"additionalProperties":false},"AccountChargeInput":{"type":"object","properties":{"cents":{"type":"integer","minimum":100,"maximum":10000000},"note":{"type":"string","maxLength":500},"requestid":{"type":"string","minLength":1,"maxLength":255},"dryrun":{"type":"boolean"}},"required":["cents"],"additionalProperties":false},"RecurringTask":{"type":"object","properties":{"id":{"type":"string"},"task":{"type":"string"},"last_due":{"type":"number"},"cents":{"type":"number"},"recurrence":{"type":"object","properties":{"days":{"type":"integer","minimum":1}},"required":["days"]}},"required":["id","task","last_due","cents","recurrence"]},"CheckoutSession":{"type":"object","properties":{"id":{"type":"string","example":"cs_test_a1b2c3"},"url":{"type":"string","example":"https://checkout.stripe.com/c/pay/cs_test_a1b2c3"}},"required":["id","url"]},"CheckoutSessionInput":{"type":"object","properties":{"success_url":{"type":"string","maxLength":2048,"format":"uri","example":"https://app.taskratchet.com/payment/success"},"cancel_url":{"type":"string","maxLength":2048,"format":"uri","example":"https://app.taskratchet.com/payment/cancel"}},"required":["success_url","cancel_url"]}},"parameters":{}},"paths":{"/api2/calendar/{token}":{"get":{"tags":["calendar"],"summary":"Public iCal feed of pending task deadlines","description":"An iCalendar (RFC 5545) feed of the token holder's pending TaskRatchet deadlines, for subscribing in a calendar app.","security":[],"parameters":[{"schema":{"type":"string","example":"a1b2c3d4e5f6","description":"The opaque calendar integration token. A trailing `.ics` is accepted and ignored."},"required":true,"description":"The opaque calendar integration token. A trailing `.ics` is accepted and ignored.","name":"token","in":"path"}],"responses":{"200":{"description":"The user's pending deadlines as an iCalendar document.","content":{"text/calendar":{"schema":{"type":"string","example":"BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//TaskRatchet//TaskRatchet//EN\r\nEND:VCALENDAR\r\n"}}}},"404":{"description":"No calendar integration matches the token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"The feed could not be generated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api2/me":{"get":{"tags":["me"],"summary":"Get the authenticated user's profile","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The authenticated user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserOutput"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."}}},"put":{"tags":["me"],"summary":"Update the authenticated user's profile","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdate"}}}},"responses":{"200":{"description":"The updated user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserOutput"}}}},"400":{"description":"Malformed or empty JSON request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."},"404":{"description":"The user no longer exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request body failed validation (or had no fields).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["me"],"summary":"Delete the authenticated user and all their data","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deletion confirmation (\"ok\").","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."}}}},"/api2/me/token":{"post":{"tags":["me"],"summary":"Generate (or regenerate) the caller’s API token","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The newly generated API token.","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."}}},"get":{"tags":["me"],"summary":"Get the caller’s current API token","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The caller’s API token.","content":{"text/plain":{"schema":{"type":"string"}}}},"400":{"description":"No API token has been generated for this user yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."}}}},"/api2/me/calendar-token":{"post":{"tags":["me"],"summary":"Generate (or regenerate) the caller’s calendar feed token","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The newly generated calendar token.","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."}}},"get":{"tags":["me"],"summary":"Get the caller’s calendar feed token","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The caller’s calendar token.","content":{"text/plain":{"schema":{"type":"string"}}}},"400":{"description":"No calendar token has been generated for this user yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."}}}},"/api2/me/integrations":{"get":{"tags":["me"],"summary":"List the caller's third-party integrations","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The caller’s integrations and their public config.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationsOutput"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."}}}},"/api2/me/integrations/items":{"get":{"tags":["me"],"summary":"List external items that can be pulled in as tasks","description":"Items from the caller’s connected integrations that are candidates for becoming tasks. Beeminder: goals derailing within the next 7 days. Todoist: open tasks due within the next 7 days. Each source is sorted soonest first. Items already linked to a task — pulled in previously, or auto-imported — are hidden. Sources the caller hasn’t connected — or that fail upstream — are simply absent from the list.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The pull-in candidates across connected integrations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationItemsOutput"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."}}}},"/api2/me/integrations/todoist/connect":{"post":{"tags":["me"],"summary":"Complete the Todoist OAuth connect flow","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoistConnect"}}}},"responses":{"200":{"description":"The connected Todoist integration.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Integration"}}}},"400":{"description":"Malformed JSON request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."},"404":{"description":"The user no longer exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request body failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api2/me/integrations/{id}":{"put":{"tags":["me"],"summary":"Merge config into an integration","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"todoist"},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationUpdate"}}}},"responses":{"200":{"description":"The updated integration.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Integration"}}}},"400":{"description":"Unknown/blank config key(s), or a malformed request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."},"404":{"description":"Unknown integration, or the user no longer exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request body failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["me"],"summary":"Clear an integration's stored config","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"todoist"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"The integration after its config was cleared.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Integration"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."},"404":{"description":"Unknown integration, or the user no longer exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api2/me/oauth-grants":{"get":{"tags":["me"],"summary":"List the caller's connected apps (active OAuth grants)","description":"#1280 revocation UX: third-party OAuth clients the caller has granted access to, with the scopes they were granted and when.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The caller’s active OAuth grants.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthGrantsOutput"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."}}}},"/api2/me/oauth-grants/{client_id}":{"delete":{"tags":["me"],"summary":"Revoke a connected app's access","description":"Invalidates the grant and every outstanding refresh token issued under it, so the client can no longer mint new access tokens. Its current access token (a stateless JWT, short-lived — see oauth/index.ts) keeps working until it naturally expires.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"client_id","in":"path"}],"responses":{"200":{"description":"Revocation confirmation (\"ok\").","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."},"404":{"description":"No active grant for that client_id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api2/me/tasks":{"get":{"tags":["me"],"summary":"List the caller's tasks","description":"Returns a page of the caller’s tasks, newest `due` first by default. For incremental polling use `sort=created`, which orders by creation time descending — unlike `due`, that ordering is monotonic with creation, so a consumer that stops at its last-seen task id does not skip tasks whose deadline happens to sort them below its watermark. `created_after` (Unix seconds, inclusive) narrows the window to tasks created at or after a timestamp. One caveat for pollers: a page holds 20 tasks unless `limit` says otherwise. `limit` is clamped rather than rejected — above 100 is capped at 100, non-positive is lifted to 1, and an unusable value falls back to 20 — so a bad page size never 400s. A consumer that may fall further behind than one page must therefore also walk `page` until it reaches its watermark.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":["number","null"],"minimum":0,"example":0},"required":false,"name":"page","in":"query"},{"schema":{"type":"string","enum":["pending","complete","expired"]},"required":false,"name":"status","in":"query"},{"schema":{"type":["number","null"],"minimum":0},"required":false,"name":"due_before","in":"query"},{"schema":{"type":["number","null"],"minimum":0},"required":false,"name":"due_after","in":"query"},{"schema":{"type":["number","null"],"minimum":0},"required":false,"name":"created_after","in":"query"},{"schema":{"type":"string","enum":["due","created"]},"required":false,"name":"sort","in":"query"},{"schema":{"type":["number","null"],"example":20},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"The caller’s tasks.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TaskOutput"}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."}}},"post":{"tags":["me"],"summary":"Create a task","description":"Creates a task with a stake (`cents`, minimum 100) due at a Unix timestamp. Optionally set `recurrence.days` to repeat it. Note: the recurrence feature is incomplete and likely buggy — use it at your own risk. Set `pulled_from` when creating the task from an integration item (see `GET /me/integrations/items`) so the item is hidden from future listings.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskInput"}}}},"responses":{"200":{"description":"The created task.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskOutput"}}}},"400":{"description":"Malformed or empty JSON request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."},"409":{"description":"The `pulled_from` item was already pulled in as another task.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Request body failed validation, or the monthly stake limit would be exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api2/me/tasks/{task_id}":{"get":{"tags":["me"],"summary":"Get one of the caller’s tasks","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"task_id","in":"path"}],"responses":{"200":{"description":"The requested task.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskOutput"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."},"404":{"description":"No task with that id belongs to the caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"put":{"tags":["me"],"summary":"Edit a task's stake, deadline, completion, or uncle (forfeit)","description":"Edits a task. You can only make a task harder: the stake (`cents`) can only be increased, the deadline (`due`) can only be moved earlier, and an expired task cannot be marked complete. Raising the stake also answers to `monthly_stake_limit_cents`, measured against the month the task was created in. Set `uncle: true` to forfeit it. At least one field is required.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"task_id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskUpdateUser"}}}},"responses":{"200":{"description":"The updated task.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskOutput"}}}},"400":{"description":"Malformed JSON request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."},"404":{"description":"No task with that id belongs to the caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Invalid update — empty body, an unknown field, an out-of-range stake/deadline, an edit that violates the stake/deadline/completion rules, or a stake increase that would exceed the monthly stake limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api2/me/tasks/{task_id}/uncle":{"post":{"tags":["me"],"summary":"Give up on a task (uncle) and accept the charge","description":"Gives up on a task early (\"cries uncle\"), starting the charge flow before the deadline: it sends the charge-notification email and begins the charge. Can only be called once per task — returns 409 if the task is already uncled or its charge has already been initiated.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"task_id","in":"path"}],"responses":{"200":{"description":"Confirmation (\"ok\").","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."},"404":{"description":"No task with that id belongs to the caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The task is already uncled, or its charge was initiated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api2/me/charges":{"post":{"tags":["me"],"summary":"Charge the caller via the API","description":"Charges the caller’s saved card an arbitrary amount, independent of any task — for external integrations that impose their own penalties. The charge is captured immediately: no authorization window and no advance warning email; a receipt email follows a successful charge. Bounded by the caller’s monthly_charge_limit_cents (default $100/month; `0` disables the endpoint; `null` is uncapped — set via PUT /api2/me), summed over successful charges in the calendar month. Pass a unique `requestid` to make retries idempotent: a repeat with the same `requestid` returns the original charge instead of charging again. Use `dryrun: true` to validate without charging.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountChargeInput"}}}},"responses":{"200":{"description":"The recorded account charge.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountChargeOutput"}}}},"400":{"description":"Malformed JSON body, or no payment method on file.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or unparseable Authorization header."},"402":{"description":"The payment could not be completed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authorization header present but the caller could not be resolved."},"409":{"description":"Another charge is already in progress.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Invalid body, or the monthly charge limit would be exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api2/me/recurring":{"get":{"tags":["me"],"summary":"List the caller's recurring tasks","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":["number","null"],"minimum":0,"example":0},"required":false,"name":"page","in":"query"}],"responses":{"200":{"description":"The caller’s recurring tasks.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RecurringTask"}}}}},"400":{"description":"Invalid query parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."}}}},"/api2/me/recurring/{recurring_id}":{"delete":{"tags":["me"],"summary":"Delete a recurring task","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"recurring_id","in":"path"}],"responses":{"200":{"description":"Deletion confirmation (\"success\").","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."},"404":{"description":"No such recurring task for this caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api2/payments/checkout/session":{"post":{"tags":["payments"],"summary":"Create a Stripe Checkout session","description":"Creates a Stripe Checkout session the caller can use to add or update a payment method.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSessionInput"}}}},"responses":{"200":{"description":"The created Checkout session id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSession"}}}},"400":{"description":"Malformed JSON request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or unparseable Authorization header."},"403":{"description":"Authorization header present but the caller could not be resolved."},"422":{"description":"Request body failed schema validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"webhooks":{}}