API

JSON API for third-party builders

Base path: /api/v1 · JSON only · Bearer tokens for capability links.

Auth Bearer token

Authentication

  • Event owner token (admin token) → required for editing/deleting events or listing/deleting RSVPs: Authorization: Bearer <event-owner-token>.
  • RSVP token → required for managing your own RSVP at /events/{event_id}/rsvps/self.
  • No root-level API; root admin stays CLI-only.

Note: the root admin token can stand in anywhere an event owner token is required.

Tip: send ISO timestamps; include timezone_offset_minutes when creating/updating events so local times are stored correctly in UTC.

Private RSVPs are hidden from GET /api/v1/events/{id} but are visible when using the event owner endpoints.

Public responses omit private channel metadata and redact locations for approval-required events unless you send an admin/root token or an approved Yes RSVP token.

Key endpoints

POST/api/v1/events Create event; returns the event owner (admin) token + links.
GET/api/v1/events List public events with pagination and date filters.
GET/api/v1/events/{event_id} Public event detail + public RSVPs.
PATCH/api/v1/events/{event_id} Update event (event owner bearer).
DELETE/api/v1/events/{event_id} Delete event (event owner bearer).
GET/api/v1/events/{event_id}/rsvps List RSVPs + stats (event owner bearer).
POST/api/v1/events/{event_id}/rsvps Create RSVP; returns token + links.
GET/PATCH/DELETE/api/v1/events/{event_id}/rsvps/self Manage your own RSVP (rsvp bearer).
POST/api/v1/events/{event_id}/rsvps/{rsvp_id}/approve|reject|pending Update approval state (event owner bearer).
GET/api/v1/events/{event_id}/event.ics Download the event as an ICS file.
POST/api/v1/events/{event_id}/messages Create a public/admin event announcement.
POST/api/v1/events/{event_id}/rsvps/{rsvp_id}/messages Send a direct message or admin note.
POST/api/v1/events/{event_id}/rsvps/self/messages Attendee message to the organizer.
GET/api/v1/channels Public channels with pagination; filter via ?q=.
GET/api/v1/channels/{slug} Channel detail + events (public or private based on slug visibility).

Create an event

Send ISO8601 times. Pass timezone_offset_minutes (e.g., browser timezone offset) so local times normalize to UTC.

curl -X POST http://localhost:8000/api/v1/events \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Cedar Social: Cigar Night",
    "description": "Monthly hang at the lounge.",
    "start_time": "2024-08-22T19:00:00",
    "end_time": "2024-08-22T21:30:00",
    "timezone_offset_minutes": -300,
    "location": "Cedar Social, Austin",
    "channel_name": "ATX Cigars",
    "channel_visibility": "public",
    "is_private": false
  }'
Response includes admin_token (the event owner token) plus links.admin for the owner page and links.public for the guest view.

Create an RSVP

No auth required to submit; the response includes the RSVP token.

curl -X POST http://localhost:8000/api/v1/events/{event_id}/rsvps \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Sky",
    "status": "yes",
    "pronouns": "they/them",
    "guest_count": 1,
    "notes": "Can bring a projector",
    "is_private_rsvp": false
  }'

Guests manage their own entry at /api/v1/events/{event_id}/rsvps/self using Authorization: Bearer <rsvp-token>. Responses include approval_status (approved/pending/rejected).

curl -X PATCH http://localhost:8000/api/v1/events/{event_id}/rsvps/self \
  -H "Authorization: Bearer <rsvp-token>" \
  -H "Content-Type: application/json" \
  -d '{"status": "no", "notes": "Out of town"}'

List public events

Returns only public (non-private) events with pagination. per_page is capped to prevent huge responses.

curl "http://localhost:8000/api/v1/events?page=1&per_page=10"

Private events never appear in this listing; they remain reachable only via their exact IDs or the root admin UI. Approval-required events return location: null until an approved Yes token (or admin/root token) is supplied, and counts only include approved RSVPs.

Filter by date range

Use ISO8601 timestamps to bound start times. Both parameters are optional.

curl "http://localhost:8000/api/v1/events?start_after=2024-08-01T00:00:00&start_before=2024-08-31T23:59:59"

start_before must be after start_after. The response echoes pagination and the applied filters.

Event owner actions on events

Use the event owner token (admin token) as a bearer to edit or delete.

Third-party apps can delete events the same way the owner UI does by calling the DELETE endpoint with the event owner token.

curl -X PATCH http://localhost:8000/api/v1/events/{event_id} \
  -H "Authorization: Bearer <event-owner-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Updated title",
    "channel_name": "Private Circle",
    "channel_visibility": "private",
    "is_private": true
  }'

Deleting an event (DELETE /api/v1/events/{id}) removes the event and all RSVPs. This is irreversible.

List RSVPs with stats (event owner)

Returns RSVP records (including private ones) plus convenience counts.

curl http://localhost:8000/api/v1/events/{event_id}/rsvps \
  -H "Authorization: Bearer <event-owner-token>"

Events with approval enabled include approval_status on each RSVP; pending/rejected entries stay off the public attendee list.

Example stats payload:

{
  "stats": {
    "yes_count": 6,
    "yes_guest_count": 3,
    "yes_total": 9,
    "maybe_count": 2,
    "no_count": 1
  }
}

Event owners can delete specific RSVPs via DELETE /api/v1/events/{event_id}/rsvps/{rsvp_token}.

Approve or reject pending RSVPs

When Require admin approval is enabled, new RSVPs enter the pending queue until an event owner (or root admin token) sends one of the approval endpoints below.

  • POST /api/v1/events/{event_id}/rsvps/{rsvp_id}/approve — marks the RSVP approved and adds an owner-visible log entry.
  • POST /api/v1/events/{event_id}/rsvps/{rsvp_id}/reject — accepts optional JSON body {"reason": "Capacity reached"} that is shared with the attendee.
  • POST /api/v1/events/{event_id}/rsvps/{rsvp_id}/pending — moves the RSVP back into the pending state.

All three routes require Authorization: Bearer <event-owner-token> or the root admin token from docker exec openrsvp openrsvp admin-token. Responses return the updated RSVP plus its attendee-facing messages.

curl -X POST http://localhost:8000/api/v1/events/{event_id}/rsvps/{rsvp_id}/approve \
  -H "Authorization: Bearer <event-owner-token>"

Messages API

Send announcements or direct messages between hosts and attendees.

  • POST /api/v1/events/{event_id}/messages — event announcements (visibility: public or admin).
  • POST /api/v1/events/{event_id}/rsvps/{rsvp_id}/messages — admin notes or direct messages to a guest.
  • POST /api/v1/events/{event_id}/rsvps/self/messages — attendee message to the organizer.
curl -X POST http://localhost:8000/api/v1/events/{event_id}/messages \
  -H "Authorization: Bearer <event-owner-token>" \
  -H "Content-Type: application/json" \
  -d '{"content": "Doors open 15 minutes early.", "visibility": "public", "message_type": "event_update"}'

Event detail responses include public announcements in messages; RSVP detail responses include attendee-visible messages.