Skip to the main content
Whenabouts Whenabouts
CreatePricingHelpSign in

Help

The API

The API lets your own code read the pages you run, and on a paid plan make and change them. It answers in JSON, over HTTPS, at one address. Reading works on every plan.

What's on this page

  • The basics
  • Keys
  • Sending the key
  • Whose pages a key can see
  • Reading
  • What comes back
  • Making and changing pages
  • Errors
  • Rate limits
  • What it doesn't do yet

The basics

  • Every endpoint is under https://whenabouts.me/v1. The address people answer on, whenabouts.link, doesn't serve the API.
  • Requests and answers are JSON. Send Accept: application/json.
  • Call it from a server. It sends no CORS headers, so a browser on another site can't call it, and a key in a web page would be readable by anybody anyway.
  • Times are UTC, written 2026-10-10T14:00:00Z. Each page also carries its own time zone, as an IANA name like America/Toronto.
  • The /v1 in the address is the version.

Keys

Sign in and open "Keys and the API" from your pages. Give a key a label you'll recognize later, choose what it can do, and press the button. The key is shown once. We keep a fingerprint of it, not the key, so if you lose it, make another.

  • "Read what I've made" works on every plan.
  • "Read and change things" needs a paid plan, both when you make the key and every time it's used. If the plan ends, the key goes on reading and stops writing.
  • What a key can do is fixed when it's made. To go from reading to writing, make a new key.
  • You can have 2 keys at once on Free and 10 on a paid plan. Revoked keys don't count.
  • "Revoke" stops a key at once. Each key shows when it was last used, to the day, so you can see which ones are idle.
  • Each time a key is made, we email your account's address its label and what it can do, never the key, so you'd know if somebody else made it.

Sending the key

Send it in the Authorization header, as a bearer token. A key anywhere else, such as in the address, is ignored, because an address ends up in browser history, referrers and logs.

curl https://whenabouts.me/v1/events \
  -H "Authorization: Bearer wa_..." \
  -H "Accept: application/json"

A missing, mistyped or revoked key, or the key of an account that's been deleted, gets 401 with WWW-Authenticate: Bearer. A 401 doesn't count toward your daily requests.

Whose pages a key can see

A key sees the pages on its own account, and the pages of any account that has added you to help run them, for as long as that account's plan has a place for you. Pages made without an account can't be reached through the API.

Writing, and the daily count, go by the plan of the account the key belongs to. A page made through the API goes on that account.

Reading

In the paths below, :id is a page's id, its short link ending, or its own link ending if it has one. Endings ignore case. Deleted pages aren't found; archived ones are.

The endpoints for reading
RequestWhat comes back
GET /v1/events{ events }: the 100 pages with the most recent activity that the key can see, newest first. Archived pages, and the single shifts a shift schedule makes, are left out.
GET /v1/events/:id{ event, slots }. slots are a sign-up sheet's rows; for every other kind it's an empty list.
GET /v1/events/:id/responses{ responses }: every current answer, oldest first.
GET /v1/events/:id/resultsOn a grid, the best times (below). On a sheet, how many answered and each row with how many it's taken. On a head count, how many answered, and nothing more.
GET /v1/rosters{ rosters }: your own lists of people, each with id, name, category and createdAt. Never the people on them.
GET https://whenabouts.me/v1/events
Authorization: Bearer wa_...
Accept: application/json

200 OK
RateLimit-Limit: 20000
RateLimit-Remaining: 19874
RateLimit-Reset: 41520

{"events":[{"id":"01K6G7Z3QH8V4N2R5T9W0XJ6MB","kind":"sheet",
  "slug":"b7kq2m9xzt","title":"Bake sale, Saturday",
  "description":"Bring something wrapped and labelled.",
  "category":"school","organizerName":"Priya",
  "timezone":"America/Toronto","status":"open","responseCount":12,
  "createdAt":"2026-09-28T15:04:11Z","closesAt":"2026-10-09T23:00:00Z",
  "url":"https://whenabouts.link/e/b7kq2m9xzt"}]}

A grid's results look like {"kind":"grid","answered":7,"best":[{"dayIndex":1,"startCell":10,"endCell":13,"count":6,"missing":["Alex"]}]}. There are up to five, best first. startCell and endCell count every time on the grid from the first, day after day, and both are included. Each is the same people free all the way through. missing names who can't make it, and is left empty once the number of times on the grid multiplied by the number of answers passes 20,000.

What comes back

A page has id, kind (grid, sheet, rsvp, or shifts for a single shift fetched by id), slug, title, description, category, organizerName, timezone, status (open, closed or suspended), responseCount, createdAt, closesAt and url, the link people answer on. A page whose closing date has passed still says open, so compare closesAt with the time.

A row has id, position, label, description, startsAt, endsAt, location, capacity and taken.

An answer has id, name, note, createdAt, updatedAt and payload. On a head count the payload is like {"v":1,"answer":"Yes","guests":2,"custom":"Vegetarian"}, with answer one of Yes, No or Maybe. On a grid it carries the times picked in a compact encoded form.

