curl --request POST \
--url https://api.1club.ai/v1/platform/classes/{id}/bookings \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"payment": {
"amount": 123,
"reference": "<string>",
"fee": 123
},
"contactId": 123,
"notes": "<string>",
"notifyCustomer": true
}
'import requests
url = "https://api.1club.ai/v1/platform/classes/{id}/bookings"
payload = {
"payment": {
"amount": 123,
"reference": "<string>",
"fee": 123
},
"contactId": 123,
"notes": "<string>",
"notifyCustomer": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
payment: {amount: 123, reference: '<string>', fee: 123},
contactId: 123,
notes: '<string>',
notifyCustomer: true
})
};
fetch('https://api.1club.ai/v1/platform/classes/{id}/bookings', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.1club.ai/v1/platform/classes/{id}/bookings",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'payment' => [
'amount' => 123,
'reference' => '<string>',
'fee' => 123
],
'contactId' => 123,
'notes' => '<string>',
'notifyCustomer' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.1club.ai/v1/platform/classes/{id}/bookings"
payload := strings.NewReader("{\n \"payment\": {\n \"amount\": 123,\n \"reference\": \"<string>\",\n \"fee\": 123\n },\n \"contactId\": 123,\n \"notes\": \"<string>\",\n \"notifyCustomer\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.1club.ai/v1/platform/classes/{id}/bookings")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"payment\": {\n \"amount\": 123,\n \"reference\": \"<string>\",\n \"fee\": 123\n },\n \"contactId\": 123,\n \"notes\": \"<string>\",\n \"notifyCustomer\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.1club.ai/v1/platform/classes/{id}/bookings")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"payment\": {\n \"amount\": 123,\n \"reference\": \"<string>\",\n \"fee\": 123\n },\n \"contactId\": 123,\n \"notes\": \"<string>\",\n \"notifyCustomer\": true\n}"
response = http.request(request)
puts response.read_body{
"bookingId": 123,
"bookingUuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "<string>",
"areaId": 123,
"classId": 123,
"eventId": 123,
"maxPlayers": 123,
"instructorId": 123,
"contactId": 123,
"startTime": "2023-11-07T05:31:56Z",
"endTime": "2023-11-07T05:31:56Z",
"customer": {
"id": 123,
"uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"firstName": "<string>",
"lastName": "<string>",
"email": "<string>",
"phone": "<string>",
"type": "<string>",
"pipelineStageId": 123,
"sourceId": 123,
"assignedToId": 123,
"createdAt": "2023-11-07T05:31:56Z"
},
"money": {
"billed": 123,
"billedExTax": 123,
"paid": 123,
"outstanding": 123,
"paymentState": "<string>",
"paymentStatus": "<string>",
"charges": [
{
"transactionId": 123,
"transactionType": "<string>",
"payerContactId": 123,
"date": "2023-11-07T05:31:56Z",
"paymentStatus": "<string>",
"amount": 123,
"paidAmount": 123,
"refundedAmount": 123,
"outstandingAmount": 123,
"invoiceIds": [
123
],
"orderId": 123
}
],
"credits": [
{
"transactionId": 123,
"chargeTransactionId": 123,
"amount": 123,
"paymentStatus": "<string>",
"date": "2023-11-07T05:31:56Z"
}
],
"payments": [
{
"paymentId": 123,
"amount": 123,
"status": "<string>",
"method": "<string>",
"source": "<string>",
"reference": "<string>",
"paidAt": "2023-11-07T05:31:56Z",
"transactionIds": [
123
]
}
],
"refunds": [
{
"refundId": 123,
"transactionId": 123,
"paymentId": 123,
"amount": 123,
"destination": "stripe",
"reason": "<string>",
"refundedAt": "2023-11-07T05:31:56Z"
}
]
},
"cancellation": {
"terms": {
"acceptedAt": "2023-11-07T05:31:56Z",
"rules": [
{
"hoursInAdvance": 123,
"refundPercentage": 123,
"description": "<string>"
}
],
"deadlines": [
{
"until": "2023-11-07T05:31:56Z",
"refundPercentage": 123
}
],
"freeCancellationUntil": "2023-11-07T05:31:56Z",
"fullyCovered": true,
"collectsFromWallet": true,
"waiver": {
"at": "2023-11-07T05:31:56Z",
"byUserId": 123,
"reason": "<string>"
}
},
"cancelled": {
"at": "2023-11-07T05:31:56Z",
"by": {
"userId": 123,
"name": "<string>"
},
"reason": "<string>",
"noticeHours": 123,
"refundPercentage": 123,
"refundAmount": 123,
"policyWaived": true,
"notes": "<string>"
}
},
"payment": {
"status": "paid",
"amount": 123,
"paidAmount": 123,
"refundedAmount": 123,
"reference": "<string>",
"fee": 123
}
}{
"error": "<string>",
"code": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"details": {}
}Book a customer into a class
Enrols one customer in a class occurrence - the booking the club’s own staff make when they add someone to a class. The seat takes the class’s time, club and price; capacity, the class’s booking policy, a waitlist entry the customer already holds (converted into this booking) and the “already on this class” check all apply exactly as they do in the admin portal. Identify the customer with contactId (resolve it via GET /v1/platform/contacts) or with an inline customer matched to a contact by email and created if new - exactly one of the two.
Payment works as on POST /v1/platform/bookings: paid records the seat as settled against a payment method named after your API key (no gateway call), unpaid leaves it outstanding, and amount is the price. With unpaid and no amount, the seat is paid for the way the club’s own staff would default it: a membership of the customer’s that covers the class is used (one session is spent and nothing is owed), and otherwise the class price is recorded as owed. With an API key that needs the customer named by contactId: an inline customer never spends a membership, and the class price is recorded as owed.
A full class, a cancelled one and one that has already run are refused; nothing here overrides them. Returns the same booking as POST /v1/platform/bookings, with classId set.
curl --request POST \
--url https://api.1club.ai/v1/platform/classes/{id}/bookings \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"payment": {
"amount": 123,
"reference": "<string>",
"fee": 123
},
"contactId": 123,
"notes": "<string>",
"notifyCustomer": true
}
'import requests
url = "https://api.1club.ai/v1/platform/classes/{id}/bookings"
payload = {
"payment": {
"amount": 123,
"reference": "<string>",
"fee": 123
},
"contactId": 123,
"notes": "<string>",
"notifyCustomer": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
payment: {amount: 123, reference: '<string>', fee: 123},
contactId: 123,
notes: '<string>',
notifyCustomer: true
})
};
fetch('https://api.1club.ai/v1/platform/classes/{id}/bookings', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.1club.ai/v1/platform/classes/{id}/bookings",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'payment' => [
'amount' => 123,
'reference' => '<string>',
'fee' => 123
],
'contactId' => 123,
'notes' => '<string>',
'notifyCustomer' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.1club.ai/v1/platform/classes/{id}/bookings"
payload := strings.NewReader("{\n \"payment\": {\n \"amount\": 123,\n \"reference\": \"<string>\",\n \"fee\": 123\n },\n \"contactId\": 123,\n \"notes\": \"<string>\",\n \"notifyCustomer\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.1club.ai/v1/platform/classes/{id}/bookings")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"payment\": {\n \"amount\": 123,\n \"reference\": \"<string>\",\n \"fee\": 123\n },\n \"contactId\": 123,\n \"notes\": \"<string>\",\n \"notifyCustomer\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.1club.ai/v1/platform/classes/{id}/bookings")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"payment\": {\n \"amount\": 123,\n \"reference\": \"<string>\",\n \"fee\": 123\n },\n \"contactId\": 123,\n \"notes\": \"<string>\",\n \"notifyCustomer\": true\n}"
response = http.request(request)
puts response.read_body{
"bookingId": 123,
"bookingUuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "<string>",
"areaId": 123,
"classId": 123,
"eventId": 123,
"maxPlayers": 123,
"instructorId": 123,
"contactId": 123,
"startTime": "2023-11-07T05:31:56Z",
"endTime": "2023-11-07T05:31:56Z",
"customer": {
"id": 123,
"uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"firstName": "<string>",
"lastName": "<string>",
"email": "<string>",
"phone": "<string>",
"type": "<string>",
"pipelineStageId": 123,
"sourceId": 123,
"assignedToId": 123,
"createdAt": "2023-11-07T05:31:56Z"
},
"money": {
"billed": 123,
"billedExTax": 123,
"paid": 123,
"outstanding": 123,
"paymentState": "<string>",
"paymentStatus": "<string>",
"charges": [
{
"transactionId": 123,
"transactionType": "<string>",
"payerContactId": 123,
"date": "2023-11-07T05:31:56Z",
"paymentStatus": "<string>",
"amount": 123,
"paidAmount": 123,
"refundedAmount": 123,
"outstandingAmount": 123,
"invoiceIds": [
123
],
"orderId": 123
}
],
"credits": [
{
"transactionId": 123,
"chargeTransactionId": 123,
"amount": 123,
"paymentStatus": "<string>",
"date": "2023-11-07T05:31:56Z"
}
],
"payments": [
{
"paymentId": 123,
"amount": 123,
"status": "<string>",
"method": "<string>",
"source": "<string>",
"reference": "<string>",
"paidAt": "2023-11-07T05:31:56Z",
"transactionIds": [
123
]
}
],
"refunds": [
{
"refundId": 123,
"transactionId": 123,
"paymentId": 123,
"amount": 123,
"destination": "stripe",
"reason": "<string>",
"refundedAt": "2023-11-07T05:31:56Z"
}
]
},
"cancellation": {
"terms": {
"acceptedAt": "2023-11-07T05:31:56Z",
"rules": [
{
"hoursInAdvance": 123,
"refundPercentage": 123,
"description": "<string>"
}
],
"deadlines": [
{
"until": "2023-11-07T05:31:56Z",
"refundPercentage": 123
}
],
"freeCancellationUntil": "2023-11-07T05:31:56Z",
"fullyCovered": true,
"collectsFromWallet": true,
"waiver": {
"at": "2023-11-07T05:31:56Z",
"byUserId": 123,
"reason": "<string>"
}
},
"cancelled": {
"at": "2023-11-07T05:31:56Z",
"by": {
"userId": 123,
"name": "<string>"
},
"reason": "<string>",
"noticeHours": 123,
"refundPercentage": 123,
"refundAmount": 123,
"policyWaived": true,
"notes": "<string>"
}
},
"payment": {
"status": "paid",
"amount": 123,
"paidAmount": 123,
"refundedAmount": 123,
"reference": "<string>",
"fee": 123
}
}{
"error": "<string>",
"code": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"details": {}
}{
"error": "<string>",
"code": "<string>",
"details": {}
}Authorizations
Organization-scoped bearer credential: a customer API key (1club_sk_live_...) or an MCP OAuth access token.
Headers
Retry-safe key; a repeat of the same request replays the first response
255Path Parameters
Class occurrence id (from GET /v1/platform/classes)
Body
Show child attributes
Show child attributes
Existing contact to book for (from GET /v1/platform/contacts). Mutually exclusive with customer.
Inline find-or-create by email. Mutually exclusive with contactId.
Show child attributes
Show child attributes
2000Tell the customer they are booked - email plus the in-app, WhatsApp and SMS notification. Off by default for an API key, on by default over an OAuth connection, as on POST /v1/platform/bookings.
Response
Booking created
A booking created through the platform API. Recorded with a booking transaction so it counts for revenue, marked paid (settled against a payment method named after the caller's API key, so the club can reconcile what each partner collected) or unpaid (outstanding) per the caller. Collection stays with the caller; what it collected and what it gave back on cancellation are reported in payment.
1club booking id
Stable unguessable identifier. Prefer this over bookingId when storing a reference.
Booking status (e.g. confirmed, cancelled)
Area id
The class occurrence this booking attends, when it is a class booking. Every attendee holds their own booking row against the same classId, and classes rows are per-occurrence - so this is what tells two classes running in the same hour apart. Join it against GET /v1/platform/classes, or read the roster with GET /v1/platform/classes/{id}/bookings.
The event this booking attends, when it is an event booking
How many players the booking takes, the organizer included, when it differs from the area type's defaultMaxPlayers: 2 on a court booked for singles (area types with allowsSingles). null means the area type's own limit. Adding a player past it is refused.
Instructor leading the session, when one is attached
Contact the booking is for
The booking's customer, identical to what GET /v1/platform/contacts/{id} returns. Present only when the request passes include=customer, which additionally requires the contacts:read scope; null when the booking has no contact. Use it to import a window of bookings without a contact lookup per row.
Show child attributes
Show child attributes
What the booking costs and how it was paid. Present only with include=money, which additionally requires the transactions:read scope. billed is always paid + outstanding, on the same basis as the admin's Booking audit: tax-inclusive, net of refunds, so a cancelled booking bills only the Cancellation Charge it kept.
Show child attributes
Show child attributes
The cancellation terms stamped on the booking and how it was cancelled. Present only with include=cancellation.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Was this page helpful?