7 operations. Every schema and example on this page is generated from the platform contract.
Clears cancel_at_period_end and REMOVES the voluntary-pause marker, so a later genuine card failure correctly takes the involuntary path with its dunning notice instead of silently going dormant on a months-old intent. The merchant is still fully live and fully paid up at this point, so nothing is charged. OWNER-only. Idempotent: undoing when nothing is scheduled returns was_scheduled=false with a 200.
The store whose scheduled pause should be cancelled.
True when a scheduled pause was actually cancelled. False means there was nothing to undo, a success, not a fault, so a double-tap is harmless.
curl -X DELETE "https://www.membber.com/api/v1/business/billing/pause?store_id=6659c139-0000-4000-8000-d0c500000066" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678"import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.DELETE("/api/v1/business/billing/pause", {
params: { query: { store_id: "6659c139-0000-4000-8000-d0c500000066" } },
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.resumeStore(
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"was_scheduled": true
}Sets cancel_at_period_end on the merchant's own Membber subscription and stamps the intent so the subscription-deleted webhook can tell a VOLUNTARY pause from an involuntary card-fail lapse (which must still run dunning). No charge, no refund: the store trades normally until the period ends, then goes dormant with every customer, stamp and Wallet pass intact. OWNER-only. Idempotent, re-tapping re-sets the same flag.
The store to pause (also authorises the caller).
ISO instant the store goes dormant, the end of the period already paid for. Null only if Stripe returned no period, in which case the client shows a generic end-of-period line rather than a date.
curl -X POST "https://www.membber.com/api/v1/business/billing/pause" \
-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"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/business/billing/pause", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066"
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.pauseStore(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066"
))
).ok.body.json
print(response){
"pause_effective_at": "2026-07-01T09:00:00Z"
}For a lapsed store (billing_status=suspended, prior_paid_tier=club|vip), mints a Stripe SetupIntent + ephemeral key so the native PaymentSheet can collect a card. Fails closed on an unconfigured price/key, a non-lapsed store, a gym tier (separate slice), or a still-live subscription (update the card instead). No charge here.
The lapsed store to renew (also authorises the caller).
Always "checkout", the client presents the native PaymentSheet.
SetupIntent client secret for the PaymentSheet (SETUP mode).
Customer ephemeral key secret for the PaymentSheet.
The platform Stripe customer id.
Stripe publishable key for the PaymentSheet.
The SetupIntent id, echoed back to /complete.
The standard tier being renewed (club | vip).
The monthly price in pence, for the confirm copy.
curl -X POST "https://www.membber.com/api/v1/business/billing/resubscribe/begin" \
-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"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/business/billing/resubscribe/begin", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066"
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.beginResubscribe(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066"
))
).ok.body.json
print(response){
"mode": "<mode>",
"client_secret": "<client_secret>",
"ephemeral_key_secret": "<ephemeral_key_secret>",
"customer_id": "96607d1c-0000-4000-8000-d0c500000096",
"publishable_key": "<publishable_key>",
"setup_intent_id": "fab3625c-0000-4000-8000-d0c5000000fa",
"tier": "<tier>",
"price_pence": 1500
}After the card is confirmed client-side, creates the standard-tier subscription (error_if_incomplete → the first invoice is charged now), guards the first charge (activates nothing on a decline), and reactivates the store to its prior paid tier (clearing prior_paid_tier so the renew banner disappears). Idempotent: reuses a sub created from this SetupIntent OR an already-paying sub for this tier, so a concurrent tap / retry never double-charges.
The lapsed store to renew (also authorises the caller).
The SetupIntent id returned by /begin, now card-confirmed.
The store is back on its paid plan.
The new (or reused) Stripe subscription id.
The tier reactivated (club | vip).
curl -X POST "https://www.membber.com/api/v1/business/billing/resubscribe/complete" \
-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",
"setup_intent_id": "fab3625c-0000-4000-8000-d0c5000000fa"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/business/billing/resubscribe/complete", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
setup_intent_id: "fab3625c-0000-4000-8000-d0c5000000fa"
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.completeResubscribe(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
setupIntentId: "fab3625c-0000-4000-8000-d0c5000000fa"
))
).ok.body.json
print(response){
"status": "<status>",
"subscription_id": "ac6da77d-0000-4000-8000-d0c5000000ac",
"tier": "<tier>"
}For a FREE store, mints a Stripe SetupIntent + ephemeral key so the native PaymentSheet can collect a card for the chosen tier (club|vip). Fails closed on an unconfigured price/key, a lapsed store (renew instead), a store already on a paid plan (change plan instead), or a still-live subscription. No charge here.
The free store upgrading (also authorises the caller).
The paid tier the merchant chose: club (Core) or vip (Pro).
clubvipAlways "checkout", the client presents the native PaymentSheet.
SetupIntent client secret for the PaymentSheet (SETUP mode).
Customer ephemeral key secret for the PaymentSheet.
The platform Stripe customer id.
Stripe publishable key for the PaymentSheet.
The SetupIntent id, echoed back to /complete.
The standard tier being subscribed to (club | vip).
The monthly price in pence, for the confirm copy.
curl -X POST "https://www.membber.com/api/v1/business/billing/subscribe/begin" \
-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",
"target_tier": "club"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/business/billing/subscribe/begin", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
target_tier: "club"
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.beginSubscribe(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
targetTier: .club
))
).ok.body.json
print(response){
"mode": "<mode>",
"client_secret": "<client_secret>",
"ephemeral_key_secret": "<ephemeral_key_secret>",
"customer_id": "96607d1c-0000-4000-8000-d0c500000096",
"publishable_key": "<publishable_key>",
"setup_intent_id": "fab3625c-0000-4000-8000-d0c5000000fa",
"tier": "<tier>",
"price_pence": 1500
}After the card is confirmed client-side, creates the standard-tier subscription (error_if_incomplete → the first invoice is charged now), guards the first charge (activates nothing on a decline), and moves the store onto the chosen paid tier. Idempotent: reuses a sub created from this SetupIntent OR an already-paying sub for this tier, so a concurrent tap / retry never double-charges. Shares the resubscribe money core.
The free store upgrading (also authorises the caller).
The paid tier chosen at begin; re-checked here so the card can only finalise that tier.
clubvipThe SetupIntent id returned by /begin, now card-confirmed.
The store is now on the chosen paid plan.
The new (or reused) Stripe subscription id.
The tier activated (club | vip).
curl -X POST "https://www.membber.com/api/v1/business/billing/subscribe/complete" \
-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",
"target_tier": "club",
"setup_intent_id": "fab3625c-0000-4000-8000-d0c5000000fa"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/business/billing/subscribe/complete", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
target_tier: "club",
setup_intent_id: "fab3625c-0000-4000-8000-d0c5000000fa"
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.completeSubscribe(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
targetTier: .club,
setupIntentId: "fab3625c-0000-4000-8000-d0c5000000fa"
))
).ok.body.json
print(response){
"status": "<status>",
"subscription_id": "ac6da77d-0000-4000-8000-d0c5000000ac",
"tier": "<tier>"
}Merchant fetches their special events (one-off workshops, seminars, competitions, open days) for the store, ordered by event date ascending. Active events only by default; pass include_inactive=true to include inactive ones.
Store whose events to list (also authorises the merchant).
Pass 'true' to include inactive (unpublished/archived) events. Defaults to active only.
curl -G "https://www.membber.com/api/v1/business/events" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
--data-urlencode "store_id=6659c139-0000-4000-8000-d0c500000066"import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.GET("/api/v1/business/events", {
params: { query: { store_id: "6659c139-0000-4000-8000-d0c500000066" } },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.listBusinessEvents(
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"events": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"name": "Example name",
"description": "Added at the front desk",
"event_date": "<event_date>",
"start_time": "<start_time>",
"end_time": "<end_time>",
"location": "<location>",
"price_pence": 1500,
"currency": "GBP",
"max_capacity": 1,
"is_members_only": true,
"is_active": true,
"image_url": "https://example.com/image.jpg",
"created_by": "<created_by>",
"created_at": "<created_at>",
"updated_at": "<updated_at>"
}
]
}