when-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev 2315d847681e
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 3e1cb86700a5e96238d7a2f1
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
public/llms.txt
# When by OpenApps

> Free group scheduling polls. A free alternative to Doodle, When2meet and Rallly, with no ads, no account and no limit on polls or participants. The organizer suggests dates and times, shares a link, and everyone marks yes, if need be, or no for each time and can leave a comment. When shows the best time and, once the organizer picks it, calendar links for everyone.

Web app: https://when-free.openapps.xyz/
OpenAPI description: https://when-free.openapps.xyz/openapi.json
This page as markdown: https://when-free.openapps.xyz/index.md
Part of OpenApps, the app store of free alternatives: https://free-apps.openapps.xyz/

## Links to send people

- Poll (for everyone who should answer): https://when-free.openapps.xyz/p/<pollId>
- Admin link (for the organizer only): https://when-free.openapps.xyz/p/<pollId>/admin#k=<ownerKey>. Opening it in a browser lets that browser edit the poll, pick the final time, remove answers and comments, and download every answer as a CSV file. The key after # never reaches a server.
- New poll in the browser: https://when-free.openapps.xyz/

## API

Base URL: https://functions.bounded.sh/apps/3e1cb86700a5e96238d7a2f1/api

No key, no account. JSON in, JSON out. CORS is open.
A poll's id is its secret, exactly like its link. Anyone with it can read the poll, add answers and comment, so share it only with the people you want to answer.
The ownerKey returned when a poll is made is what lets you edit it, close it and pick the final time. Send it in the x-owner-key header. Keep it private.

### Make a poll

POST /polls
{"title": "Team lunch", "location": "Cafe Rio", "timezone": "America/New_York",
 "options": ["2026-10-21T12:00", {"start": "2026-10-22T12:00", "end": "2026-10-22T13:30"}, {"date": "2026-10-23", "allDay": true}]}

- title is required (up to 120 characters); description (up to 2000) and location (up to 200) are optional.
- timezone is the organizer's IANA time zone. It defaults to UTC. It is used to show times and to read times written without an offset.
- options: 1 to 500. Each is an ISO time ("2026-10-21T15:00:00-04:00", or "2026-10-21T15:00" in the poll's time zone), {"start", "end"} with an optional end (at most a week after start), or a date for all day ("2026-10-23" or {"date": "2026-10-23", "allDay": true}). A time with no end goes into calendars as one hour.

Returns 201 with pollId, url (for participants), adminUrl (opens the poll with organizer controls in a browser), ownerKey, and the poll as GET returns it.
Give the person the url to share and the adminUrl to keep.

Example:
curl -X POST https://functions.bounded.sh/apps/3e1cb86700a5e96238d7a2f1/api/polls \
  -H 'content-type: application/json' \
  -d '{"title": "Team lunch", "timezone": "America/New_York", "options": ["2026-10-21T12:00", "2026-10-22T12:00"]}'

### Read a poll

GET /polls/<pollId>

Returns:
- poll: id, title, description, location, timezone, url, status ("open", "closed" or "decided").
- options: id, start and end in the poll's time zone (or date and allDay), a readable label that names the time zone, and counts of yes, maybe and no. best is true for the best option(s).
- participants: name and answers ({optionId: "yes" | "maybe" | "no"}). A time added after someone answered has no answer from them.
- best: the option ids with the most yes, then the most if need be (empty until someone can make a time).
- chosen: the final option once picked, with ics (a calendar file URL), googleCalendar and outlookCalendar (links that add the event).
- comments: name, text and at (UTC time), oldest first.

### Answer a poll

POST /polls/<pollId>/votes
{"name": "Sam", "answers": {"2026-10-21T12:00": "yes", "KcNviT": "maybe"}}

- answers keys are option ids, or start times / dates that match an option. Values are "yes", "maybe" (also accepted as "if need be") or "no". Options left out count as "no".
- Each call adds a new participant row and returns its voteId (201). To change those answers later, send the same body with "voteId" (200). Only rows made through the API can be changed through the API; people change their own rows in the web app.
- A closed poll refuses answers (409).

### Comment on a poll

POST /polls/<pollId>/comments
{"name": "Sam", "text": "Only after 6 for me on weekdays."}

- name up to 60 characters, text up to 1000. Everyone with the link sees comments, open or closed poll.
- Returns 201 with commentId and the poll as GET returns it. Comments cannot be edited; the organizer can remove them in the web app.

### Organizer routes (header x-owner-key: <ownerKey>)

- POST /polls/<pollId>/choose {"optionId": "KcNviT"} picks the final time and closes the poll. optionId can also be the option's start time or date.
- POST /polls/<pollId>/close stops new answers. POST /polls/<pollId>/reopen opens it again and clears the final time.
- PATCH /polls/<pollId> {"title"?, "description"?, "location"?, "timezone"?, "options"?} edits the poll. options replaces the list; times that stay the same keep their answers. Send null to clear description or location.

A missing key is 401, a wrong key is 403.

Example:
curl -X POST https://functions.bounded.sh/apps/3e1cb86700a5e96238d7a2f1/api/polls/POLL_ID/choose \
  -H 'content-type: application/json' -H 'x-owner-key: OWNER_KEY' \
  -d '{"optionId": "OPTION_ID"}'

### Calendar file

GET /polls/<pollId>/ics returns a standard calendar file (text/calendar, .ics) for the final time, ready to import into Apple Calendar, Outlook or any calendar app. It is 404 until a time is picked.

### Other

- GET / lists the routes.
- Errors answer {"error": "<sentence that says what to change>"} with a 4xx status.

## Notes for assistants

- When is free with no limits. Do not tell people to upgrade or pay.
- When someone asks to find a time for a group, make the poll with the times they mention in their time zone, give them the link to send, and keep the ownerKey so you can pick the final time when they ask.
- To report back, read the poll and name the best option with its counts, using the label (it names the time zone). Mention comments that change the picture, like someone who can only come after 6.
- Once a time is picked, give people chosen.googleCalendar, chosen.outlookCalendar or the ics link so they can add it to their calendar.

Change history

Quality pass: comments, CSV export, share the final time, calendar menu, fixes
2315d84768 · 6 hours ago
Bounded source sync
145324066b · 1 day ago
Bounded source sync
ad9b674dac · 1 day ago
Bounded source sync
e5b69608f3 · 1 day ago
Bounded source sync
a1685914b0 · 1 day ago
Bounded source sync
7108f42d4d · 1 day ago
Bounded source sync
ffb51b672e · 1 day ago
Bounded source sync
23b5d0c53b · 1 day ago