API referenceMemberships

Memberships

9 operations. Every schema and example on this page is generated from the platform contract.

List a store's memberships.

Merchant lists their store memberships for the Members screen: membership rows with embedded plan and customer, the filtered total count, and a whole-roster status rollup (active / frozen / past_due / total) on the first unsearched page. Supports status filter, server-side name/email/phone search, an exact per-customer lookup, and pagination.

Parameters

store_idstring · uuidqueryrequired

Store whose memberships to list (also authorises the merchant).

statusstringqueryoptional

Filter to a single membership status (e.g. active, frozen, past_due).

customer_idstring · uuidqueryoptional

Exact per-customer lookup, returns all of this customer's membership rows, unbounded by the page window.

searchstringqueryoptional

Server-side name/email/phone match across the whole roster.

limitintegerqueryoptional

Page size (default 50).

offsetintegerqueryoptional

Page offset (default 0).

Response, 200

membershipsarray of objectrequired
6 child fields
idstringrequired
store_idstringrequired
customer_idstring, nullableoptional
plan_idstring, nullableoptional
statusstring, nullableoptional
created_atstring, nullableoptional
totalnumberrequired
statusCountsobjectrequired
4 child fields
activenumberrequired
frozennumberrequired
past_duenumberrequired
totalnumberrequired
curl -G "https://www.membber.com/api/v1/memberships" \
  -H "Authorization: Bearer $MEMBBER_TOKEN" \
  --data-urlencode "store_id=6659c139-0000-4000-8000-d0c500000066"
Response, 200
{
  "memberships": [
    {
      "id": "00000d1b-0000-4000-8000-d0c500000000",
      "store_id": "6659c139-0000-4000-8000-d0c500000066",
      "customer_id": "96607d1c-0000-4000-8000-d0c500000096",
      "plan_id": "e28fa9f1-0000-4000-8000-d0c5000000e2",
      "status": "<status>",
      "created_at": "<created_at>"
    }
  ],
  "total": 1,
  "statusCounts": {
    "active": 1,
    "frozen": 1,
    "past_due": 1,
    "total": 1
  }
}

Enrol a customer into a membership plan.

Merchant staff enrols a customer into a gym membership plan: creates the membership and its Stripe subscription (or one-time PaymentIntent), gated by the can_use_member_billing entitlement and refused on a store that no longer serves new obligations. Money-moving. Returns the full membership row (with embedded plan + customer) for an immediate optimistic roster insert.

Request body

store_idstring · uuidrequired

Store enrolling the member (also authorises the merchant).

customer_idstring · uuidrequired

Customer to enrol into the plan.

plan_idstring · uuidrequired

The gym membership plan to enrol the customer into.

notesstring, nullableoptional

Optional free-text staff note stored on the membership.

Response, 200

membershipobjectrequired

The enrolled membership row (with embedded plan + customer when the detail read-back succeeds).

6 child fields
idstringrequired
store_idstringrequired
customer_idstring, nullableoptional
plan_idstring, nullableoptional
statusstring, nullableoptional
created_atstring, nullableoptional
curl -X POST "https://www.membber.com/api/v1/memberships" \
  -H "Authorization: Bearer $MEMBBER_TOKEN" \
  -H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
  -H "Content-Type: application/json" \
  -d '{
    "store_id": "6659c139-0000-4000-8000-d0c500000066",
    "customer_id": "96607d1c-0000-4000-8000-d0c500000096",
    "plan_id": "e28fa9f1-0000-4000-8000-d0c5000000e2"
  }'
Response, 200
{
  "membership": {
    "id": "00000d1b-0000-4000-8000-d0c500000000",
    "store_id": "6659c139-0000-4000-8000-d0c500000066",
    "customer_id": "96607d1c-0000-4000-8000-d0c500000096",
    "plan_id": "e28fa9f1-0000-4000-8000-d0c5000000e2",
    "status": "<status>",
    "created_at": "<created_at>"
  }
}

Cancel a membership at the end of its current billing period.

