Skip to Content

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

ScopeGrants
read:clubClub profile, tiers with member counts
read:membersMember list and detail: name, university email, picture, major, graduation year, roles, memberships
read:members:contactAdds private email and phone (only where the member shares it)
read:membershipsMemberships with tier, status, startDate, endDate; /memberships/active
read:memberships:paymentsMembership payments
read:tiersMembership tiers
read:eventsYour events, including members-only ones
read:events:applicationsRegistrations and application answers for an event
write:event_registrationsRegister or withdraw a member for an event
payments:create, payments:verifyMembership 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: page and limit (default 100, max 500).
  • Caching: list endpoints send an ETag. Send it back as If-None-Match to get a cheap 304.
  • Rate limit: 1000 requests per hour per key. Watch the X-RateLimit-* headers; a 429 comes with Retry-After.
  • Request IDs: every response has an X-Request-ID. Include it if you report a problem.