16 operations. Every schema and example on this page is generated from the platform contract.
Every service the store offers, each with its variants and add-ons. Scoped to the authenticated store; archived services are excluded unless asked for.
The store whose catalogue to read (must be the authenticated store).
Include archived services. Defaults to active only.
Image URLs the merchant uploaded for this service.
fixedfromper_personon_premisesonlinecustomer_sitePricing/duration variants for this service.
Optional paid add-ons that extend this service.
curl -G "https://www.membber.com/api/v1/bookings/services" \
-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/bookings/services", {
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.listBookingServices(
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"services": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"category": "<category>",
"name": "Example name",
"description": "Added at the front desk",
"images": [
"<image>"
],
"duration_min": 1,
"price_pence": 1500,
"currency": "GBP",
"price_type": "fixed",
"party_min": 1,
"party_max": 1,
"buffer_before_min": 1,
"buffer_after_min": 1,
"processing_min": 1,
"location_type": "on_premises",
"rebook_interval_days": 1,
"online_visible": true,
"sort": 1,
"is_active": true,
"variants": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"name": "Example name",
"duration_min": 1,
"price_pence": 1500,
"sort": 1,
"is_active": true
}
],
"addons": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"name": "Example name",
"extra_min": 1,
"extra_pence": 1500,
"sort": 1,
"is_active": true
}
]
}
]
}Adds a service to the authenticated store. Send a `client_token` to make the create idempotent, a retry with the same token returns the same service rather than a duplicate.
Caller-generated idempotency key. Send the same token on a retry to get the SAME service back instead of a duplicate.
What the customer books.
Uploaded image URLs.
Appointment length in minutes.
Price in the smallest currency unit.
'fixed' | 'from' | 'per_person'.
fixedfromper_personDeposit policy JSON. WRITABLE but INERT until the money stage, no charge is wired from it here.
Prep time the unit is occupied before.
Clean-up time the unit is occupied after.
on_premisesonlinecustomer_siteWhether customers can see and book this online.
Image URLs the merchant uploaded for this service.
fixedfromper_personon_premisesonlinecustomer_sitePricing/duration variants for this service.
Optional paid add-ons that extend this service.
curl -X POST "https://www.membber.com/api/v1/bookings/services" \
-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",
"name": "Example name",
"duration_min": 1
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/bookings/services", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
name: "Example name",
duration_min: 1
},
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.createBookingService(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
name: "Example name",
durationMin: 1
))
).ok.body.json
print(response){
"service": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"category": "<category>",
"name": "Example name",
"description": "Added at the front desk",
"images": [
"<image>"
],
"duration_min": 1,
"price_pence": 1500,
"currency": "GBP",
"price_type": "fixed",
"party_min": 1,
"party_max": 1,
"buffer_before_min": 1,
"buffer_after_min": 1,
"processing_min": 1,
"location_type": "on_premises",
"rebook_interval_days": 1,
"online_visible": true,
"sort": 1,
"is_active": true,
"variants": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"name": "Example name",
"duration_min": 1,
"price_pence": 1500,
"sort": 1,
"is_active": true
}
],
"addons": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"name": "Example name",
"extra_min": 1,
"extra_pence": 1500,
"sort": 1,
"is_active": true
}
]
}
}Partial update of a service the authenticated store owns. A price or duration change shapes FUTURE availability only, a booked appointment keeps the price and policy it was snapshotted with.
What the customer books.
Uploaded image URLs.
Appointment length in minutes.
Price in the smallest currency unit.
'fixed' | 'from' | 'per_person'.
fixedfromper_personDeposit policy JSON. WRITABLE but INERT until the money stage, no charge is wired from it here.
Prep time the unit is occupied before.
Clean-up time the unit is occupied after.
on_premisesonlinecustomer_siteWhether customers can see and book this online.
Image URLs the merchant uploaded for this service.
fixedfromper_personon_premisesonlinecustomer_sitePricing/duration variants for this service.
Optional paid add-ons that extend this service.
curl -X PATCH "https://www.membber.com/api/v1/bookings/services/f46cf6b0-0000-4000-8000-d0c5000000f4" \
-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.PATCH("/api/v1/bookings/services/{serviceId}", {
params: { path: { serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4" } },
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.updateBookingService(
path: .init(serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4"),
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066"
))
).ok.body.json
print(response){
"service": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"category": "<category>",
"name": "Example name",
"description": "Added at the front desk",
"images": [
"<image>"
],
"duration_min": 1,
"price_pence": 1500,
"currency": "GBP",
"price_type": "fixed",
"party_min": 1,
"party_max": 1,
"buffer_before_min": 1,
"buffer_after_min": 1,
"processing_min": 1,
"location_type": "on_premises",
"rebook_interval_days": 1,
"online_visible": true,
"sort": 1,
"is_active": true,
"variants": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"name": "Example name",
"duration_min": 1,
"price_pence": 1500,
"sort": 1,
"is_active": true
}
],
"addons": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"name": "Example name",
"extra_min": 1,
"extra_pence": 1500,
"sort": 1,
"is_active": true
}
]
}
}Adds an add-on to a service the authenticated store owns. Idempotent per `client_token`.
Caller-generated idempotency key. Send the same token on a retry to get the SAME service back instead of a duplicate.
Extra minutes this add-on adds to the appointment.
Extra charge in the smallest currency unit (INERT until the money stage).
curl -X POST "https://www.membber.com/api/v1/bookings/services/f46cf6b0-0000-4000-8000-d0c5000000f4/addons" \
-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",
"name": "Example name"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/bookings/services/{serviceId}/addons", {
params: { path: { serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4" } },
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
name: "Example name"
},
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.createBookingServiceAddon(
path: .init(serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4"),
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
name: "Example name"
))
).ok.body.json
print(response){
"addon": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"name": "Example name",
"extra_min": 1,
"extra_pence": 1500,
"sort": 1,
"is_active": true
}
}Partial update of an add-on belonging to a service the authenticated store owns.
Set false to archive this add-on.
curl -X PATCH "https://www.membber.com/api/v1/bookings/services/f46cf6b0-0000-4000-8000-d0c5000000f4/addons/bb965b7b-0000-4000-8000-d0c5000000bb" \
-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.PATCH("/api/v1/bookings/services/{serviceId}/addons/{addonId}", {
params: { path: { serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4", addonId: "bb965b7b-0000-4000-8000-d0c5000000bb" } },
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.updateBookingServiceAddon(
path: .init(serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4", addonId: "bb965b7b-0000-4000-8000-d0c5000000bb"),
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066"
))
).ok.body.json
print(response){
"addon": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"name": "Example name",
"extra_min": 1,
"extra_pence": 1500,
"sort": 1,
"is_active": true
}
}Sets the service inactive so it stops appearing in availability, but NEVER deletes it, every existing appointment keeps its snapshotted price/duration and its link to the service. Idempotent.
true once inactive (idempotent, archiving twice is a no-op).
curl -X POST "https://www.membber.com/api/v1/bookings/services/f46cf6b0-0000-4000-8000-d0c5000000f4/archive" \
-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/bookings/services/{serviceId}/archive", {
params: { path: { serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4" } },
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.archiveBookingService(
path: .init(serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4"),
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066"
))
).ok.body.json
print(response){
"service_id": "993232e5-0000-4000-8000-d0c500000099",
"archived": true
}Adds a variant to a service the authenticated store owns. Idempotent per `client_token`.
Caller-generated idempotency key. Send the same token on a retry to get the SAME service back instead of a duplicate.
Overrides the service duration for this variant.
curl -X POST "https://www.membber.com/api/v1/bookings/services/f46cf6b0-0000-4000-8000-d0c5000000f4/variants" \
-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",
"name": "Example name"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/bookings/services/{serviceId}/variants", {
params: { path: { serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4" } },
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
name: "Example name"
},
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.createBookingServiceVariant(
path: .init(serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4"),
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
name: "Example name"
))
).ok.body.json
print(response){
"variant": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"name": "Example name",
"duration_min": 1,
"price_pence": 1500,
"sort": 1,
"is_active": true
}
}Partial update of a variant belonging to a service the authenticated store owns.
Set false to archive this variant.
curl -X PATCH "https://www.membber.com/api/v1/bookings/services/f46cf6b0-0000-4000-8000-d0c5000000f4/variants/fb1b0c80-0000-4000-8000-d0c5000000fb" \
-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.PATCH("/api/v1/bookings/services/{serviceId}/variants/{variantId}", {
params: { path: { serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4", variantId: "fb1b0c80-0000-4000-8000-d0c5000000fb" } },
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.updateBookingServiceVariant(
path: .init(serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4", variantId: "fb1b0c80-0000-4000-8000-d0c5000000fb"),
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066"
))
).ok.body.json
print(response){
"variant": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"name": "Example name",
"duration_min": 1,
"price_pence": 1500,
"sort": 1,
"is_active": true
}
}Writes `stores.timezone` after validating it is a real IANA timezone. This is the anchor every day boundary, hour label and rollup in the bookings vertical reads, so an invalid value is refused rather than silently skewing a diary. Idempotent.
An IANA timezone name, e.g. "Europe/London". Validated against the runtime before it is written.
curl -X PUT "https://www.membber.com/api/v1/bookings/store-timezone" \
-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",
"timezone": "Europe/London"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.PUT("/api/v1/bookings/store-timezone", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
timezone: "Europe/London"
},
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.setStoreTimezone(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
timezone: "Europe/London"
))
).ok.body.json
print(response){
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"timezone": "Europe/London"
}Every bookable unit for the authenticated store, each carrying which services it offers. Archived units excluded unless asked for.
personspaceassetFree-text sub-type (e.g. "chair", "room").
The staff member this unit represents, when kind = person.
Diary column colour.
Whether the unit can hold appointments at all.
Whether customers can book it online (vs staff-only).
Which services this unit offers, with any per-unit overrides.
curl -G "https://www.membber.com/api/v1/bookings/units" \
-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/bookings/units", {
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.listBookableUnits(
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"units": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"kind": "person",
"unit_type": "<unit_type>",
"user_id": "f73aee0f-0000-4000-8000-d0c5000000f7",
"display_name": "<display_name>",
"bio": "<bio>",
"photo_url": "https://example.com/image.jpg",
"colour": "<colour>",
"bookable": true,
"online_bookable": true,
"sort": 1,
"is_active": true,
"services": [
{
"service_id": "993232e5-0000-4000-8000-d0c500000099",
"duration_override_min": 1,
"price_override_pence": 1500
}
]
}
]
}Adds a person / space / asset to the authenticated store. Idempotent per `client_token`.
Caller-generated idempotency key, a retry with the same token returns the SAME unit, never a duplicate.
'person' | 'space' | 'asset'. Defaults to 'person'.
personspaceassetOnly permitted when kind = person (the DB enforces this).
What the diary column is labelled.
personspaceassetFree-text sub-type (e.g. "chair", "room").
The staff member this unit represents, when kind = person.
Diary column colour.
Whether the unit can hold appointments at all.
Whether customers can book it online (vs staff-only).
Which services this unit offers, with any per-unit overrides.
curl -X POST "https://www.membber.com/api/v1/bookings/units" \
-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",
"display_name": "<display_name>"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/bookings/units", {
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
display_name: "<display_name>"
},
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.createBookableUnit(
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
displayName: "<display_name>"
))
).ok.body.json
print(response){
"unit": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"kind": "person",
"unit_type": "<unit_type>",
"user_id": "f73aee0f-0000-4000-8000-d0c5000000f7",
"display_name": "<display_name>",
"bio": "<bio>",
"photo_url": "https://example.com/image.jpg",
"colour": "<colour>",
"bookable": true,
"online_bookable": true,
"sort": 1,
"is_active": true,
"services": [
{
"service_id": "993232e5-0000-4000-8000-d0c500000099",
"duration_override_min": 1,
"price_override_pence": 1500
}
]
}
}Partial update of a unit the authenticated store owns. Archiving (is_active=false) keeps existing appointments intact.
'person' | 'space' | 'asset'. Defaults to 'person'.
personspaceassetOnly permitted when kind = person (the DB enforces this).
What the diary column is labelled.
Set false to archive the unit (existing appointments are honoured).
personspaceassetFree-text sub-type (e.g. "chair", "room").
The staff member this unit represents, when kind = person.
Diary column colour.
Whether the unit can hold appointments at all.
Whether customers can book it online (vs staff-only).
Which services this unit offers, with any per-unit overrides.
curl -X PATCH "https://www.membber.com/api/v1/bookings/units/cde691bf-0000-4000-8000-d0c5000000cd" \
-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.PATCH("/api/v1/bookings/units/{unitId}", {
params: { path: { unitId: "cde691bf-0000-4000-8000-d0c5000000cd" } },
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.updateBookableUnit(
path: .init(unitId: "cde691bf-0000-4000-8000-d0c5000000cd"),
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066"
))
).ok.body.json
print(response){
"unit": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"store_id": "6659c139-0000-4000-8000-d0c500000066",
"kind": "person",
"unit_type": "<unit_type>",
"user_id": "f73aee0f-0000-4000-8000-d0c5000000f7",
"display_name": "<display_name>",
"bio": "<bio>",
"photo_url": "https://example.com/image.jpg",
"colour": "<colour>",
"bookable": true,
"online_bookable": true,
"sort": 1,
"is_active": true,
"services": [
{
"service_id": "993232e5-0000-4000-8000-d0c500000099",
"duration_override_min": 1,
"price_override_pence": 1500
}
]
}
}Records that a unit offers a service (with optional per-unit duration/price overrides). Upsert on the (unit, service) pair, so it is idempotent, re-sending it converges rather than duplicating. Both the unit and the service must belong to the authenticated store.
The service this unit should offer (must belong to the same store).
Per-unit duration override.
Per-unit price override.
curl -X POST "https://www.membber.com/api/v1/bookings/units/cde691bf-0000-4000-8000-d0c5000000cd/services" \
-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",
"service_id": "993232e5-0000-4000-8000-d0c500000099"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/bookings/units/{unitId}/services", {
params: { path: { unitId: "cde691bf-0000-4000-8000-d0c5000000cd" } },
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
service_id: "993232e5-0000-4000-8000-d0c500000099"
},
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.setBookableUnitService(
path: .init(unitId: "cde691bf-0000-4000-8000-d0c5000000cd"),
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
serviceId: "993232e5-0000-4000-8000-d0c500000099"
))
).ok.body.json
print(response){
"unit_id": "eeebf9b6-0000-4000-8000-d0c5000000ee",
"service_id": "993232e5-0000-4000-8000-d0c500000099"
}Removes the (unit, service) mapping. Idempotent, removing one that is already gone is a no-op.
false when there was nothing to remove (idempotent).
curl -X DELETE "https://www.membber.com/api/v1/bookings/units/cde691bf-0000-4000-8000-d0c5000000cd/services/f46cf6b0-0000-4000-8000-d0c5000000f4?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/bookings/units/{unitId}/services/{serviceId}", {
params: { path: { unitId: "cde691bf-0000-4000-8000-d0c5000000cd", serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4" }, 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.removeBookableUnitService(
path: .init(unitId: "cde691bf-0000-4000-8000-d0c5000000cd", serviceId: "f46cf6b0-0000-4000-8000-d0c5000000f4"),
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"unit_id": "eeebf9b6-0000-4000-8000-d0c5000000ee",
"service_id": "993232e5-0000-4000-8000-d0c500000099",
"removed": true
}The working intervals for a unit the authenticated store owns. Multiple rows for one weekday ARE the intervals; the gaps ARE the breaks.
0 = Sunday … 6 = Saturday.
Minutes past midnight the interval starts.
Minutes past midnight the interval ends (must be after start).
True for an interval that runs past midnight.
YYYY-MM-DD the interval starts applying (null = always).
YYYY-MM-DD the interval stops applying (null = open-ended).
curl -G "https://www.membber.com/api/v1/bookings/units/cde691bf-0000-4000-8000-d0c5000000cd/working-patterns" \
-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/bookings/units/{unitId}/working-patterns", {
params: { path: { unitId: "cde691bf-0000-4000-8000-d0c5000000cd" }, 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.listUnitWorkingPatterns(
path: .init(unitId: "cde691bf-0000-4000-8000-d0c5000000cd"),
query: .init(storeId: "6659c139-0000-4000-8000-d0c500000066")
).ok.body.json
print(response){
"unit_id": "eeebf9b6-0000-4000-8000-d0c5000000ee",
"patterns": [
{
"weekday": 0,
"start_minute": 0,
"end_minute": 1,
"spans_midnight": true,
"effective_from": "<effective_from>",
"effective_to": "<effective_to>",
"id": "00000d1b-0000-4000-8000-d0c500000000"
}
]
}Swaps the unit's ENTIRE working pattern for the set you send, atomically (the old rows and the new ones never coexist, and a half-applied pattern is impossible). Idempotent, replacing with the same set converges. The unit must belong to the authenticated store.
The COMPLETE new set of intervals for this unit. Send an empty array to clear the pattern.
0 = Sunday … 6 = Saturday.
Minutes past midnight the interval starts.
Minutes past midnight the interval ends (must be after start).
True for an interval that runs past midnight.
YYYY-MM-DD the interval starts applying (null = always).
YYYY-MM-DD the interval stops applying (null = open-ended).
0 = Sunday … 6 = Saturday.
Minutes past midnight the interval starts.
Minutes past midnight the interval ends (must be after start).
True for an interval that runs past midnight.
YYYY-MM-DD the interval starts applying (null = always).
YYYY-MM-DD the interval stops applying (null = open-ended).
curl -X PUT "https://www.membber.com/api/v1/bookings/units/cde691bf-0000-4000-8000-d0c5000000cd/working-patterns" \
-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",
"patterns": [
{
"weekday": 0,
"start_minute": 0,
"end_minute": 1
}
]
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.PUT("/api/v1/bookings/units/{unitId}/working-patterns", {
params: { path: { unitId: "cde691bf-0000-4000-8000-d0c5000000cd" } },
body: {
store_id: "6659c139-0000-4000-8000-d0c500000066",
patterns: [
{
weekday: 0,
start_minute: 0,
end_minute: 1
}
]
},
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.replaceUnitWorkingPatterns(
path: .init(unitId: "cde691bf-0000-4000-8000-d0c5000000cd"),
body: .json(.init(
storeId: "6659c139-0000-4000-8000-d0c500000066",
patterns: [.init(
weekday: 0,
startMinute: 0,
endMinute: 1
)]
))
).ok.body.json
print(response){
"unit_id": "eeebf9b6-0000-4000-8000-d0c5000000ee",
"patterns": [
{
"weekday": 0,
"start_minute": 0,
"end_minute": 1,
"spans_midnight": true,
"effective_from": "<effective_from>",
"effective_to": "<effective_to>",
"id": "00000d1b-0000-4000-8000-d0c500000000"
}
]
}