Merchant staff cancels a gym membership: flips the Stripe subscription to cancel at period end and records the cancellation atomically (UPDATE membership + INSERT history in one transaction), then invalidates cache, pushes the wallet update, sends the scheduled-cancellation notification, and recomputes retention analytics. Gated by the can_use_member_billing entitlement + the can_process_payments staff permission. Money-adjacent (stops future billing). Idempotent: a membership already scheduled for cancellation returns already_scheduled=true.

Parameters

idstringpathrequired

Request body

store_idstring · uuidrequired

Store the membership belongs to (also authorises the merchant).

reasonstring, nullableoptional

Optional staff reason recorded on the cancellation history row (defaults to "Staff cancelled").

Response, 200

cancellation_effective_datestring, nullablerequired

ISO timestamp the cancellation takes effect (end of current billing period).

already_scheduledbooleanrequired

True when a cancellation was already scheduled and this call was a no-op (idempotent).

curl -X POST "https://www.membber.com/api/v1/memberships/00000d1b-0000-4000-8000-d0c500000000/cancel" \
  -H "Authorization: Bearer $MEMBBER_TOKEN" \
  -H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
  -H "Content-Type: application/json" \
  -d '{
    "store_id": "6659c139-0000-4000-8000-d0c500000066"
  }'
Response, 200
{
  "cancellation_effective_date": "<cancellation_effective_date>",
  "already_scheduled": true
}

Freeze a membership: pause its Stripe billing for a set period.

Merchant staff freezes a gym membership: pauses the Stripe subscription collection (behavior: void) and records the freeze atomically (status flip + per-year freeze counters + history INSERT in one transaction), then recomputes retention analytics, refreshes the wallet pass, and pushes the customer a "membership frozen" notification. Gated by the can_use_member_billing entitlement + the can_process_payments staff permission. Enforces the freeze business rules (must be active, no pending cancellation, min-commitment met, max 2 freezes/year, min 7 days, max 90 days/year). Money-moving (changes what Stripe charges). Idempotent on (membership_id, freeze_end): a retry never double-bumps the per-year counters.

Parameters

idstringpathrequired

Request body

store_idstring · uuidrequired

Store the membership belongs to (also authorises the merchant).

freeze_endstring · date-timerequired

ISO timestamp the freeze ends (the resume date). Must be at least 7 days out.

reasonstring, nullableoptional

Optional staff reason recorded on the freeze history row. Truncated to 500 chars server-side.

Response, 200

freeze_startstringrequired

The date the freeze started (YYYY-MM-DD, server clock at the time of the call).

freeze_endstringrequired

ISO timestamp the freeze ends (echoes the requested resume date).

freeze_daysintegerrequired

Number of days the membership is frozen for.

curl -X POST "https://www.membber.com/api/v1/memberships/00000d1b-0000-4000-8000-d0c500000000/freeze" \
  -H "Authorization: Bearer $MEMBBER_TOKEN" \
  -H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
  -H "Content-Type: application/json" \
  -d '{
    "store_id": "6659c139-0000-4000-8000-d0c500000066",
    "freeze_end": "2026-07-01T09:00:00Z"
  }'
Response, 200
{
  "freeze_start": "<freeze_start>",
  "freeze_end": "<freeze_end>",
  "freeze_days": -9007199254740991
}

Preview a transferred-membership claim.

Returns the member’s imported (transferred) membership awaiting setup: plan, preserved first-charge date, the £0-today terms and the consent hash the claim must echo. Null when the member has nothing to claim at this store.

Parameters

store_idstring · uuidqueryrequired

Response, 200

claimobjectrequired
10 child fields
membership_idstringrequired
plan_idstringrequired
plan_namestringrequired
price_pencenumberrequired
billing_cyclestringrequired
first_charge_datestring, nullablerequired
first_charge_pencenumberrequired
requires_setupbooleanrequired
consent_content_hashstring, nullablerequired
consent_snapshotstring, nullablerequired
curl -G "https://www.membber.com/api/v1/memberships/claim" \
  -H "Authorization: Bearer $MEMBBER_TOKEN" \
  --data-urlencode "store_id=6659c139-0000-4000-8000-d0c500000066"
