REST API
The REST API is for your backend: syncing members into your own tools, checking memberships, listing events, or pulling application answers. Every key belongs to one club and can only ever see that club’s data.
Reference: https://uniclubs.ch/api/external/v1/openapi.yaml. GET https://uniclubs.ch/api/external/v1 returns a quick index of the endpoints.
Keys
A club admin creates keys under Settings → API & OAuth → API keys, picks the scopes, and an expiry (default 90 days). The key is shown once. Send it on every request:
X-API-Key: sk_live_…API keys are secrets. Never put one in browser JavaScript or a public repository. For data you want to show in the browser, use the public events endpoint, which needs no key.
GET /api/external/v1/test tells you which club a key belongs to and which scopes it has.
Scopes
| Scope | Grants |
|---|---|
read:club | Club profile, tiers with member counts |
read:members | Member list and detail: name, university email, picture, major, graduation year, roles, memberships |
read:members:contact | Adds private email and phone (only where the member shares it) |
read:memberships | Memberships with tier, status, startDate, endDate; /memberships/active |
read:memberships:payments | Membership payments |
read:tiers | Membership tiers |
read:events | Your events, including members-only ones |
read:events:applications | Registrations and application answers for an event |
write:event_registrations | Register or withdraw a member for an event |
payments:create, payments:verify | Membership checkout from your own site |
Give each key only the scopes it needs.
Common recipes
Is this user a member right now?
GET /api/external/v1/members/{sub}, where sub is from sign-in. It returns all of the student’s memberships in your club, past ones included, so check for one with status: "active". A 404 means they’ve never been a member.
IDs are your club’s own. Every userId / memberId the API returns is your club’s ID for that student, the same one as sub at sign-in. It only works with your club’s key: a userId from another club resolves to nothing. Older IDs you stored (from a merged account, or global IDs from before 11 November 2026) are still accepted, and the response always carries the current ID, so update your copy when they differ.
When does a membership end? Every membership has an endDate (null = lifetime) and a status: active, expired, future, pending_payment, awaiting_approval, cancelled, or rejected. There are no webhooks yet, so poll GET /api/external/v1/memberships or /memberships/active (e.g. nightly) and compare.
Application answers for an event.
GET /api/external/v1/events/{eventId}/registrations with read:events:applications returns each registration’s status and answers to your custom questions. CVs and documents are not available via the API. Use the panel or the event export.
Conventions
- Responses are wrapped:
{ "success": true, "data": … }. Errors look like{ "success": false, "error": "…", "code": "…" }. - Pagination:
pageandlimit(default 100, max 500). - Caching: list endpoints send an
ETag. Send it back asIf-None-Matchto get a cheap304. - Rate limit: 1000 requests per hour per key. Watch the
X-RateLimit-*headers; a429comes withRetry-After. - Request IDs: every response has an
X-Request-ID. Include it if you report a problem.