7 operations. Every schema and example on this page is generated from the platform contract.
Writes staged rows to live tables: customers (merge-or-create), memberships in awaiting-payment state, class-pack balances and historical visits. No member is contacted, nothing is charged, no Stripe objects are created. Exactly-once per row via DB unique guards; a 7-day undo window opens on completion.
curl -X POST "https://www.membber.com/api/v1/import/commit" \
-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",
"job_id": "bb2be0dd-0000-4000-8000-d0c5000000bb"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/import/commit", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
job_id: "bb2be0dd-0000-4000-8000-d0c5000000bb"
},
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.commitImportJob(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
jobId: "bb2be0dd-0000-4000-8000-d0c5000000bb"
))
).ok.body.json
print(response){
"started": true,
"progress": {
"total": 1,
"done": 1,
"counts": {}
}
}Sends the store-branded claim invite (transactional service-transfer notice) to imported members who have not yet claimed their account. Explicit merchant action only, the import itself never contacts members. One initial wave and one reminder wave per import.
'initial' then 'reminder' (day 3) then 'reminder2' (day 7 final); each sends once. Reminders also fire automatically via the hourly journey cron.
initialreminderreminder2curl -X POST "https://www.membber.com/api/v1/import/invites" \
-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",
"job_id": "bb2be0dd-0000-4000-8000-d0c5000000bb",
"wave": "initial"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/import/invites", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
job_id: "bb2be0dd-0000-4000-8000-d0c5000000bb",
wave: "initial"
},
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.sendImportInvites(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
jobId: "bb2be0dd-0000-4000-8000-d0c5000000bb",
wave: .initial
))
).ok.body.json
print(response){
"sent": 1,
"already_claimed": 1,
"no_email": 1,
"failed": 1
}Job header, uploaded file summaries, plan-match decisions, dry-run report and live row progress for the store’s import.
Store whose import job to fetch (authorises the merchant).
Specific job; defaults to the most recent job for the store.
draftparsingmappedpreviewedimportingdonefailedundoneclientsautopayspassesvisitsmapcreateskipRe-card funnel, present once the import is committed.
curl -G "https://www.membber.com/api/v1/import/jobs" \
-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/import/jobs", {
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.getImportJob(
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"state": {
"job": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"source": "<source>",
"status": "draft",
"counts": {},
"dry_run_report": {},
"committed_at": "<committed_at>",
"undo_deadline": "<undo_deadline>",
"created_at": "<created_at>"
},
"files": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"kind": "clients",
"original_name": "<original_name>",
"row_count": 1,
"created_at": "<created_at>"
}
],
"plan_matches": [
{
"source_name": "<source_name>",
"action": "map",
"matched_plan_id": "1c4475d6-0000-4000-8000-d0c50000001c"
}
],
"progress": {
"total": 1,
"done": 1,
"counts": {}
},
"funnel": {
"imported_members": 1,
"claimed": 1,
"active_billing": 1,
"awaiting": 1,
"monthly_value_pence": 1500,
"invites": {
"initial_at": "<initial_at>",
"initial_sent": 1,
"reminder_at": "<reminder_at>",
"reminder_sent": 1,
"reminder2_at": "<reminder2_at>",
"reminder2_sent": 1
}
}
}
}Creates a draft import job for the store, or returns the existing editable one. Files are attached via the multipart upload endpoint; nothing is written to live tables until commit.
Store starting (or resuming) a Mindbody import. Authorises the merchant.
draftparsingmappedpreviewedimportingdonefailedundonecurl -X POST "https://www.membber.com/api/v1/import/jobs" \
-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/import/jobs", {
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.createImportJob(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066"
))
).ok.body.json
print(response){
"job": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"source": "<source>",
"status": "draft",
"counts": {},
"dry_run_report": {},
"committed_at": "<committed_at>",
"undo_deadline": "<undo_deadline>",
"created_at": "<created_at>"
}
}Records the merchant’s mapping decision for one Mindbody contract/pass name. Idempotent upsert per (job, name).
The Mindbody contract/pass name being decided.
'map' links to an existing Membber plan; 'skip' leaves these rows unimported.
mapskipRequired when action is 'map'.
curl -X POST "https://www.membber.com/api/v1/import/plan-match" \
-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",
"job_id": "bb2be0dd-0000-4000-8000-d0c5000000bb",
"source_name": "<source_name>",
"action": "map",
"plan_id": "e28fa9f1-0000-4000-8000-d0c5000000e2"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/import/plan-match", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
job_id: "bb2be0dd-0000-4000-8000-d0c5000000bb",
source_name: "<source_name>",
action: "map",
plan_id: "e28fa9f1-0000-4000-8000-d0c5000000e2"
},
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.setImportPlanMatch(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
jobId: "bb2be0dd-0000-4000-8000-d0c5000000bb",
sourceName: "<source_name>",
action: .map,
planId: "e28fa9f1-0000-4000-8000-d0c5000000e2"
))
).ok.body.json
print(response){
"ok": true
}Deletes customers, awaiting-payment memberships and imported visit history created by this job. Customers who have since claimed their account or hold a live billing membership are kept (never deleted by undo).
curl -X POST "https://www.membber.com/api/v1/import/undo" \
-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",
"job_id": "bb2be0dd-0000-4000-8000-d0c5000000bb"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/import/undo", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
job_id: "bb2be0dd-0000-4000-8000-d0c5000000bb"
},
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.undoImportJob(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
jobId: "bb2be0dd-0000-4000-8000-d0c5000000bb"
))
).ok.body.json
print(response){
"ok": true,
"deleted": 1,
"kept": 1
}Parses, sniffs (clients/autopays/passes/visits), validates and stages one Mindbody export. Re-uploading the same kind replaces it. Returns merchant-readable issue counts and the refreshed dry-run preview; live tables are untouched.
Existing job; a draft is created/resumed when absent.
Which Mindbody export this is; auto-detected from headers when omitted.
clientsautopayspassesvisitsThe raw CSV text (UTF-8). Mindbody exports are comfortably under this cap; split visit exports by date range if needed.
clientsautopayspassesvisitsclientsautopayspassesvisitscurl -X POST "https://www.membber.com/api/v1/import/upload" \
-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",
"file_name": "<file_name>",
"content": "<content>"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/import/upload", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
file_name: "<file_name>",
content: "<content>"
},
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.uploadImportFile(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
fileName: "<file_name>",
content: "<content>"
))
).ok.body.json
print(response){
"job_id": "bb2be0dd-0000-4000-8000-d0c5000000bb",
"kind": "clients",
"summary": {
"kind": "clients",
"total": 1,
"valid": 1,
"warnings": 1,
"errors": 1,
"issue_counts": {}
},
"preview": {}
}