Okkre
ScheduleThe operational starting point for your clubBookingsFrom an available slot to a direct bookingClub siteA public experience that stays up to date
Okkre ConnectThe useful connections for your clubLearn more →
Founding clubsPricing
DocumentationGet started with OkkreBlogNews and insights from OkkreUpdatesFollow product updates
AboutThe vision behind OkkreLearn more →
FAQ
FeaturesScheduleThe operational starting point for your clubBookingsFrom an available slot to a direct bookingClub siteA public experience that stays up to dateOkkre ConnectThe useful connections for your club
Founding clubsPricing
ResourcesDocumentationGet started with OkkreBlogNews and insights from OkkreUpdatesFollow product updatesAboutThe vision behind Okkre
FAQLog in
  • Découvrir Okkre / Discover Okkre
  • Planning / Schedule
  • Réservations / Bookings
  • Site du club / Club website
  • API publique / Public API
  • Intégration IA / AI integration
Documentation Back
Okkre

Features

  • Schedule
  • Bookings
  • Club website
  • Okkre Connect

Product

  • Pricing
  • About
  • Founding clubs
  • Contact us

Resources

  • Documentation
  • Contact
  • Blog
  • Updates

Legal

  • Privacy
  • Terms of use
  • Cookie policy
© Okkre 2026Made to keep your eyes on the court

Intégration IA / AI integration

Guide API pour assistants IA (anglais) / API integration guide for AI assistants (English).

Guide original en anglais à transmettre à votre assistant IA. Original guide in English to share with your AI assistant.

Télécharger le Markdown / Download Markdown

Use this file when an LLM must generate code that integrates a club website with the Okkre public API.

Core Contract

Base URL:

/api/v1/clubs/{clubId}

Authentication:

Authorization: Bearer <api_key>

Every request needs both values: {clubId} in the URL identifies the club and the API key authorizes the request. The key must belong to that club.

Scopes:

  • read: read courts, availability, API-created reservations.
  • book: all read permissions plus create/cancel reservations.

Never expose a book key in browser code. Prefer server-side calls.

Endpoints

MethodPathScopePurpose
GET/courtsreadList active courts.
GET/availability?from=YYYY-MM-DD&to=YYYY-MM-DD&sport=padel&court_id=...readList available slots using the club's configured duration and price.
POST/reservationsbookCreate an idempotent reservation.
GET/reservations/{externalId}readRead one API-created reservation.
DELETE/reservations/{externalId}bookCancel one API-created reservation.
POST/reservations/{externalId}/cancelbookCancel one API-created reservation.

Data Shapes

Court response:

{
  "courts": [
    {
      "id": "uuid",
      "name": "Terrain 1",
      "sport": "padel",
      "environment": "indoor",
      "display_order": 1
    }
  ]
}

Availability response:

{
  "availability": [
    {
      "court": "Terrain 1",
      "date": "2026-09-12",
      "start_time": "18:00",
      "end_time": "20:00",
      "price_cents": 2400
    }
  ]
}

Create reservation request:

{
  "external_id": "site-order-123",
  "court": "Terrain 1",
  "date": "2026-09-12",
  "start_time": "18:00",
  "end_time": "19:30",
  "person": {
    "first_name": "Ada",
    "last_name": "Lovelace",
    "email": "ada@example.com"
  },
  "notes": "Optional"
}

Create/read/cancel reservation response:

{
  "reservation": {
    "id": "uuid",
    "external_id": "site-order-123",
    "court_id": "uuid",
    "starts_at": "2026-09-12T16:00:00.000Z",
    "ends_at": "2026-09-12T17:30:00.000Z",
    "price_cents": 2400,
    "status": "confirmed",
    "cancellation_reason": null
  },
  "idempotent_replay": false
}

GET /reservations/{externalId} returns the same reservation object without idempotent_replay.

Error shape:

{
  "error": {
    "code": "slot_unavailable",
    "message": "Ce terrain est deja occupe sur ce creneau."
  }
}

Validation Rules

  • from, to, date: YYYY-MM-DD.
  • Availability range: 31 days maximum.
  • Times: HH:MM, 24-hour format.
  • Reservation start must be on the hour or half-hour.
  • Reservation duration must be positive and a multiple of 30 minutes.
  • court: readable court name is preferred; UUID also works.
  • person.email or person.phone is required.
  • person.email: basic email format.
  • person.phone: 6 to 30 characters.
  • person.first_name and person.last_name: required, max 80 characters each.
  • notes: optional, truncated to 500 characters.
  • Cancellation reason: optional, truncated to 300 characters.

Integration Algorithm

  1. On page load, call GET /courts or directly call GET /availability.
  2. Show availability slots to the user. Slots are returned in local club date and time fields, with price_cents for the complete configured slot. Send the returned start and end times unchanged when booking.
  3. When the user confirms, call POST /reservations from the backend with a stable external_id.
  4. If response is 201 or 200 with idempotent_replay: true, treat the reservation as created.
  5. If response is 409 and error.code is slot_unavailable, refresh availability and ask the user to choose another slot.
  6. To cancel, call either DELETE /reservations/{externalId} or POST /reservations/{externalId}/cancel.

TypeScript Helper

type OkkreReservationInput = {
  external_id: string;
  court: string;
  date: string;
  start_time: string;
  end_time: string;
  person: {
    first_name: string;
    last_name: string;
    email?: string;
    phone?: string;
  };
  notes?: string;
};

async function okkreFetch<T>(
  baseUrl: string,
  apiKey: string,
  path: string,
  init: RequestInit = {},
): Promise<T> {
  const response = await fetch(`${baseUrl}${path}`, {
    ...init,
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
      ...init.headers,
    },
  });

  const data = await response.json().catch(() => null);
  if (!response.ok) {
    const code = data?.error?.code ?? "unknown_error";
    const message = data?.error?.message ?? `Okkre API error ${response.status}`;
    throw new Error(`${code}: ${message}`);
  }
  return data as T;
}

export async function createOkkreReservation(
  baseUrl: string,
  apiKey: string,
  input: OkkreReservationInput,
) {
  return okkreFetch(baseUrl, apiKey, "/reservations", {
    method: "POST",
    body: JSON.stringify(input),
  });
}

Common Error Handling

  • missing_api_key, invalid_authorization_header, api_key_not_found, api_key_revoked: ask the admin to check the API key.
  • api_key_wrong_club: check the {clubId} in the URL.
  • insufficient_scope: use a book key for create/cancel.
  • validation_error: fix request fields.
  • invalid_period: fix availability date range.
  • reservation_not_found: unknown or non-API reservation.
  • slot_unavailable: refresh availability and retry with another slot.