REST API

The Happa plugin API is installation-scoped. Every request uses the token for one installed user, and each endpoint enforces the scopes that installation was granted.

Base URL

https://us-central1-happa-1aff4.cloudfunctions.net/pluginApi

Authentication

Authorization: Bearer hpt_your_installation_token

Missing or invalid tokens return 401. Valid tokens without the right scope return 403.

Rate limits

Window Limit
Hourly600 requests per installation token
Daily5000 requests per installation token

When the limit is exceeded, the API responds with 429 and includes Retry-After.

Events

Requires events.read unless noted otherwise.

GET /events

Lists events owned by the installing organizer. Supports limit and cursor.

curl "https://us-central1-happa-1aff4.cloudfunctions.net/pluginApi/events?limit=20" \
  -H "Authorization: Bearer hpt_..."

GET /events/:id

Returns one event. Access is limited to organizer-owned events.

PATCH /events/:id

Requires events.write. You can update only description, location, and eventDate.

curl -X PATCH "https://us-central1-happa-1aff4.cloudfunctions.net/pluginApi/events/abc123" \
  -H "Authorization: Bearer hpt_..." \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Doors open at 7PM",
    "location": "123 Main St, Austin TX",
    "eventDate": "2026-08-15T18:00:00.000Z"
  }'

Attendees

GET /events/:id/attendees

Requires attendees.read. Returns attendee IDs plus display names and photo URLs when available.

POST /events/:id/attendees

Requires attendees.write. Adds one attendee by user ID.

curl -X POST "https://us-central1-happa-1aff4.cloudfunctions.net/pluginApi/events/abc123/attendees" \
  -H "Authorization: Bearer hpt_..." \
  -H "Content-Type: application/json" \
  -d '{ "userId": "user_456" }'

DELETE /events/:id/attendees/:uid

Requires attendees.write. Removes one attendee by user ID.

GET /attendees?eventId=:id

Alias that redirects to the canonical attendees endpoint.

Comments

GET /events/:id/comments

Requires events.read. Supports limit and cursor, returns newest comments first, and allows public-event reads even when the event is not owned by the installer.

Polls

Poll endpoints are available when the installation has events.read. The backend also honors legacy polls.read tokens if they already exist.

GET /events/:id/polls

Lists polls for an organizer-owned event, including live nominee vote counts.

GET /events/:id/polls/:pollId

Returns one poll object with status, resultsVisibility, nominee metadata, and totalVotes.

Tickets

GET /events/:id/revenue

Requires tickets.read. Returns aggregate ticketsSold, totalRevenue, and currency for an organizer-owned event. Buyer PII is not exposed through this endpoint.

Profile

GET /profile

Requires profile.read. Returns the installing user's profile and follower/following counts.

{
  "uid": "user456",
  "displayName": "Jane Smith",
  "photoUrl": "https://...",
  "followerCount": 340,
  "followingCount": 88,
  "pluginId": "plg_123"
}

Pagination shape

{
  "events": [/* ... */],
  "nextCursor": "abc123",
  "hasMore": true
}

Error responses

{ "error": "Scope attendees.read not granted" }

See the Error Codes reference for the full response matrix and the most common causes.

Implementation tip: use webhooks to know when to fetch and the REST API to fetch the fresh state you need. That pattern keeps your token usage low and your plugin responsive.