Response, 200
{
  "claim": {
    "membership_id": "bc83d224-0000-4000-8000-d0c5000000bc",
    "plan_id": "e28fa9f1-0000-4000-8000-d0c5000000e2",
    "plan_name": "<plan_name>",
    "price_pence": 1500,
    "billing_cycle": "<billing_cycle>",
    "first_charge_date": "<first_charge_date>",
    "first_charge_pence": 1500,
    "requires_setup": true,
    "consent_content_hash": "<consent_content_hash>",
    "consent_snapshot": "<consent_snapshot>"
  }
}

Claim a transferred membership (£0 today).

Creates the Stripe subscription for an imported membership with the member’s preserved billing date honoured as a free period (nothing charged today), adopting the existing membership row. Returns the SetupIntent used to save the card. Idempotent: retrying resumes the same subscription.

Request body

store_idstring · uuidrequired
billing_consent_acceptedbooleanrequired

Member accepted the claim billing terms.

billing_consent_content_hashstring, nullablerequired

Hash from the claim preview, must match the current terms.

idempotency_keystringrequired

Client-generated key; a retried claim resumes the same subscription.

Response, 200

membership_idstringrequired
requires_setupbooleanrequired
setup_intent_client_secretstring, nullablerequired
ephemeral_keystring, nullablerequired
stripe_customer_idstring, nullablerequired
connected_account_idstring, nullablerequired
first_charge_datestring, nullablerequired
first_charge_pencenumberrequired
curl -X POST "https://www.membber.com/api/v1/memberships/claim" \
  -H "Authorization: Bearer $MEMBBER_TOKEN" \
  -H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
  -H "Content-Type: application/json" \
  -d '{
    "store_id": "6659c139-0000-4000-8000-d0c500000066",
    "billing_consent_accepted": true,
    "billing_consent_content_hash": "<billing_consent_content_hash>",
    "idempotency_key": "1f0e2d3c-4b5a-4678-9abc-def012345678"
  }'
Response, 200
{
  "membership_id": "bc83d224-0000-4000-8000-d0c5000000bc",
  "requires_setup": true,
  "setup_intent_client_secret": "<setup_intent_client_secret>",
  "ephemeral_key": "<ephemeral_key>",
  "stripe_customer_id": "847b302a-0000-4000-8000-d0c500000084",
  "connected_account_id": "231b6f63-0000-4000-8000-d0c500000023",
  "first_charge_date": "<first_charge_date>",
  "first_charge_pence": 1500
}

Finish a transferred-membership claim.

Verifies the saved card on the claimed subscription and switches the membership on. Safe to retry; the billing webhooks provide the belt-and-braces path if this call is missed.

Request body

store_idstring · uuidrequired
membership_idstring · uuidrequired

Response, 200

statusstringrequired
curl -X POST "https://www.membber.com/api/v1/memberships/claim/confirm" \
  -H "Authorization: Bearer $MEMBBER_TOKEN" \
  -H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
  -H "Content-Type: application/json" \
  -d '{
    "store_id": "6659c139-0000-4000-8000-d0c500000066",
    "membership_id": "bc83d224-0000-4000-8000-d0c5000000bc"
  }'
Response, 200
{
  "status": "<status>"
}

Get the signed-in customer's membership at a store.

The customer's own membership status at a store: the active membership with classes remaining, or when they have no membership the available plans enriched with capacity (member count, is-full, spots remaining) plus any waitlist entries, the membership display config, and the self-service action config.

Parameters

store_idstring · uuidqueryrequired

Store whose membership to read for the signed-in customer.

Response, 200

