Skip to content

API v2

WARNING

This version of the API is in active development. The API and its associated documentation are likely to be incomplete and/or incorrect, and may change without notice.

Authentication

To use the TaskRatchet API, you need an API key. This key is used to authenticate your requests and is required for all endpoints.

Example request with API key:

bash
curl "https://api.taskratchet.com/api2/me" \
  -H "Authorization: ApiKey-v2 YOUR_API_V2_TOKEN"

Please reach out to support@taskratchet.com to get an API key.

Rate Limiting

Rate limiting is handled at the edge by Cloudflare. Limits are configured per route pattern:

  • /api2/*: 60 requests per 10 seconds

Rate-limited requests receive HTTP 429 (Too Many Requests) responses.

Schema

Base URL: https://api.taskratchet.com/api2/

EndpointDescription
GET /api2/meGet your profile data
PUT /api2/meUpdate your profile
DELETE /api2/meDelete your account
GET /api2/me/tasksGet all your tasks
POST /api2/me/tasksCreate a new task
GET /api2/me/tasks/:task_idGet a single task
PUT /api2/me/tasks/:task_idUpdate a task
POST /api2/me/tasks/:task_id/uncleGive up on a task and trigger charge
GET /api2/me/recurringGet your recurring tasks
DELETE /api2/me/recurring/:recurring_idStop a recurring task
POST /api2/me/tokenReset your API v2 token
GET /api2/me/tokenGet your API v2 token
POST /api2/me/calendar-tokenGenerate/regenerate your calendar feed token
GET /api2/me/calendar-tokenGet your calendar feed token
GET /api2/calendar/:token.icsPublic iCal feed of task deadlines (no auth)
GET /api2/health/stripeStripe connectivity probe (public, no auth)

GET /api2/me

Response FieldTypeDescription
idstringThe account's unique identifier
namestringUser's full name (optional)
emailstringUser's email address
timezonestringDeprecated. User's IANA timezone (optional)
integrationsobjectUser's integration settings; currently only Beeminder
has_stripe_customerbooleanWhether the user has a Stripe customer account
has_calendar_tokenbooleanWhether the user has generated a calendar feed token
monthly_stake_limit_centsnumber | nullPer-user monthly stake cap in cents, or null if no limit is set
monthly_charge_limit_centsnumber | nullPer-user monthly cap (in cents) on charges via POST /api2/me/charges, or null for no limit

Example response:

json
{
  "id": "Zu0qDVncIgSuUbQfr261",
  "name": "Jon Doe",
  "email": "jon@doe.com",
  "timezone": "America/New_York",
  "integrations": {
    "beeminder": {
      "user": "jondoe",
      "goal_new_tasks": "tr_tasks"
    }
  },
  "has_stripe_customer": true,
  "has_calendar_token": false,
  "monthly_stake_limit_cents": 50000
}

PUT /api2/me

Updates the authenticated user's profile. The request body should be a JSON object with at least one of the following fields:

FieldTypeRequiredDescription
namestringfalseUser's full name
emailstringfalseUser's email address
timezonestringfalseDeprecated. User's IANA timezone
email_global_unsubscribebooleanfalseUnsubscribe from all emails (e.g. daily reminders)
beeminder_userstringfalseBeeminder username for the connected integration
beeminder_tokenstringfalseBeeminder auth token for the connected integration
beeminder_goal_new_tasksstringfalseBeeminder goal slug for new-task tracking
monthly_stake_limit_centsnumber | nullfalseMonthly stake cap in cents (non-negative integer), or null to remove
monthly_charge_limit_centsnumber | nullfalseMonthly API-charge cap in cents (non-negative integer), or null to remove the cap (uncapped)

Example request:

bash
curl -X PUT "https://api.taskratchet.com/api2/me" \
  -H "Authorization: ApiKey-v2 YOUR_API_V2_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Jane Doe"}'

On success, returns the updated user profile object (same shape as GET /api2/me).

DELETE /api2/me

Deletes the user's account. This action is irreversible.

GET /api2/me/tasks

Returns an array of tasks. This route is paginated.

Query params:

ParamTypeRequiredDescription
pagenumberfalsePage number (default: 0)
statusstringfalseFilter by task status (pending, complete, expired)
due_beforenumberfalseUnix timestamp; only return tasks due before this time
due_afternumberfalseUnix timestamp; only return tasks due after this time

Response format:

Response FieldTypeDescription
idstringThe task's unique identifier
taskstringThe task description
duenumberUnix timestamp of the task's due date
centsnumberThe task's stakes in cents
completebooleanWhether the task is complete
statusstringThe task's status (pending, complete, expired)
chargeStatusstringPresent only when a charge has been initiated. One of: notified, authorized, captured (optional)
contestedbooleanPresent and true only when the user has contested the charge (optional)

Example request:

bash
curl "https://api.taskratchet.com/api2/me/tasks?page=0" \
  -H "Authorization: ApiKey-v2 YOUR_API_V2_TOKEN"

Example response:

json
[
  {
    "id": "tdDPzh1GpZHAGZURVBf6",
    "task": "Take out the trash",
    "due": 1614556800,
    "cents": 100,
    "complete": false,
    "status": "pending"
  },
  {
    "id": "xkL9mN2OpQrStUvWxYz3",
    "task": "File tax return",
    "due": 1614470400,
    "cents": 500,
    "complete": false,
    "status": "expired",
    "chargeStatus": "notified"
  }
]

POST /api2/me/tasks

Creates a new task. The request body should be a JSON object with the following fields:

FieldTypeRequiredDescription
taskstringtrueThe task description (must be non-empty)
duenumbertrueUnix timestamp of the task's due date
centsnumbertrueThe task's stakes in cents (minimum 100)
recurrenceobjectfalseThe task's recurrence settings
recurrence.daysnumbertrueNumber of days between recurrences

WARNING

The recurrence feature is incomplete and likely buggy. Use it at your own risk.

Error responses:

StatusBodyCondition
422{ "error": "Monthly stake limit exceeded" }Adding the new task's cents would push the current calendar month's total over the user's monthly_stake_limit_cents
422Unprocessable EntityInvalid request body (missing or malformed fields)

On success, the response will be the created task object.

Example response:

json
{
  "id": "tdDPzh1GpZHAGZURVBf6",
  "task": "Take out the trash",
  "due": 1614556800,
  "cents": 100,
  "complete": false,
  "status": "pending"
}

GET /api2/me/tasks/:task_id

Returns a single task by ID.

Example request:

bash
curl "https://api.taskratchet.com/api2/me/tasks/tdDPzh1GpZHAGZURVBf6" \
  -H "Authorization: ApiKey-v2 YOUR_API_V2_TOKEN"

Example response:

json
{
  "id": "tdDPzh1GpZHAGZURVBf6",
  "task": "Take out the trash",
  "due": 1614556800,
  "cents": 100,
  "complete": false,
  "status": "pending"
}

PUT /api2/me/tasks/:task_id

Updates an existing task. All fields are optional, but at least one must be provided.

FieldTypeRequiredDescription
completebooleanfalseMark the task complete or incomplete (cannot mark as complete if expired)
centsnumberfalseUpdate the stakes in cents (can only be increased, minimum 100)
duenumberfalseUpdate the due date as a Unix timestamp (can only be moved earlier)

INFO

Stakes can only be increased and deadlines can only be moved earlier — you cannot make a task easier after creating it.

Example request:

bash
curl -X PUT "https://api.taskratchet.com/api2/me/tasks/tdDPzh1GpZHAGZURVBf6" \
  -H "Authorization: ApiKey-v2 YOUR_API_V2_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"complete": true}'

On success, returns the updated task object.

Example response:

json
{
  "id": "tdDPzh1GpZHAGZURVBf6",
  "task": "Take out the trash",
  "due": 1614556800,
  "cents": 100,
  "complete": true,
  "status": "complete"
}

POST /api2/me/tasks/:task_id/uncle

Gives up on a task early ("cries uncle"), triggering the charge process before the deadline. This sends a charge notification email and begins the charge flow. Can only be called once per task — returns 409 Conflict if the task has already been uncled or a charge has already been initiated.

Example request:

bash
curl -X POST "https://api.taskratchet.com/api2/me/tasks/tdDPzh1GpZHAGZURVBf6/uncle" \
  -H "Authorization: ApiKey-v2 YOUR_API_V2_TOKEN"

Returns 200 OK with body ok on success.

POST /api2/me/charges

Charges the authenticated user's saved card an arbitrary amount, independent of any task. Intended for external integrations that impose their own penalties on top of TaskRatchet. The charge is captured immediately — there is no authorization window and no advance warning email; a receipt email is sent after a successful charge.

The request body should be a JSON object with the following fields:

FieldTypeRequiredDescription
centsnumbertrueAmount to charge, in cents (minimum 100, i.e. $1.00)
notestringfalseA short description of the charge (max 500 chars). Included on the receipt email and the Stripe charge.
requestidstringfalseIdempotency token. A repeat request with the same requestid returns the original charge instead of charging again.
dryrunbooleanfalseWhen true, validates the request (amount, limit, payment method) and returns a simulated charge without charging the card.

Idempotency

Supplying a unique requestid per logical charge makes retries safe: if a request times out or you resend it, you get the original result back rather than a second charge. To intentionally retry after a declined card, use a new requestid.

Monthly charge limit

Charges are bounded by the user's monthly_charge_limit_cents (a separate cap from monthly_stake_limit_cents), summed over successful charges in the current calendar month:

  • A finite value caps the total charged per month. Every account starts at a default of $100/month.
  • 0 disables the endpoint (every charge is rejected).
  • null means no limit (uncapped). Set it via PUT /api2/me.

Error responses:

StatusBodyCondition
422{ "error": "Monthly charge limit exceeded" }This charge would push the calendar month's successful-charge total over monthly_charge_limit_cents
422Unprocessable EntityInvalid request body (e.g. cents below 100)
400{ "error": "No payment method on file" }The user has no saved card to charge
402{ "error": "<decline message>" }The card was declined (the attempt is still recorded)

Example request:

bash
curl -X POST "https://api.taskratchet.com/api2/me/charges" \
  -H "Authorization: ApiKey-v2 YOUR_API_V2_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"cents": 500, "note": "Missed my workout", "requestid": "2026-06-15-workout"}'

Example response:

json
{
  "id": "9f8b0c2e-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
  "cents": 500,
  "note": "Missed my workout",
  "status": "succeeded",
  "created": 1614556800
}

GET /api2/me/recurring

Returns an array of your recurring tasks — the schedules that automatically create new tasks on a fixed cadence. This route is paginated.

Query params:

ParamTypeRequiredDescription
pagenumberfalsePage number (default: 0)

Response format:

Response FieldTypeDescription
idstringThe recurring task's unique identifier
taskstringThe task description applied to each created task
last_duenumberUnix timestamp of the most recent due date in the schedule
centsnumberThe stakes in cents applied to each created task
recurrenceobjectThe cadence, e.g. { "days": 7 } for every 7 days

Example request:

bash
curl "https://api.taskratchet.com/api2/me/recurring" \
  -H "Authorization: ApiKey-v2 YOUR_API_V2_TOKEN"

Example response:

json
[
  {
    "id": "59059053-55dd-4c7e-bdf5-c08eeb37106d",
    "task": "Weekly system review",
    "last_due": 1780882200,
    "cents": 5000,
    "recurrence": { "days": 7 }
  }
]

DELETE /api2/me/recurring/:recurring_id

Stops a recurring task by deleting its recurrence schedule, so no new tasks are created from it going forward. Tasks that have already been created from the schedule are left untouched.

Example request:

bash
curl -X DELETE "https://api.taskratchet.com/api2/me/recurring/59059053-55dd-4c7e-bdf5-c08eeb37106d" \
  -H "Authorization: ApiKey-v2 YOUR_API_V2_TOKEN"

Responses:

StatusBodyCondition
200successRecurring task deleted
404{ "error": "Recurring task not found" }No matching recurring task exists for your account
403{ "error": "Forbidden" }Missing or invalid authentication

POST /api2/me/token

Reset your account's API v2 token. This will invalidate the old token and generate a new one.

You'll need to be authenticated in order to reset your token. If you don't already have a token, contact support for help.

GET /api2/me/token

Returns the current API v2 token for the authenticated user.

POST /api2/me/calendar-token

Generates a new calendar feed token for the authenticated user, replacing any existing one (which invalidates the previous feed URL). Use this to enable the feed or to rotate the token if a URL is exposed.

Returns the token as a plain-text response body. Combine it with the public feed route to build the subscription URL: https://api.taskratchet.com/api2/calendar/<token>.ics.

bash
curl -X POST "https://api.taskratchet.com/api2/me/calendar-token" \
  -H "Authorization: ApiKey-v2 YOUR_API_V2_TOKEN"

GET /api2/me/calendar-token

Returns the authenticated user's current calendar feed token as a plain-text response body.

StatusBodyMeaning
200 OKthe tokenA calendar token exists
400 Bad Request{ "error": "Calendar token has not been generated for this user. Please use the POST /api2/me/calendar-token endpoint to generate a new calendar token." }No token has been generated yet

GET /api2/calendar/:token.ics

Public, unauthenticated iCal feed of the user's pending task deadlines, secured by the token in the URL. Subscribe to this URL from any calendar app. The .ics extension is optional. Each pending task is emitted as a VEVENT whose summary includes the task description and stake amount; expired tasks are excluded.

Responses are served as text/calendar; charset=utf-8 with Cache-Control: no-cache.

StatusBodyMeaning
200 OKiCal (VCALENDAR) documentToken resolved; feed returned
404 Not FoundNot FoundNo user matches the supplied token
500 Internal Server ErrorInternal Server ErrorThe feed could not be generated
bash
curl "https://api.taskratchet.com/api2/calendar/YOUR_CALENDAR_TOKEN.ics"

GET /api2/health/stripe

Public, unauthenticated Stripe connectivity probe intended for uptime monitors. It makes a lightweight, read-only call to Stripe and reports whether the API can reach it.

StatusBodyMeaning
200 OK{"stripe":"ok"}Stripe is reachable
503 Service Unavailable{"stripe":"unreachable"}The Stripe call failed
bash
curl "https://api.taskratchet.com/api2/health/stripe"

Example response (healthy):

json
{ "stripe": "ok" }