Skip to content
easygym

Documentation · For developers

API and MCP server

This guide is for developers who connect a website, an app, a script or an AI assistant to a club in easygym. Everything here works with access keys the club creates itself.

In the admin:Settings

Contents

Two ways in

easygym offers a REST API for websites, apps and scripts, and an MCP server for an AI assistant that supports the Model Context Protocol. Both live at the admin address: the REST API under /v1, the MCP server at /mcp. The “API” tab in Settings shows the full addresses of your installation.

Both authenticate with the same access keys, see only the data of the club that issued the key, and book classes with the same booking logic as the member area: booking rules, capacity, the class waitlist setting and membership coverage.

Create an access key

  1. Open Settings → API. Keys are created by the club owner, administrators and roles of your own with full access to “Settings”.
  2. In “Create a key” enter a “Name”, such as the integration it is for, and tick the “Scopes” it needs.
  3. Press “Create a key” and copy the key at once: it is shown only once. easygym stores only its hash.
  4. Send it with every request in the header Authorization: Bearer followed by the key.

The “Access keys” list shows each key’s name, its visible beginning (ec_sk_live_ and a few characters), its scopes and “Last used”. “Revoke” switches a key off at once, even when the admin is read-only. Keys do not expire by themselves, so revoke the ones you no longer need. easygym support cannot issue keys, even in support mode.

A key gets no more than its creator’s role

“Scopes” offers only what the creator’s own role can do across the whole club: a role without access to members cannot create a key with contacts:read. A key keeps its scopes when roles change later, so revoke keys that should no longer have them.

Scopes

A scope has the form resource:action, and a write scope includes reading the same resource. “Scopes” in the key form offers exactly the scopes that the REST API and the MCP server check:

  • contacts:read: the contact list, and member search and member summary over MCP.
  • classes:read: the schedule with free spots.
  • bookings:read: the list of bookings.
  • bookings:write: booking a member onto a class.
  • analytics:read: club metrics over MCP.

A key created earlier may also list other scopes. No endpoint or tool requires them, and the key keeps working with the scopes above.

REST endpoints

  • GET /v1/contacts (contacts:read): contacts that are not archived, with id, uuid, first and last name, email, phone, type and join date.
  • GET /v1/classes (classes:read): classes with id, uuid, name, start and end time, capacity, price before tax, area, branch, booked places and free spots. The optional from and to parameters limit the start time.
  • GET /v1/bookings (bookings:read): bookings with id, uuid, member uuid, class name, start and end time, status, payment state and price.
  • POST /v1/bookings (bookings:write): books a member onto a class; the JSON body holds contactUuid and classUuid.

Lists come in pages. The limit parameter sets the page size, 25 by default and up to 100. The response holds data and nextCursor; send nextCursor back as the cursor parameter to get the next page, until it is null. Dates are ISO 8601 strings.

Booking through the API

POST /v1/bookings runs the same booking logic as the member area, and the key cannot override the booking rules. If a membership of the member covers the class, it is used; if none does, the booking is recorded as unpaid at the class price. A full class puts the member on the waitlist, unless the class has its waitlist turned off. A member who is already booked on the class or is on its waitlist is not booked a second time, so repeating a request does not create a duplicate.

  • 201 with data.status booked and data.bookingId, or waitlisted and data.waitlistEntryId.
  • 409 already_booked: the member is already booked on this class or is on its waitlist.
  • 409 class_full: the class is full and its waitlist is turned off.
  • 409 class_closed: the class is cancelled or completed.
  • 409 policy_blocked: the booking rules do not allow it, for example the booking window is closed or the member has no access to an online branch.
  • 404 contact_not_found or class_not_found: no such uuid in this club.
  • 400 invalid_body or missing_fields: the body is not JSON or lacks contactUuid or classUuid.

MCP server

The MCP server speaks JSON-RPC 2.0 over HTTP POST: one request, one JSON reply, protocol version 2025-06-18. initialize and tools/list work without a key; tools/call needs the key in the Authorization header with the scope of the tool. Results come back as text content and as structuredContent; a failed key check returns a JSON-RPC error with code -32001. A booking that book_class refuses comes back as a tool error (isError) with the same code as in the REST API, such as already_booked or class_full.

  • list_classes (classes:read): upcoming classes with booked places; limit up to 50, 10 by default.
  • find_member (contacts:read): search by name, phone, email or check-in code.
  • member_summary (contacts:read): by contactUuid, the member’s memberships, today’s bookings and outstanding amount.
  • club_metrics (analytics:read): the last 30 days as on the Analytics screen: active base, new and lost members, churn rate, quick ratio and attendance index.
  • book_class (bookings:write): books a member onto a class with the same logic as POST /v1/bookings.

Rate limits, errors and read-only mode

  • Up to 100 requests per minute per club: REST requests and MCP tool calls count together, across all its keys. The count starts again at the top of each minute; above the limit the API answers 429 rate_limited with a Retry-After header, the seconds left until the next minute.
  • Errors come as JSON with error.code and error.message: 401 with unauthorized, malformed, unknown, revoked or expired for key problems, and 403 scope when the key lacks the scope.
  • When the admin is read-only because an easygym invoice is unpaid, reading keeps working and writing answers 403 read_only.

No webhooks to your own server

You cannot register your own webhook: easygym does not push events to your addresses, so poll the API instead. The only webhook easygym sets up is the one in the club’s Stripe account for card payments.

Internal addresses

The /v1/access addresses are internal: they do not accept access keys and are not part of the public API.

API and MCP server · easygym