has_membershipbooleanrequired
membershipobjectrequired
30 child fields
idstringrequired
store_idstringrequired
customer_idstringrequired
plan_idstringrequired
member_numbernumber, nullablerequired
statusstringrequired
status_changed_atstringrequired
stripe_subscription_idstring, nullablerequired
stripe_customer_idstring, nullablerequired
current_period_startstring, nullablerequired
current_period_endstring, nullablerequired
classes_used_this_cyclenumberrequired
cycle_reset_datestring, nullablerequired
freeze_startstring, nullablerequired
freeze_endstring, nullablerequired
freeze_reasonstring, nullablerequired
freezes_used_this_yearnumberrequired
total_freeze_days_yearnumberrequired
grace_period_startstring, nullablerequired
grace_period_endstring, nullablerequired
cancelled_atstring, nullablerequired
cancellation_effective_datestring, nullablerequired
cancellation_reasonstring, nullablerequired
min_commitment_endstring, nullablerequired
joined_atstringrequired
enrolled_bystring, nullablerequired
notesstring, nullablerequired
created_atstringrequired
updated_atstringrequired
planobjectrequired
32 child fields
idstringrequired
store_idstringrequired
namestringrequired
descriptionstring, nullablerequired
plan_typestringrequired
billing_cyclestringrequired
price_pencenumber, nullablerequired
currencystringrequired
classes_per_cyclenumber, nullablerequired
credit_expiry_daysnumber, nullablerequired
allowed_class_categoriesarray of stringrequired
allowed_time_startstring, nullablerequired
allowed_time_endstring, nullablerequired
allowed_daysarray of numberrequired
min_commitment_monthsnumberrequired
cancellation_notice_daysnumberrequired
joining_fee_pencenumberrequired
stripe_product_idstring, nullablerequired
stripe_price_idstring, nullablerequired
platform_stripe_price_idstring, nullablerequired
is_activebooleanrequired
sort_ordernumber, nullablerequired
highlight_labelstring, nullablerequired
max_membersnumber, nullablerequired
billing_cycle_typestringrequired
billing_anchor_daynumber, nullablerequired
billing_anchor_weekdaynumber, nullablerequired
billing_anchor_monthnumber, nullablerequired
proration_enabledbooleanrequired
hero_image_urlstring, nullablerequired
created_atstringrequired
updated_atstringrequired
classes_remainingnumber, nullablerequired
available_plansarray of objectrequired
35 child fields
idstringrequired
store_idstringrequired
namestringrequired
descriptionstring, nullablerequired
plan_typestringrequired
billing_cyclestringrequired
price_pencenumber, nullablerequired
currencystringrequired
classes_per_cyclenumber, nullablerequired
credit_expiry_daysnumber, nullablerequired
allowed_class_categoriesarray of stringrequired
allowed_time_startstring, nullablerequired
allowed_time_endstring, nullablerequired
allowed_daysarray of numberrequired
min_commitment_monthsnumberrequired
cancellation_notice_daysnumberrequired
joining_fee_pencenumberrequired
stripe_product_idstring, nullablerequired
stripe_price_idstring, nullablerequired
platform_stripe_price_idstring, nullablerequired
is_activebooleanrequired
sort_ordernumber, nullablerequired
highlight_labelstring, nullablerequired
max_membersnumber, nullablerequired
billing_cycle_typestringrequired
billing_anchor_daynumber, nullablerequired
billing_anchor_weekdaynumber, nullablerequired
billing_anchor_monthnumber, nullablerequired
proration_enabledbooleanrequired
hero_image_urlstring, nullablerequired
created_atstringrequired
updated_atstringrequired
member_countnumberoptional
is_fullbooleanoptional
spots_remainingnumber, nullableoptional
membership_displayobjectrequired
3 child fields
allow_self_service_signupbooleanrequired
show_prices_publiclybooleanrequired
default_picker_view_modestringrequired
qualifies_for_gym_app_homebooleanrequired
waitlist_entriesarray of objectoptional
6 child fields
idstringrequired
plan_idstringrequired
plan_namestringrequired
positionnumberrequired
statusstringrequired
joined_atstringrequired
self_service_configobjectoptional
5 child fields
allow_self_cancelbooleanrequired
allow_self_cancel_reversalbooleanrequired
allow_self_freezebooleanrequired
allow_self_resumebooleanrequired
allow_plan_changebooleanrequired
pending_price_changeobjectoptional
10 child fields
plan_namestringrequired
current_price_pencenumberrequired

What this member pays today, in pence.

new_price_pencenumberrequired

