Endpoint reference¶
Every read API endpoint, with request shape, response shape, required scopes, and example payloads.
Common conventions¶
Field naming¶
A few naming conventions you'll see across endpoints — call out in case any catch you off guard:
- Application review fields on participants are prefixed
last_because the participant object reflects the most recent review action:last_reviewed_at,last_reviewer_id,last_review_action(approved/rejected/revision_requested). Webhooks for individual review actions use the action-specific verb (application.approvedcarriesapproved_at,application.rejectedcarriesrejected_at). - Status field naming:
statuson the resource itself (e.g.application_statusfor applications,event.publish_status,activity.status). - Time fields: always ISO 8601 in UTC. Field name ends in
_at(submitted_at,connected_at). - Enums starting with a digit are prefixed:
min_agevalues areage_all,age_18_plus— never bare18_plus(which would be invalid as an enum identifier in many languages).
Base URL¶
| Environment | Base |
|---|---|
| Production (and sandbox) | https://api.revento.example/api/v1 |
There is no separate sandbox endpoint. Sandbox usage means connecting your integration to a curated test event hosted by Revento — same URL, different event id. See Sandbox & test environment.
URLs in this reference are written relative to the base.
Authentication¶
Every request requires a Bearer header with an installation token (event-scoped) or user token (participant-scoped). Token type matters per endpoint — see the table on each endpoint page.
Request IDs¶
Send a UUID on every request:
We echo it back in the response and log it on our side.
Pagination¶
List endpoints return:
To fetch the next page, pass next_cursor as the cursor query parameter. The cursor is opaque — don't parse it. has_more is the canonical "more pages exist" signal. limit defaults to 25, max 50 — kept conservative because list responses can carry custom_form_fields per row, which may approach the 2MB per-response cap on events with rich custom forms. If you receive 413 payload_too_large, reduce limit and retry.
Errors¶
Every error has the same envelope:
{
"error": "string_code",
"message": "Human-readable explanation",
"request_id": "UUID matching X-Revento-Request-Id"
}
Full catalog in Errors.
Endpoint summary¶
Three groups, three auth styles:
| Group | Auth | Endpoints |
|---|---|---|
| Event data (installation token) | Authorization: Bearer rev_install_... |
GET /events/{id}, /participants, /program, /activities, /locations, /threads, /registration-waves |
| User data (user token) | Authorization: Bearer rev_user_... |
GET /me/profile, /me/application |
Developer (your client_secret) |
HTTP Basic client_id:client_secret |
POST /oauth/revoke, GET /developer/integrations/{id}/installations, POST /developer/integrations/{id}/rotate-webhook-secret |
Mixing token types returns 403 user_token_required or 403 installation_token_required. Hitting a developer endpoint with a Bearer token returns 401 invalid_token.
Event endpoints (installation token)¶
GET /events/{event_id}¶
Read event metadata.
Scope: event.read
Request
GET /api/v1/events/evt_abc123 HTTP/1.1
Host: api.revento.example
Authorization: Bearer rev_install_...
Accept: application/vnd.revento.v1+json
Response
{
"id": "evt_abc123",
"title": "Sample Convention 2026",
"description": "Annual convention...",
"start_date": "2026-08-15T16:00:00Z",
"end_date": "2026-08-17T16:00:00Z",
"min_age": "age_all",
"access_mode": "open_approval",
"publish_status": "published",
"visibility": "discoverable",
"organization_id": "org_xyz789",
"location_summary": "Main Venue, Sample City",
"image_url": "https://example.com/image.jpg",
"created_at": "2026-04-01T10:30:00Z",
"updated_at": "2026-05-09T14:22:00Z"
}
Field reference
| Field | Type | Notes |
|---|---|---|
id |
string | Stable, opaque identifier |
title |
string | Display title |
description |
string | null | Free-text Markdown |
start_date, end_date |
ISO 8601 (UTC) | Always UTC |
min_age |
enum | age_all | age_18_plus |
access_mode |
enum | closed | open_approval | open_auto |
publish_status |
enum | draft | published |
visibility |
enum | private | discoverable |
organization_id |
string | The organization that owns this event |
location_summary |
string | null | Free-text "headline" location. The full venue graph (with buildings, floors, rooms) is at /locations |
image_url |
URL | null | Cover image |
GET /events/{event_id}/participants¶
List participants of the event. Returns the event-scoped profile (not the global Revento user profile) — including custom form responses and PII fields where present.
Scope: participants.read
Request
Response
{
"data": [
{
"id": "ptp_001",
"user_id": "usr_def456",
"display_name": "Sample Name",
"nickname": "Sample",
"organisation": "Sample Org",
"privacy_mode": false,
"role": { "id": "role_attendee", "name": "Attendee" },
"application_status": "approved",
"real_name": "Sample Real Name",
"email": "sample@example.com",
"admin_notes": null,
"custom_form_fields": {
"favorite_track": "RPG",
"dietary_notes": "Vegetarian",
"arrival_day": "Friday"
},
"last_reviewed_at": "2026-05-02T09:14:00Z",
"last_reviewer_id": "usr_org_123",
"last_review_action": "approved",
"registered_at": "2026-05-02T09:14:00Z",
"created_at": "2026-04-29T14:00:00Z",
"updated_at": "2026-05-02T09:14:00Z"
}
],
"next_cursor": "eyJjIjogIjIw...",
"has_more": true
}
Roles
role is event-scoped — every event defines its own roles (typically Attendee, Organizer, Staff, NPC, but custom roles are possible). The full role list is at GET /events/{id}/roles.
Application statuses
pending | approved | rejected | revision_requested
custom_form_fields
A JSON object whose keys depend on the event's custom application form. The schema is defined per-event by the organizer. Treat it as an opaque map — never assume specific keys exist.
GET /events/{event_id}/program¶
Read the event's program — threads with nested activities. Activities have start_time and end_time (UTC) — group them by date on your side if you need a day-level view.
Scope: program.read
Response
{
"threads": [
{
"id": "thr_main",
"name": "Main Hall",
"description": "All headline activities",
"icon_name": "auditorium",
"color_hex": "#2ED75A",
"sort_order": 0,
"activities": [
{ /* full activity — see GET /events/{id}/activities/{aid} */ }
]
}
]
}
For paginated flat access to activities, use /activities.
GET /events/{event_id}/activities¶
List activities, paginated. Use this when you don't need the program tree structure or when there are many activities.
Scope: program.read
Response
GET /events/{event_id}/activities/{activity_id}¶
Read a single activity.
Scope: program.read
Response
{
"id": "act_001",
"title": "Opening Ceremony",
"description": "Welcome and overview of the weekend",
"activity_type": "rpg_session",
"activity_details": { /* typed object per activity_type — see below */ },
"start_time": "2026-08-15T16:00:00Z",
"end_time": "2026-08-15T17:00:00Z",
"duration_minutes": 60,
"status": "scheduled",
"thread": {
"id": "thr_main",
"name": "Main Hall",
"color_hex": "#2ED75A"
},
"location": { /* full location with building/floor/venue summary */ },
"host_id": "ptp_001",
"host_display_name": "Sample Host",
"co_host_ids": ["ptp_002", "ptp_003"],
"co_host_display_names": "Co-host A, Co-host B",
"markers": [
{ "id": "mkr_kids", "name": "Kids-friendly", "color_hex": "#DCA041" }
],
"capacity": 8,
"sign_ups_enabled": true,
"committed_signups_count": 5,
"signed_up_participant_ids": ["ptp_010", "ptp_011", "ptp_012", "ptp_013", "ptp_014"],
"registration_waves": ["wave_a"],
"created_at": "2026-04-20T10:00:00Z",
"updated_at": "2026-08-15T14:30:00Z"
}
Field reference
| Field | Type | Notes |
|---|---|---|
activity_type |
enum | rpg_session | lecture | workshop | competition | discussion | LARP | other | break |
activity_details |
object | Typed per activity_type. The schema is defined by the event's activity type definitions. Treat as opaque per-type JSON unless you've coordinated with the organizer on what fields to expect. |
start_time, end_time |
ISO 8601 (UTC) | null | null until the activity is scheduled |
status |
enum | new | scheduled | canceled |
thread |
object | Reference to the parent thread, with name + color for display |
location |
object | null | Full location with building/floor/venue. null until a location is assigned |
host_id, co_host_ids |
string, string[] | Participant IDs (per /participants). Display names denormalized into host_display_name + co_host_display_names (comma-joined). |
signed_up_participant_ids |
string[] | Current participants signed up (only present if sign_ups_enabled) |
committed_signups_count |
int | Number that have actually committed; useful when signed_up_participant_ids is paginated or omitted |
markers |
object[] | Tag-like badges (e.g. "Kids-friendly", "Advanced") with display info |
registration_waves |
string[] | IDs of waves that gate sign-ups for this activity |
GET /events/{event_id}/locations¶
The full venue graph — venues, buildings, floors, and locations (the rooms / spots that activities point at).
Scope: program.read
Response
{
"venues": [
{
"id": "ven_default",
"name": "Main Venue",
"address": "1 Sample Street, 12-345 Sample City",
"google_maps_url": "https://maps.google.com/...",
"center_lat": 52.0,
"center_lng": 19.0,
"sort_order": 0,
"buildings": [
{
"id": "bld_main",
"name": "Main Building",
"description": "...",
"lat": 52.0,
"lng": 19.0,
"position_x": 50.0,
"position_y": 50.0,
"sort_order": 0,
"floors": [
{
"id": "flr_0",
"number": 0,
"name": "Ground Floor",
"sort_order": 0
}
]
}
],
"locations": [
{
"id": "loc_main_hall",
"name": "Main Hall",
"code": "MH-1",
"description": "...",
"scope": "indoor",
"type": "room",
"is_schedulable": true,
"capacity": 150,
"amenities": ["projector", "wifi"],
"position_x": 50.0,
"position_y": 50.0,
"icon_override": null,
"color_hex": null,
"operating_hours": "08:00-22:00",
"sort_order": 0,
"building": { "id": "bld_main", "name": "Main Building" },
"floor": { "id": "flr_0", "number": 0, "name": "Ground Floor" }
}
]
}
]
}
Location types: room | stage | expo | food | restroom | entrance | info | parking | rest_area | first_aid | smoking_area | other
Scopes: indoor | outdoor
GET /events/{event_id}/threads¶
The flat list of program threads, with display metadata. Activities reference threads by id; use this if you need to render thread color/icon outside the program tree.
Scope: program.read
Response
{
"data": [
{
"id": "thr_main",
"name": "Main Hall",
"description": "All headline activities",
"icon_name": "auditorium",
"color_hex": "#2ED75A",
"sort_order": 0
}
]
}
GET /events/{event_id}/registration-waves¶
List the event's registration waves — the time windows during which activity sign-ups are open.
Scope: program.read
Response
{
"data": [
{
"id": "wave_a",
"name": "Friday morning",
"starts_at": "2026-05-10T08:00:00Z",
"ends_at": "2026-05-10T12:00:00Z",
"status": "scheduled",
"activity_ids": ["act_001", "act_002", "act_003"]
}
]
}
Statuses: scheduled | started | finished | canceled
GET /events/{event_id}/roles¶
The event's role catalog. Participants reference roles by id; use this to resolve role names if you cache participants.
Scope: participants.read
Response
{
"data": [
{ "id": "role_attendee", "name": "Attendee", "description": "..." },
{ "id": "role_organizer", "name": "Organizer", "description": "..." }
]
}
User endpoints (user token)¶
GET /me/profile¶
Read the signed-in participant's basic profile.
Scope: profile.read
Response
{
"user_id": "usr_def456",
"display_name": "Sample Name",
"email": "sample@example.com",
"locale": "pl",
"event_id": "evt_abc123"
}
email is included if the participant granted profile.read. The scope is per-participant and may be declined on the consent screen.
GET /me/application¶
Read the signed-in participant's application for the event their token is bound to.
Scope: event.attendance
Response
{
"id": "app_xyz",
"event_id": "evt_abc123",
"status": "approved",
"submitted_at": "2026-04-29T14:00:00Z",
"last_reviewed_at": "2026-05-02T09:14:00Z",
"last_review_action": "approved"
}
Returns a single object — a user token is bound to exactly one event, so there's exactly one application. Status 404 resource_not_found if the participant withdrew their application.
Developer endpoints¶
These endpoints are authenticated with client_id + client_secret (HTTP Basic auth) rather than a Bearer token. They're for managing your integration itself, not for reading event data.
POST /oauth/revoke¶
Revoke a token (RFC 7009).
Request
POST /oauth/revoke HTTP/1.1
Host: auth.revento.example
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {base64(client_id:client_secret)}
token={the access or refresh token to revoke}
&token_type_hint=access_token
token_type_hint is optional; values are access_token or refresh_token.
Response
Always 200 OK with empty body, including for unknown tokens (prevents information disclosure about token validity).
Revoking an access token invalidates only that token. Revoking a refresh token invalidates the entire token family.
GET /developer/integrations/{integration_id}/installations¶
List every active installation of your integration.
Request
GET /api/v1/developer/integrations/int_yourapp/installations?limit=100 HTTP/1.1
Host: api.revento.example
Authorization: Basic {base64(client_id:client_secret)}
Accept: application/vnd.revento.v1+json
Response
{
"data": [
{
"event_id": "evt_abc123",
"organization_id": "org_xyz789",
"scopes": ["event.read", "participants.read"],
"status": "active",
"connected_at": "2026-04-15T10:30:00Z",
"last_used_at": "2026-05-09T14:22:00Z"
}
],
"next_cursor": null,
"has_more": false
}
status values: active | revoked | suspended.
POST /developer/integrations/{integration_id}/rotate-webhook-secret¶
Generate a new HMAC signing secret for your integration's webhook deliveries. The previous secret remains valid for 24 hours; during the overlap window, every delivery carries two X-Revento-Signature headers (one signed with the old secret, one with the new) so you can roll the new secret to production without a downtime window.
Request: empty body.
Response
The new secret is shown once in this response — afterwards we only store its hash. Store it before navigating away.
Note on the subscription model: your integration has a single webhook URL and a single signing secret, declared in your integration manifest at registration time. There are no per-event-type subscription objects to manage — when your manifest declares an event type, you receive deliveries for it automatically as soon as you have an installation token that's authorized for the matching event.
If you need to change which event types you receive: update your integration manifest. If you need to change your webhook URL: update your manifest. Manifest edits don't trigger re-consent unless they add scopes.
API versioning¶
| Version | Status |
|---|---|
v1 |
Current |
Use the Accept header to pin a version: Accept: application/vnd.revento.v1+json. Calls without an Accept header default to the current version. Pin the header in production so a version transition can't silently change the response shape.
Any future version is supported alongside the previous one for at least 6 months after announcement, with the deprecation surfaced both in the Changelog and in your developer console.