curl --request POST \
--url https://api.1club.ai/v1/platform/bookings \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"areaId": 123,
"startTime": "2023-11-07T05:31:56Z",
"endTime": "2023-11-07T05:31:56Z",
"payment": {
"amount": 123,
"reference": "<string>",
"fee": 123
},
"contactId": 123,
"instructorId": 123,
"channel": "<string>",
"notes": "<string>",
"notifyCustomer": true
}
'import requests
url = "https://api.1club.ai/v1/platform/bookings"
payload = {
"areaId": 123,
"startTime": "2023-11-07T05:31:56Z",
"endTime": "2023-11-07T05:31:56Z",
"payment": {
"amount": 123,
"reference": "<string>",
"fee": 123
},
"contactId": 123,
"instructorId": 123,
"channel": "<string>",
"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({
areaId: 123,
startTime: '2023-11-07T05:31:56Z',
endTime: '2023-11-07T05:31:56Z',
payment: {amount: 123, reference: '<string>', fee: 123},
contactId: 123,
instructorId: 123,
channel: '<string>',
notes: '<string>',
notifyCustomer: true
})
};
fetch('https://api.1club.ai/v1/platform/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/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([
'areaId' => 123,
'startTime' => '2023-11-07T05:31:56Z',
'endTime' => '2023-11-07T05:31:56Z',
'payment' => [
'amount' => 123,
'reference' => '<string>',
'fee' => 123
],
'contactId' => 123,
'instructorId' => 123,
'channel' => '<string>',
'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/bookings"
payload := strings.NewReader("{\n \"areaId\": 123,\n \"startTime\": \"2023-11-07T05:31:56Z\",\n \"endTime\": \"2023-11-07T05:31:56Z\",\n \"payment\": {\n \"amount\": 123,\n \"reference\": \"<string>\",\n \"fee\": 123\n },\n \"contactId\": 123,\n \"instructorId\": 123,\n \"channel\": \"<string>\",\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/bookings")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"areaId\": 123,\n \"startTime\": \"2023-11-07T05:31:56Z\",\n \"endTime\": \"2023-11-07T05:31:56Z\",\n \"payment\": {\n \"amount\": 123,\n \"reference\": \"<string>\",\n \"fee\": 123\n },\n \"contactId\": 123,\n \"instructorId\": 123,\n \"channel\": \"<string>\",\n \"notes\": \"<string>\",\n \"notifyCustomer\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.1club.ai/v1/platform/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 \"areaId\": 123,\n \"startTime\": \"2023-11-07T05:31:56Z\",\n \"endTime\": \"2023-11-07T05:31:56Z\",\n \"payment\": {\n \"amount\": 123,\n \"reference\": \"<string>\",\n \"fee\": 123\n },\n \"contactId\": 123,\n \"instructorId\": 123,\n \"channel\": \"<string>\",\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>",
"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": {}
}Create a booking
Creates a booking on an area (e.g. a padel court), optionally with an instructor leading the session. Identify the customer with contactId (resolve it via GET /v1/platform/contacts) or, for callers that do not track 1club ids, with an inline customer matched to a contact by email and created if new - exactly one of the two.
A booking transaction is recorded so the booking counts for revenue: paid marks it settled against a payment method named after your API key (no gateway call), so the club can see and reconcile what you collected separately from every other channel; unpaid leaves it outstanding. amount is the price the customer paid for the booking, before any fee you kept, and defaults to the computed price for the slot - the area’s price, plus the instructor’s hourly rate when one is attached. Send your own payment id as payment.reference and your commission as payment.fee: the sale is recorded at amount, and the fee is what the club reconciles against your payout statement.
This API assumes the calling system enforces its own booking rules, so 1club’s member-facing policy (minimum notice, maximum days in advance, operating-hours envelope, slots that have already ended, instructor availability) is not applied - which is what lets an existing schedule be recorded as-is.
What the club physically has is never overridden, and a booking that breaks one of these is refused with 400 and a populated details.conflicts[]: the area’s concurrency capacity (AREA_AT_CAPACITY), a court the club has blocked for maintenance or a private hire (AREA_BLOCKED), a live event on the court (AREA_RUNNING_EVENT), the instructor already booked or teaching (INSTRUCTOR_AT_CAPACITY, INSTRUCTOR_TEACHING_CLASS, INSTRUCTOR_RUNNING_EVENT), whether an instructor takes one-on-one bookings, and the slot alignment the area requires. There is no override parameter: a conflict is a refusal, not a warning.
curl --request POST \
--url https://api.1club.ai/v1/platform/bookings \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"areaId": 123,
"startTime": "2023-11-07T05:31:56Z",
"endTime": "2023-11-07T05:31:56Z",
"payment": {
"amount": 123,
"reference": "<string>",
"fee": 123
},
"contactId": 123,
"instructorId": 123,
"channel": "<string>",
"notes": "<string>",
"notifyCustomer": true
}
'import requests
url = "https://api.1club.ai/v1/platform/bookings"
payload = {
"areaId": 123,
"startTime": "2023-11-07T05:31:56Z",
"endTime": "2023-11-07T05:31:56Z",
"payment": {
"amount": 123,
"reference": "<string>",
"fee": 123
},
"contactId": 123,
"instructorId": 123,
"channel": "<string>",
"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({
areaId: 123,
startTime: '2023-11-07T05:31:56Z',
endTime: '2023-11-07T05:31:56Z',
payment: {amount: 123, reference: '<string>', fee: 123},
contactId: 123,
instructorId: 123,
channel: '<string>',
notes: '<string>',
notifyCustomer: true
})
};
fetch('https://api.1club.ai/v1/platform/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/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([
'areaId' => 123,
'startTime' => '2023-11-07T05:31:56Z',
'endTime' => '2023-11-07T05:31:56Z',
'payment' => [
'amount' => 123,
'reference' => '<string>',
'fee' => 123
],
'contactId' => 123,
'instructorId' => 123,
'channel' => '<string>',
'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/bookings"
payload := strings.NewReader("{\n \"areaId\": 123,\n \"startTime\": \"2023-11-07T05:31:56Z\",\n \"endTime\": \"2023-11-07T05:31:56Z\",\n \"payment\": {\n \"amount\": 123,\n \"reference\": \"<string>\",\n \"fee\": 123\n },\n \"contactId\": 123,\n \"instructorId\": 123,\n \"channel\": \"<string>\",\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/bookings")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"areaId\": 123,\n \"startTime\": \"2023-11-07T05:31:56Z\",\n \"endTime\": \"2023-11-07T05:31:56Z\",\n \"payment\": {\n \"amount\": 123,\n \"reference\": \"<string>\",\n \"fee\": 123\n },\n \"contactId\": 123,\n \"instructorId\": 123,\n \"channel\": \"<string>\",\n \"notes\": \"<string>\",\n \"notifyCustomer\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.1club.ai/v1/platform/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 \"areaId\": 123,\n \"startTime\": \"2023-11-07T05:31:56Z\",\n \"endTime\": \"2023-11-07T05:31:56Z\",\n \"payment\": {\n \"amount\": 123,\n \"reference\": \"<string>\",\n \"fee\": 123\n },\n \"contactId\": 123,\n \"instructorId\": 123,\n \"channel\": \"<string>\",\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>",
"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": {}
}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 instead of creating a second booking
255Body
Area id (from GET /v1/platform/areas)
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
Instructor leading the session (from GET /v1/platform/instructors). Must be bookable for one-on-one sessions.
Optional channel label, stored for attribution
Tell the customer their booking is confirmed - email plus the in-app, WhatsApp and SMS notification, and the payment receipt for a paid booking. Off by default for an API key, since the calling system normally sends its own confirmation; on by default over an OAuth connection, where a staff member is booking through an assistant and their member expects to hear from the club. The club's own staff alerts are sent either way.
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?