What they will pay after the change, in pence.

is_increasebooleanrequired
currencystringrequired

ISO currency of both amounts.

billing_cyclestringrequired
effective_datestringrequired

ISO timestamp the new price takes effect.

announced_atstring, nullablerequired

ISO timestamp the change was announced.

days_until_effectivenumberrequired

Whole days until the change lands. Never negative.

owner_messagestring, nullablerequired

Optional note from the store owner.

curl -G "https://www.membber.com/api/v1/memberships/me" \
  -H "Authorization: Bearer $MEMBBER_TOKEN" \
  --data-urlencode "store_id=6659c139-0000-4000-8000-d0c500000066"
Response, 200
{
  "has_membership": true,
  "membership": {
    "id": "00000d1b-0000-4000-8000-d0c500000000",
    "store_id": "6659c139-0000-4000-8000-d0c500000066",
    "customer_id": "96607d1c-0000-4000-8000-d0c500000096",
    "plan_id": "e28fa9f1-0000-4000-8000-d0c5000000e2",
    "member_number": 1,
    "status": "<status>",
    "status_changed_at": "<status_changed_at>",
    "stripe_subscription_id": "d8bc238b-0000-4000-8000-d0c5000000d8",
    "stripe_customer_id": "847b302a-0000-4000-8000-d0c500000084",
    "current_period_start": "<current_period_start>",
    "current_period_end": "<current_period_end>",
    "classes_used_this_cycle": 1,
    "cycle_reset_date": "<cycle_reset_date>",
    "freeze_start": "<freeze_start>",
    "freeze_end": "<freeze_end>",
    "freeze_reason": "Added at the front desk",
    "freezes_used_this_year": 1,
    "total_freeze_days_year": 1,
    "grace_period_start": "<grace_period_start>",
    "grace_period_end": "<grace_period_end>",
    "cancelled_at": "<cancelled_at>",
    "cancellation_effective_date": "<cancellation_effective_date>",
    "cancellation_reason": "Added at the front desk",
    "min_commitment_end": "<min_commitment_end>",
    "joined_at": "<joined_at>",
    "enrolled_by": "<enrolled_by>",
    "notes": "Added at the front desk",
    "created_at": "<created_at>",
    "updated_at": "<updated_at>",
    "plan": {
      "id": "00000d1b-0000-4000-8000-d0c500000000",
      "store_id": "6659c139-0000-4000-8000-d0c500000066",
      "name": "Example name",
      "description": "Added at the front desk",
      "plan_type": "<plan_type>",
      "billing_cycle": "<billing_cycle>",
      "price_pence": 1500,
      "currency": "GBP",
      "classes_per_cycle": 1,
      "credit_expiry_days": 1,
      "allowed_class_categories": [
        "<allowed_class_categorie>"
      ],
      "allowed_time_start": "<allowed_time_start>",
      "allowed_time_end": "<allowed_time_end>",
      "allowed_days": [
        1
      ],
      "min_commitment_months": 1,
      "cancellation_notice_days": 1,
      "joining_fee_pence": 1500,
      "stripe_product_id": "25d87d9d-0000-4000-8000-d0c500000025",
      "stripe_price_id": "588c2783-0000-4000-8000-d0c500000058",
      "platform_stripe_price_id": "a1e99fb7-0000-4000-8000-d0c5000000a1",
      "is_active": true,
      "sort_order": 1,
      "highlight_label": "<highlight_label>",
      "max_members": 1,
      "billing_cycle_type": "<billing_cycle_type>",
      "billing_anchor_day": 1,
      "billing_anchor_weekday": 1,
      "billing_anchor_month": 1,
      "proration_enabled": true,
      "hero_image_url": "https://example.com/image.jpg",
      "created_at": "<created_at>",
      "updated_at": "<updated_at>"
    }
  },
  "classes_remaining": 1,
  "available_plans": [
    {
      "id": "00000d1b-0000-4000-8000-d0c500000000",
      "store_id": "6659c139-0000-4000-8000-d0c500000066",
      "name": "Example name",
      "description": "Added at the front desk",
      "plan_type": "<plan_type>",
      "billing_cycle": "<billing_cycle>",
      "price_pence": 1500,
      "currency": "GBP",
      "classes_per_cycle": 1,
      "credit_expiry_days": 1,
      "allowed_class_categories": [
        "<allowed_class_categorie>"
      ],
      "allowed_time_start": "<allowed_time_start>",
      "allowed_time_end": "<allowed_time_end>",
      "allowed_days": [
        1
      ],
      "min_commitment_months": 1,
      "cancellation_notice_days": 1,
      "joining_fee_pence": 1500,
      "stripe_product_id": "25d87d9d-0000-4000-8000-d0c500000025",
      "stripe_price_id": "588c2783-0000-4000-8000-d0c500000058",
      "platform_stripe_price_id": "a1e99fb7-0000-4000-8000-d0c5000000a1",
      "is_active": true,
      "sort_order": 1,
      "highlight_label": "<highlight_label>",
      "max_members": 1,
      "billing_cycle_type": "<billing_cycle_type>",
      "billing_anchor_day": 1,
      "billing_anchor_weekday": 1,
      "billing_anchor_month": 1,
      "proration_enabled": true,
      "hero_image_url": "https://example.com/image.jpg",
      "created_at": "<created_at>",
      "updated_at": "<updated_at>",
      "member_count": 1,
      "is_full": true,
      "spots_remaining": 1
    }
  ],
  "membership_display": {
    "allow_self_service_signup": true,
    "show_prices_publicly": true,
    "default_picker_view_mode": "<default_picker_view_mode>"
  },
  "qualifies_for_gym_app_home": true,
  "waitlist_entries": [
    {
      "id": "00000d1b-0000-4000-8000-d0c500000000",
      "plan_id": "e28fa9f1-0000-4000-8000-d0c5000000e2",
      "plan_name": "<plan_name>",
      "position": 1,
      "status": "<status>",
      "joined_at": "<joined_at>"
    }
  ],
  "self_service_config": {
    "allow_self_cancel": true,
    "allow_self_cancel_reversal": true,
    "allow_self_freeze": true,
    "allow_self_resume": true,
    "allow_plan_change": true
  },
  "pending_price_change": {
    "plan_name": "<plan_name>",
    "current_price_pence": 1500,
    "new_price_pence": 1500,
    "is_increase": true,
    "currency": "GBP",
    "billing_cycle": "<billing_cycle>",
    "effective_date": "<effective_date>",
    "announced_at": "<announced_at>",
    "days_until_effective": 1,
    "owner_message": "Added at the front desk"
  }
}