Email addresses are never in anything the API returns, on any plan. Neither are private links, PINs or a page's settings. If you need addresses, download the spreadsheet from the page's console.

Making and changing pages

These need a key made with "Read and change things" and a paid plan. Without both, they answer 403, whether or not the page exists.

The endpoints for making and changing pages
RequestWhat it does
POST /v1/eventsMakes a grid, a sign-up sheet or a head count on your account. Answers 201 with { event }. No private link comes back; manage it from your dashboard.
PATCH /v1/events/:idChanges the title, and only the title: {"title":"…"}. Everything else is changed on the page.
POST /v1/events/:id/closeStops it taking answers, the same as "Stop taking responses". It doesn't lock in a time. No body.
POST /v1/events/:id/remindersOn a head count, asks the addresses you added on the console that haven't been asked or answered. Answers { asked, considered }. Once a day per page, shared with the console's button, and each address is only ever asked once. The body, if any, is {"audience":"not_responded"}.

POST /v1/events takes the same things the forms do:

  • Always: kind (grid, sheet or rsvp), title (up to 80 characters; longer is cut), organizerName, timezone and settings. Optionally description, organizerEmail (where the page's emails go; never returned), category and closesAt.
  • A grid's settings: mode (dates or weekdays), days (up to 31 dates) and weekdays (0 for Sunday to 6), one of them filled in for the mode and the other an empty list, windowStart and windowEnd as HH:MM, slotMinutes (5 to 240), hideNamesUntilClosed and allowNotes. Up to 1,500 times in all.
  • A sheet's settings: slotStyle (times, days, items or shifts), requireEmail, allowMultipleClaims, allowNotes and hideNames; and slots, at least one, each with a label and optionally capacity (1 to 999), startsAt, endsAt, location and description. Up to 500 rows.
  • A head count's settings: startsAt, optionally endsAt, and allDay, allowGuests, maxGuestsPerResponse (0 to 20), hideNames and remind24h; optionally location, mapUrl, guestCap and customQuestion.
POST https://whenabouts.me/v1/events
Authorization: Bearer wa_...
Content-Type: application/json

{"kind":"sheet","title":"Bake sale, Saturday","organizerName":"Priya",
 "timezone":"America/Toronto","category":"school",
 "settings":{"slotStyle":"items","requireEmail":false,
   "allowMultipleClaims":true,"allowNotes":true,"hideNames":false},
 "slots":[{"label":"Cookies","capacity":3},
   {"label":"Lemonade stand","startsAt":"2026-10-10T14:00:00Z",
    "endsAt":"2026-10-10T16:00:00Z","capacity":2}]}

201 Created
{"event":{"id":"01K6...","kind":"sheet","status":"open","responseCount":0,...}}

A new page, and a changed title, is checked for scams the same way the forms' are, and a page that looks like one is made paused, with status suspended.

Errors

Every error is the same shape:

{"type":"about:blank","title":"Not found","status":404,
 "detail":"We can't find that."}
What each status means
StatusWhen
400The body of a new page isn't JSON.
401No usable key.
403Writing without a paid plan, or with a key that can only read. The detail says which.
404No such page, or one this key can't see (those two look the same on purpose), or no such endpoint.
409The page is paused, a sheet has more rows than the plan allows, or asking for answers can't happen (not a head count, or nobody left to ask).
422Something in the body isn't valid. The detail describes the first problem found.
429Over today's requests, or asking for answers more than once a day on one page.
500Something went wrong at our end. The detail has a reference to quote if you write to us.

Rate limits

Each account has 1,000 requests a day on Free and 20,000 on a paid plan, shared by all its keys. The day runs from midnight to midnight UTC. Every request with a usable key to an endpoint that exists counts, the ones that end in an error included.

Answers from an endpoint that accepted your key carry three headers. A 500, and the 409 for too many rows, don't.

  • RateLimit-Limit: the daily number.
  • RateLimit-Remaining: what's left today.
  • RateLimit-Reset: seconds until midnight UTC.

Over the limit, the answer is 429 with Retry-After in seconds. If a plan ends, the account drops to the free number right away.

What it doesn't do yet

  • No Idempotency-Key. Version 1 doesn't support one. If a POST /v1/events times out and you send it again, you can end up with two pages. Before retrying, check GET /v1/events for the one you meant to make.
  • No paging or filters. GET /v1/events stops at the 100 most recently active pages.
  • No grid settings. Nothing returns a grid's dates, hours or how long each time is, so a grid's results can't be turned into clock times from the API alone.
  • No head-count totals in results, and no record of who took which row on a sheet. Answers carry what each person said, so you can count them yourself.
  • Little editing. Only a page's title can be changed, and pages can't be deleted, reopened or locked in through the API.

If you're building something and one of these is in the way, write to us. Webhooks tell you when things happen, so you don't have to poll.

Didn't find what you were after? The rest of the help pages might have it, or write to us and somebody will answer.

© WhenaboutsFind a timeSign-up sheetsRSVPTemplatesHelpPrivacyTermsSecurityAccessibilityContact