2 operations. Every schema and example on this page is generated from the platform contract.
Merchant approves or retries one no-show penalty fee: an off-session destination charge on the member's saved card (gym keeps 100%, fee-neutral application fee recovers only Stripe's cost). Atomic single-winner claim + a Stripe idempotency key make it safe against concurrent crons / double taps. Requires the gym-management entitlement and the can_waive_penalties staff permission, and the fee must belong to the authorised store. A non-ok result (no card, consent withdrawn, SCA required, store dark) is returned as a successful body with ok=false, not an HTTP error.
Store the fee belongs to (also authorises the merchant). Never trusted for identity beyond authorisation.
The gym_penalty_actions row (action_type=fee_charged) to charge or retry.
Whether the fee was collected. false = a friendly, non-error outcome the merchant UI shows.
Stripe PaymentIntent id of the successful charge.
Amount collected, in pence.
True when the fee was already collected (idempotent replay of a prior success).
Why the charge did not complete (drives the merchant-readable reason).
no_cardblocked_no_consentno_accountfailednot_chargeableUnderlying Stripe/guard failure code (e.g. authentication_required, store_dark).
Human-readable failure detail.
curl -X POST "https://www.membber.com/api/v1/penalties/fee-charges" \
-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",
"action_id": "0bd1bfc4-0000-4000-8000-d0c50000000b"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/penalties/fee-charges", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
action_id: "0bd1bfc4-0000-4000-8000-d0c50000000b"
},
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.chargeNoShowFee(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
actionId: "0bd1bfc4-0000-4000-8000-d0c50000000b"
))
).ok.body.json
print(response){
"ok": true,
"payment_intent_id": "0b6642a5-0000-4000-8000-d0c50000000b",
"amount_pence": 1500,
"already": true,
"status": "no_card",
"failure_code": "EXAMPLE10",
"error": "<error>"
}Merchant reviews the no-show penalty fees owed to their gym (the "Payments to collect" inbox), newest first, each with its collection status, amount, member, strike count, and any failure code. Optionally filtered by a comma-separated list of fee statuses. Requires the gym-management entitlement.
Store whose fees to list (also authorises the merchant).
Comma-separated fee_status filter (e.g. pending,scheduled). Empty returns all statuses.
curl -G "https://www.membber.com/api/v1/penalties/fees-owed" \
-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/penalties/fees-owed", {
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.listFeesOwed(
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"fees": [
{
"action_id": "0bd1bfc4-0000-4000-8000-d0c50000000b",
"customer_id": "96607d1c-0000-4000-8000-d0c500000096",
"customer_name": "Alex Example",
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"amount_pence": 1500,
"fee_status": "<fee_status>",
"collect_after": "<collect_after>",
"charged_at": "<charged_at>",
"failure_code": "EXAMPLE10",
"strikes_at_time": 1,
"created_at": "<created_at>"
}
]
}