Cancel the signed-in customer's own membership at the end of the current billing period.

The signed-in customer cancels their OWN gym membership: gated by the gym allow_self_cancel toggle, it flips the Stripe subscription to cancel at period end and records the cancellation atomically (UPDATE membership + INSERT history in one transaction), then invalidates cache, pushes the wallet update, sends the scheduled-cancellation notification, and recomputes retention analytics. Money-adjacent (stops future billing, no partial refund). Idempotent: a membership already scheduled for cancellation returns already_scheduled=true.

Request body

store_idstring · uuidrequired

Store whose membership the signed-in customer is cancelling (gates the gym's self-cancel toggle).

reasonstring, nullableoptional

Optional member reason recorded on the cancellation history row (defaults to null). Truncated to 500 chars server-side.

Response, 200

cancellation_effective_datestring, nullablerequired

ISO timestamp the cancellation takes effect (end of current billing period).

already_scheduledbooleanrequired

True when a cancellation was already scheduled and this call was a no-op (idempotent).

curl -X POST "https://www.membber.com/api/v1/memberships/me/cancel" \
  -H "Authorization: Bearer $MEMBBER_TOKEN" \
  -H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
  -H "Content-Type: application/json" \
  -d '{
    "store_id": "6659c139-0000-4000-8000-d0c500000066"
  }'
Response, 200
{
  "cancellation_effective_date": "<cancellation_effective_date>",
  "already_scheduled": true
}
WhatsApp
Book a Call
Start Free