Products, payments, and bookings
Create a product
curl -X POST "$BOOKING_URL/api/products" \
-H "Authorization: Bearer $BOOKING_SESSION" \
-H "Content-Type: application/json" \
-d '{
"type":"class_pass",
"name":"Ten class pass",
"prices":[{"amount":120000,"currency":"DKK"}],
"classAllowance":10,
"validityDays":180,
"status":"active"
}'Supported types are drop_in, subscription, class_pass, workshop, teacher_training, and other.
Every product has one or more price options. Subscription prices additionally require a cadence:
{
"type": "subscription",
"name": "Membership",
"prices": [
{
"amount": 69500,
"currency": "DKK",
"cadence": { "unit": "month", "count": 1 }
},
{
"amount": 695000,
"currency": "DKK",
"cadence": { "unit": "year", "count": 1 }
}
]
}Purchase
An authenticated user purchases with POST /api/products/{productId}/purchases. Pass { "priceId": "PRICE_ID" } when the product has multiple options. A paid result creates an entitlement automatically. Purchases require an active payment connection.
Attendees list their active access with GET /api/entitlements. Class-pass entitlements include remainingClasses and may include expiresAt; subscription entitlements include renewsAt and a snapshot of the purchased price and cadence. A consumer should show these before offering a new purchase.
The hosted service checks due subscriptions hourly. A successful MobilePay charge creates a payment record and advances renewsAt by the purchased cadence; a failed charge revokes access. Operators can also trigger the same due-item scan with POST /api/subscriptions/renewals/run.
An attendee cancels their own membership with PATCH /api/entitlements/{entitlementId} and { "action": "cancel" }. Cancellation revokes the entitlement immediately, removes renewsAt, and prevents future renewal attempts. Owners and administrators may perform the same action for account support.
Book with an entitlement
{
"instanceId": "INSTANCE_ID",
"entitlementId": "ENTITLEMENT_ID"
}Book with a drop-in payment
{
"instanceId": "INSTANCE_ID",
"productId": "DROP_IN_PRODUCT_ID",
"priceId": "DROP_IN_PRICE_ID"
}Post either body to /api/bookings. priceId can be omitted when a drop-in has exactly one price. The API checks cancellation, audience, group participation, capacity, entitlement ownership/expiry/allowance, and payment outcome atomically.
When an eligible active entitlement exists, submit its entitlementId directly. Do not start another payment flow. The booking consumes one remaining class for a limited pass and uses a subscription without creating a new payment.
Attendees see their own bookings with GET /api/bookings; elevated operational roles see all bookings in their account. Delete /api/bookings/{bookingId} to cancel. Cancelling an entitlement-funded booking restores one remaining class where applicable.