POST/v1/integrations/leads
Create a lead
Sends a name and contact to the current studio. Idempotency-Key protects a retry after a lost response.
Required permission: leads.create
Public API · version 1.0.0
Your website’s server creates a lead in the right studio and reads its status. A key opens only the studio that issued it.
Base URLhttps://api.clubbase.fit
A studio can have up to 20 keys, and a new key is valid for up to 366 days. Replacing a key turns off the previous secret at once; revoking is final. The CRM sign-in cookie does not replace a key.
Open your CRMThe key goes in the Authorization: Bearer … header. Creating a lead also needs an Idempotency-Key: any UUID that you store together with the lead.
curl -X POST https://api.clubbase.fit/v1/integrations/leads \
-H "Authorization: Bearer $CLUBBASE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen | tr 'A-Z' 'a-z')" \
-d '{
"displayName": "API example",
"contact": {
"type": "email",
"value": "[email protected]"
},
"sourceId": null,
"note": "Integration test lead"
}'import { randomUUID } from 'node:crypto';
// The key comes from environment variables, never from page code.
const response = await fetch('https://api.clubbase.fit/v1/integrations/leads', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CLUBBASE_API_KEY}`,
'Content-Type': 'application/json',
// Retrying with the same key returns the same lead, not a second one.
'Idempotency-Key': randomUUID(),
},
body: JSON.stringify({
"displayName": "API example",
"contact": {
"type": "email",
"value": "[email protected]"
},
"sourceId": null,
"note": "Integration test lead"
}),
});
if (!response.ok) {
const problem = await response.json();
throw new Error(`${problem.status} ${problem.code}: ${problem.detail}`);
}
const lead = await response.json();<?php
// The key is read from the server environment, not from page code.
// Idempotency-Key must be a UUID: the API rejects 32 hex characters without hyphens.
$bytes = random_bytes(16);
$bytes[6] = chr(ord($bytes[6]) & 0x0f | 0x40);
$bytes[8] = chr(ord($bytes[8]) & 0x3f | 0x80);
$idempotencyKey = vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($bytes), 4));
$ch = curl_init('https://api.clubbase.fit/v1/integrations/leads');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CLUBBASE_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . $idempotencyKey,
],
CURLOPT_POSTFIELDS => json_encode([
'displayName' => "API example",
'contact' => [
'type' => "email",
'value' => "[email protected]",
],
'note' => "Integration test lead",
], JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);Success returns 201 and the lead body with its ID. Repeating the same Idempotency-Key returns the same lead, not a second one.
POST/v1/integrations/leads
Sends a name and contact to the current studio. Idempotency-Key protects a retry after a lost response.
Required permission: leads.create
GET/v1/integrations/leads/{id}
Returns the permitted fields of one lead. An ID from another studio or an unknown ID returns 404.
Required permission: leads.read
GET/v1/integrations/leads
Reads leads page by page. Pass the nextCursor value to the next request unchanged.
Required permission: leads.read
curl "https://api.clubbase.fit/v1/integrations/leads?limit=20" \
-H "Authorization: Bearer $CLUBBASE_API_KEY"curl https://api.clubbase.fit/v1/integrations/leads/$LEAD_ID \
-H "Authorization: Bearer $CLUBBASE_API_KEY"The list comes in pages. limit is from 1 to 100, 25 by default. The response contains nextCursor: pass it unchanged to the next request as the cursor parameter. nextCursor: null means there are no more pages.
Networks drop responses more often than you’d think. If you did not get a response, repeat the same request with the same Idempotency-Key: ClubBase returns the original result and does not create a second lead.
The same key with a different body is an error, 409 integration_idempotency_conflict. That way you see that state got lost somewhere, instead of a duplicate being created quietly.
If you run the example twice with a new Idempotency-Key and the same contact, the response is 409 integration_lead_already_open. This is not an integration error: the studio already has an open lead from this person, and ClubBase does not create a second one. To test retries, change the key together with the contact, not one without the other.
An error response is application/problem+json with the fields status, code, detail.
| Code | Identifier | When it happens |
|---|---|---|
| 400 | integration_invalid_request | Unknown field, invalid contact or cursor, or a missing UUID Idempotency-Key. |
| 401 | integration_key_invalid | The key is missing, revoked, replaced or past its expiry date. |
| 402 | subscription_suspended | Access to the studio is suspended. |
| 403 | integration_scope_forbidden | The key does not allow this operation. |
| 403 | integration_issuer_forbidden | The current permissions of the person who issued the key no longer allow the integration. |
| 404 | integration_lead_not_found | The lead is not available in this key’s studio. |
| 409 | integration_idempotency_conflict | The same Idempotency-Key was used with different data. |
| 409 | integration_lead_already_open | The contact already has an open lead. |
| 400 | integration_source_invalid | The lead source does not belong to this studio or is turned off. |
| 429 | integration_rate_limited | Wait the number of seconds given in Retry-After. |
| 503 | integration_rate_unavailable | The quota check is temporarily unavailable; nothing was written. |
429 comes with a Retry-After header: the number of seconds until the next attempt. Respect it, or the next response will be the same.
Describe what should be sent to ClubBase and in which direction, and we will look at your case.
Write to the team