Skip to main content
ClubBase

Public API · version 1.0.0

Leads from your website go straight into the CRM

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

Where to get a key

  1. Sign in to the CRM as the owner or an adminOther roles do not see keys, on purpose: a key opens access to the whole studio’s leads.
  2. Open Settings → API and integrations («Налаштування → API та інтеграції»)It is in the CRM’s left menu, in the section with the gear icon.
  3. Click Create key («Створити ключ») and set a name, an expiry date and permissionsPermissions are separate: leads.read reads leads, leads.create creates them. Take only what your integration really needs.
  4. Copy the secret right awayClubBase shows it exactly once. If you lose it, create a new key and revoke the old one.
  5. Put the secret in your server’s environment variablesNot in page code and not in a request from the visitor’s browser: the key gives access to all of the studio’s leads.

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 CRM

First request

The key goes in the Authorization: Bearer … header. Creating a lead also needs an Idempotency-Key: any UUID that you store together with the lead.

Create a lead · curl
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"
  }'
Create a lead · Node.js
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();
Create a lead · PHP
<?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.

Methods

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

GET/v1/integrations/leads/{id}

Read a lead

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

List leads

Reads leads page by page. Pass the nextCursor value to the next request unchanged.

Required permission: leads.read

List leads · curl
curl "https://api.clubbase.fit/v1/integrations/leads?limit=20" \
  -H "Authorization: Bearer $CLUBBASE_API_KEY"
One lead · curl
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.

Retrying a request

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.

Errors

An error response is application/problem+json with the fields status, code, detail.

CodeIdentifierWhen it happens
400integration_invalid_requestUnknown field, invalid contact or cursor, or a missing UUID Idempotency-Key.
401integration_key_invalidThe key is missing, revoked, replaced or past its expiry date.
402subscription_suspendedAccess to the studio is suspended.
403integration_scope_forbiddenThe key does not allow this operation.
403integration_issuer_forbiddenThe current permissions of the person who issued the key no longer allow the integration.
404integration_lead_not_foundThe lead is not available in this key’s studio.
409integration_idempotency_conflictThe same Idempotency-Key was used with different data.
409integration_lead_already_openThe contact already has an open lead.
400integration_source_invalidThe lead source does not belong to this studio or is turned off.
429integration_rate_limitedWait the number of seconds given in Retry-After.
503integration_rate_unavailableThe 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.

Need another method?

Describe what should be sent to ClubBase and in which direction, and we will look at your case.

Write to the team