Events
List and publish events, register participants, and manage registrations.
List events
curl "https://api.loupe.ch/api/public/cms-events?organization.slug=riveville&locale=en" \ -H "Accept: application/json"Each event carries what you need to display it:
{ "id": "0199…", "title": "Creative writing workshop", "slug": "creative-writing-workshop", "cover": { … }, "startAt": "2026-10-17 14:00", "endAt": "2026-10-17 16:00", "locationType": "address", "locationName": "Agora, level 1", "locationAddress": "…", "onlineUrl": null, "categories": [ { "id": "0199…", "name": "Workshops" } ], "enableRegistration": true, "capacity": 12, "membersOnly": false, "content": "<p>…</p>"}startAt and endAt are local times in the library's time zone. locationType is address, map (a place on the library's map), free (free text in locationName) or none; online events also carry an onlineUrl.
Filter by category with categories.id[]=<uuid>, or by title with title=. Events come most recently published first; sort them by startAt on your side for an agenda. The public list only contains published events: a cancelled event is unpublished, so it disappears from it.
Categories come from GET /api/public/cms-event-categories?organization.slug=riveville.
Show one event
curl "https://api.loupe.ch/api/public/cms-events/item?organization.slug=riveville&slug=creative-writing-workshop"Register a participant
When enableRegistration and enableEmailRegistration are both true, anyone can register with their contact details:
curl -X POST https://api.loupe.ch/api/public/cms-events/0199…/register \ -H "Content-Type: application/json" \ -d '{ "email": "camille@example.org", "firstname": "Camille", "lastname": "Martin", "guests": 1, "comment": "Wheelchair access needed" }'The API answers 200 with a token. The participant receives Loupe's confirmation e-mail, with a link to manage or cancel the registration.
guests counts the people coming with the participant; it cannot exceed the event's capacityGuests, which is 0 unless the library allows companions. Each registration takes 1 + guests seats out of capacity.
Call this endpoint without an API key: when a key is present, the registration is made in the name of the key's owner, not of the person in the body.
To make retries safe, send a confirmationId (a UUID you generate). Replaying the same request returns the original registration instead of creating a second one.
| Status | detail | Meaning |
|---|---|---|
400 | Registration disabled for this event. | Registrations are closed |
400 | Event does not allow simple email registration… | Only signed-in readers can register |
400 | Guests exceed the allowed capacity… | guests is above capacityGuests |
400 | You are already registered for this event. | Same e-mail, active registration |
400 | too_many_registration | Full; context.remaining says how many seats are left |
400 | members_only | Reserved for library members, see context.reason |
404 | Unknown or unpublished event |
Manage events
These endpoints need an API key whose owner holds the matching permission: events.create, events.update_own or events.update_any, and so on. "Own" covers the events that person created.
Create an event. It starts as a draft:
curl -X POST "https://api.loupe.ch/api/manager/cms-events?organization.slug=riveville&locale=en" \ -H "X-Api-Key: $LOUPE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Creative writing workshop", "slug": "creative-writing-workshop", "startAt": "2026-10-17 14:00", "endAt": "2026-10-17 16:00", "locationType": "free", "locationName": "Agora, level 1", "enableRegistration": true, "enableEmailRegistration": true, "capacity": 12, "capacityGuests": 2, "categories": ["/api/manager/cms-event-categories/0199…"] }'title and slug are required; the slug must be unique within the organization. Dates use the local YYYY-MM-DD HH:mm format. A capacity of 0 or null means unlimited. locale chooses the language the title and content are written in; send the same request with another locale to add a translation.
Publish or update with a merge patch. Publishing is a field, not a separate call, and needs events.publish_own or events.publish_any on top of the update permission. Set publishedAt at the same time, since public lists are ordered by it:
curl -X PATCH https://api.loupe.ch/api/manager/cms-events/0199… \ -H "X-Api-Key: $LOUPE_API_KEY" \ -H "Content-Type: application/merge-patch+json" \ -d '{ "isPublished": true, "publishedAt": "2026-10-09", "capacity": 15 }'Changes are live immediately, and each one is kept in the event's version history in the Loupe admin.
Cancel with POST /api/manager/cms-events/{id}/cancel and {"reason": "…"}. The event is unpublished, registrations close, and every participant is e-mailed the reason.
Write to participants with POST /api/manager/cms-events/{id}/notify-participants and {"subject": "…", "body": "…"} (up to 3,000 characters): each active participant receives the message by e-mail.
Duplicate with POST /api/manager/cms-events/{id}/duplicate (optional {"title": "…"}). The copy is a draft with its own slug and no registrations; it keeps the content, dates, cover, categories and registration settings.
Delete with DELETE /api/manager/cms-events/{id}. The event goes to the Loupe trash for 30 days. An event that still has registrations answers 409: cancel it first.
Registrations
| Method | Path | Use |
|---|---|---|
GET | /api/manager/cms-event-registrations?event.id=<uuid> | Registrations of an event |
POST | /api/manager/cms-event-registrations/{id}/cancel | Cancel one registration with {"reason": "…"}; the participant is e-mailed |
GET | /api/manager/statistics/cms-events?from=…&to=… | Events, registrations and attendance for a period |
These need event_registrations.own or event_registrations.any. Prefer cancelling to deleting a registration: deletion sends no e-mail and leaves no trace.