3 operations. Every schema and example on this page is generated from the platform contract.
Public, pre-membership read for the customer app: the config-driven onboarding steps a first-time customer sees when joining a store (café / salon / retail / general). Resolves the family default set (selected from the store's category) overlaid with any merchant edits, returned enabled-only and in order. Separate from the gym member fitness-profile flow. Only publicly displayable step definitions are returned, never PII.
Store whose onboarding flow to fetch.
food_drinkbeautyretailfitnessgeneralwelcomenamenotificationsmarketing_opt_interms_privacycelebrateLegacy media_assets reference. Kept for installed binaries; new clients use the resolved URLs below.
Full-bleed still for this step, from the store's own media.
Silent looping video for this step. Clients must respect Reduce Motion and fall back to posterUrl/imageUrl.
First-frame still for videoUrl, shown while the video loads and instead of it under Reduce Motion.
Tiny blurred placeholder so a slow image never renders as a grey box.
Crop anchor when the asset is cropped to fill. Defaults to center.
centertopbottomStable hash of the resolved steps, the completion/seen key: a merchant edit changes it and re-triggers onboarding once.
Which of the store's surfaces to open when onboarding completes, derived from what the store can actually do.
menuschedulecardchatWhat the celebration screen can honestly show this customer, computed from real store data.
curl -G "https://www.membber.com/api/v1/store-onboarding" \
--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/store-onboarding", {
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.getStoreOnboarding(
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"version": 1,
"store": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"name": "Example name"
},
"family": "food_drink",
"steps": [
{
"kind": "welcome",
"enabled": true,
"required": true,
"order": 1,
"copy": {
"title": "Morning class",
"body": "<body>",
"cta": "<cta>"
},
"media": {
"heroRef": "<heroRef>",
"imageUrl": "https://example.com/image.jpg",
"videoUrl": "https://example.com/image.jpg",
"posterUrl": "https://example.com/image.jpg",
"blurhash": "<blurhash>",
"focus": "center"
}
}
],
"config_hash": "<config_hash>",
"landing": "menu",
"finale": "<finale>"
}Persists a per-customer-per-store completion (with the completed config hash) so the welcome flow dedupes across devices and reinstalls, and a merchant edit (new hash) re-triggers it once.
Store whose onboarding the customer finished.
The config_hash the customer completed (from getStoreOnboarding).
curl -X POST "https://www.membber.com/api/v1/store-onboarding/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",
"config_hash": "<config_hash>"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/store-onboarding/complete", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
config_hash: "<config_hash>"
},
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.completeStoreOnboarding(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
configHash: "<config_hash>"
))
).ok.body.json
print(response){
"recorded": true
}Store to check.
True when the customer completed onboarding at the CURRENT config hash.
The current config hash (also returned by getStoreOnboarding).
curl -G "https://www.membber.com/api/v1/store-onboarding/status" \
-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/store-onboarding/status", {
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.getStoreOnboardingStatus(
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"completed": true,
"config_hash": "<config_hash>"
}