The Public API gives organization admins direct HTTP access to your organization's live data — pull it into any website, app, bot, or automation that can make an HTTP request. It's a Business plan feature.
The key is scoped to your organization — all endpoints operate on that group automatically. Base URL: https://api.ludoya.com/public/v1. Auth header: X-Api-Key: YOUR_KEY. Rate limit: 100 requests/minute.
What You Can Access
- Locations — your group's available venues and their spots; used as input when creating events
- Events (read) — upcoming and past events with title, description, date/time, timezone, capacity, participant count, and status
- Events (write) — create and update events via POST and PUT, with full control over location, capacity, permissions, visibility, and image
- Members — member list with user profiles and roles (Owner, Admin, Member), paginated
- Collection — game collection with filtering by ownership, name, player count, and list; sortable and paginated; each game includes BGG metadata
- Stats — play statistics for any time period: totals, averages, top players with wins and scores, per-player-count breakdowns, per-location, and per-game
- Campaigns (read) — list the group's campaigns with member and session counts; retrieve full campaign detail including members, past sessions, and scheduled events
- Campaigns (write) — create campaigns for the group and update their name, description, status, and visibility
Endpoints
GET /locations
Returns the group's available locations. Each location has an id, name, optional address, capacity, an isDefault flag, and a spots array (each spot has its own id, name, and capacity). Use location and spot IDs when creating events.
GET /events
Returns future and past events in separate paginated lists.
| Param | Type | Default | Description |
|---|---|---|---|
onlyFuture |
boolean | true |
Set false to also return past events |
Each event includes: type (MEETUP or PLANNED_PLAY), title, description, startsAt, endsAt, timeZone, imageUrl, capacity, participantCount, canceled, teacher (user object or null), master (user object or null). User objects contain id, username, name, avatarUrl.
POST /events
Creates an event in the group. Required fields: type and title. If locationId is omitted, the group's default location is used; if none exists, returns 400.
Optional fields include: description, locationId, spotId, gameId, parentEventId (for sub-events), startsAt, endsAt, restrictedAttendance, capacity, minParticipants, estimatedDurationMinutes, allowReservations, takeGamesPermission, organizePlaysPermission, teacherUserId, masterUserId, visibility, image.
The image field accepts either {"base64": "data:image/jpeg;base64,..."} or {"url": "https://..."}. Max 5 MB.
Returns {"id": "string"} with status 201.
PUT /events/{eventId}
Updates an existing event. Same body shape as POST — only include the fields you want to change. The caller must be the event organizer (the group account). Returns 202 with empty body.
GET /members
Returns a paginated member list.
| Param | Type | Default |
|---|---|---|
pagination.size |
int | 50 |
pagination.offset |
int | 0 |
Each member includes: id, username, name, avatarUrl, role (OWNER, ADMIN, or MEMBER).
GET /collection
Returns your game collection with filtering, sorting, and pagination.
| Param | Type | Default | Description |
|---|---|---|---|
filter |
string | — | Semicolon-separated key=value pairs. Keys: ownership (OWNED, PREVIOUSLY_OWNED, PREORDERED, WISHLISTED), played (boolean), listId, nameFilter, playerCountFilterType (OFFICIAL, GOOD, BEST), playerCountFilter (number) |
groupExpansions |
boolean | true |
Group expansions under their base game |
sort |
string | — | Format: property,direction — e.g. name,asc |
pagination |
string | — | Format: size,pageIndex — e.g. 20,0 |
Response: totalGames, totalExpansions, games[] — each with: id, slug, name, imageUrl, isExpansion, yearPublished, minPlayerCount, maxPlayerCount.
GET /stats
Returns play statistics for a configurable time window.
| Param | Type | Default | Description |
|---|---|---|---|
period |
string | ALL_TIME | Format: PERIOD,date,index. Values: ALL_TIME, ONE_YEAR, ONE_MONTH, THIRTY_DAYS, SEVEN_DAYS, ONE_DAY, CUSTOM. The index shifts the window back (0 = current, 1 = previous). Custom: CUSTOM,startDate,0,endDate |
Response includes:
- Summary — total plays, total/average play time, unique game, player, and location counts
- By player — per-person plays, wins, average and best score
- By player count — breakdown of 2-player, 3-player, 4-player games, etc.
- By location — play count and unique games per venue
- By game — play count, total/average play time, and unique players per title
GET /campaigns
Returns a paginated list of campaigns belonging to the group.
| Param | Type | Default | Description |
|---|---|---|---|
status |
string | — | Filter by status: ACTIVE, COMPLETED, or ARCHIVED |
pagination.size |
int | 50 | Items per page |
pagination.offset |
int | 0 | Offset |
Each campaign includes: id, game (id, name, imageUrl), name, image, status, visibility, createdAt, updatedAt, memberCount, sessionCount.
GET /campaigns/{campaignId}
Returns the full detail of a campaign belonging to the group.
Response includes: All list fields, plus template, description, globalNotes, globalState, members[] (each with user, role, characterNotes, characterState), sessions[], and events[].
POST /campaigns
Creates a campaign for the group. Required fields: gameId and name. Visibility defaults to group-members-only (ONLY_GROUP) if omitted.
Optional fields: templateId, description, visibility (PUBLIC, ONLY_GROUP, ONLY_FRIENDS, or PRIVATE).
Returns {"id": "string"} with status 201.
PUT /campaigns/{campaignId}
Updates an existing campaign. All fields are optional — only include what you want to change.
Optional fields: name, description, status (ACTIVE, COMPLETED, ARCHIVED), visibility.
Returns 202 with empty body.
Error Codes
| Status | When |
|---|---|
| 400 | Validation failure (missing required field, no location found, invalid image) |
| 401 | Missing or invalid API key |
| 403 | Action not permitted or group not on Business plan |
| 404 | Resource not found |
| 429 | Rate limit exceeded |
Getting Started
1. Generate an API Key
- Go to your organization's profile page
- Tap the menu (⋮) → Public API
- Tap Generate key
- Copy your key immediately — it is shown only once and cannot be retrieved again
The key is tied to your organization. Keep it secret: anyone with the key can read and write all of the data above.
2. Revoke or Regenerate
To revoke an existing key, go back to the Public API page and tap Revoke. Confirm the dialog. Any system using the old key will immediately start receiving 401 errors. To issue a new key, tap Generate key again.
See also:
- Organizations — organization accounts and premium features
- Premium — Business plan pricing
- Integrations — other ways to connect Ludoya with external tools