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

API publique / Public API

Référence API complète (français) / Complete API reference (French).

Référence originale en français. Original reference in French.

Télécharger le Markdown / Download Markdown

Cette API permet a un site de club ou a un service tiers de lire les terrains, afficher les disponibilites et creer ou annuler des reservations dans Okkre.

Base URL :

/api/v1/clubs/{clubId}

Toutes les requetes doivent envoyer une cle API dans le header Authorization.

Authorization: Bearer <cle_api>

Les deux informations sont necessaires : {clubId} dans l'URL identifie le club cible et la cle API autorise l'appel. Le serveur verifie que la cle appartient bien a ce club ; une cle seule ne suffit donc pas pour construire l'URL.

Prerequis

  • Le club doit etre configure dans Okkre.
  • Une cle API doit etre creee dans les reglages API du club.
  • Le serveur doit avoir SUPABASE_SERVICE_ROLE_KEY.
  • La base doit avoir les migrations appliquees, notamment 20260829120000_public_api_service_role_grants.sql.
  • Pour les appels navigateur depuis un autre domaine, configurer PUBLIC_API_ALLOWED_ORIGINS cote serveur, par exemple :
PUBLIC_API_ALLOWED_ORIGINS=https://club.example,https://staging.club.example

Les appels serveur a serveur ne sont pas concernes par CORS.

Droits des cles

Deux niveaux de cle existent :

DroitCapacites
readLire les terrains, disponibilites et reservations creees par l'API.
bookTout read, plus creer et annuler des reservations.

Une cle revoquee renvoie 401 api_key_revoked. Une cle read utilisee sur un endpoint de reservation renvoie 403 insufficient_scope.

La gestion des cles est reservee au proprietaire du club. Les contacts staff du club n'ont pas acces aux reglages ni aux cles API.

Endpoints

MethodeEndpointDroitDescription
GET/courtsreadListe les terrains actifs du club.
GET/availability?from=YYYY-MM-DD&to=YYYY-MM-DD&sport=padel&court_id=...readListe les creneaux disponibles avec leur duree et leur prix configures.
POST/reservationsbookCree une reservation idempotente.
GET/reservations/{externalId}readLit une reservation creee par l'API.
DELETE/reservations/{externalId}bookAnnule une reservation creee par l'API.
POST/reservations/{externalId}/cancelbookVariante explicite pour annuler une reservation.

Format des erreurs

Toutes les erreurs utilisent ce format :

{
  "error": {
    "code": "validation_error",
    "message": "date doit etre une date valide au format YYYY-MM-DD."
  }
}

En developpement local, certaines erreurs Supabase ajoutent error.details avec l'operation et le code base de donnees. Ces details ne sont pas renvoyes en production.

Codes courants :

HTTPCodeCas
400validation_errorCorps JSON invalide, champ manquant, date ou horaire invalide.
400invalid_periodParametres from / to invalides ou periode superieure a 31 jours.
401missing_api_keyHeader Authorization absent.
401invalid_authorization_headerHeader different de Bearer <cle_api>.
401api_key_not_foundCle inconnue dans la base utilisee par le serveur.
401api_key_revokedCle revoquee.
403api_key_wrong_clubCle valide mais appartenant a un autre club.
403insufficient_scopeCle read utilisee sur une action book.
404club_not_foundClub introuvable pour les disponibilites.
404reservation_not_foundReservation API introuvable.
409slot_unavailableTerrain deja occupe sur ce creneau.
500database_errorOperation Supabase impossible.
500internal_errorErreur serveur inattendue.
503api_key_lookup_failedVerification de cle impossible.

GET /courts

Retourne les terrains actifs, tries par display_order.

curl "$BASE_URL/courts" \
  -H "Authorization: Bearer $OKKRE_API_KEY"

Reponse :

{
  "courts": [
    {
      "id": "8b5d5b7d-8b91-4b22-a6d8-3a6d5f5c2a10",
      "name": "Terrain 1",
      "sport": "padel",
      "environment": "indoor",
      "display_order": 1
    }
  ]
}

GET /availability

Retourne les creneaux disponibles selon la duree configuree dans la regle d'ouverture (par exemple 120 minutes), avec le prix applicable a chaque creneau. Les disponibilites tiennent compte des regles d'ouverture publiees et des occupations confirmees.

Parametres :

ParametreObligatoireDescription
fromOuiDate de debut au format YYYY-MM-DD.
toNonDate de fin au format YYYY-MM-DD. Si absent, vaut from.
sportNonFiltre par sport, par exemple padel.
court_idNonFiltre par identifiant de terrain.

La periode ne peut pas depasser 31 jours.

curl "$BASE_URL/availability?from=2026-09-12&to=2026-09-13&sport=padel" \
  -H "Authorization: Bearer $OKKRE_API_KEY"

Reponse :

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

Le champ court est le nom lisible du terrain. Il peut etre reutilise tel quel dans POST /reservations. price_cents est le prix du creneau entier, en centimes d'euro : reutiliser exactement les heures renvoyees garantit le tarif affiche.

POST /reservations

Cree une reservation. Cet endpoint exige une cle book.

curl -X POST "$BASE_URL/reservations" \
  -H "Authorization: Bearer $OKKRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "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": "Optionnel"
  }'

Corps JSON :

ChampObligatoireDescription
external_idOuiIdentifiant unique cote site ou integrateur. Sert a l'idempotence.
courtOuiNom lisible du terrain, ou UUID du terrain.
dateOuiDate locale du club, au format YYYY-MM-DD.
start_timeOuiHeure locale du club au format HH:MM. Doit commencer a l'heure ou a la demi-heure.
end_timeOuiHeure locale du club au format HH:MM. La duree doit etre un multiple de 30 minutes.
person.first_nameOuiPrenom, 80 caracteres maximum.
person.last_nameOuiNom, 80 caracteres maximum.
person.emailOui si pas de telephoneEmail du client. Sert a retrouver une fiche existante.
person.phoneOui si pas d'emailTelephone du client, entre 6 et 30 caracteres.
notesNonNotes libres, tronquees a 500 caracteres.

Reponse 201 :

{
  "reservation": {
    "id": "32ec69b4-7fd9-4508-9f9d-022bb2dc0f8c",
    "external_id": "site-order-123",
    "court_id": "8b5d5b7d-8b91-4b22-a6d8-3a6d5f5c2a10",
    "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
}

starts_at et ends_at sont renvoyes en ISO UTC. Les champs date, start_time et end_time envoyes par le client sont interpretes dans le fuseau horaire du club.

Idempotence

external_id doit etre stable pour une tentative de reservation donnee. Si le meme external_id existe deja pour le club, l'API ne cree pas de doublon et renvoie la reservation existante :

{
  "reservation": {
    "id": "32ec69b4-7fd9-4508-9f9d-022bb2dc0f8c",
    "external_id": "site-order-123",
    "court_id": "8b5d5b7d-8b91-4b22-a6d8-3a6d5f5c2a10",
    "starts_at": "2026-09-12T16:00:00.000Z",
    "ends_at": "2026-09-12T17:30:00.000Z",
    "status": "confirmed",
    "cancellation_reason": null
  },
  "idempotent_replay": true
}

La fiche client est recherchee d'abord par email, puis par telephone. Si elle n'existe pas, elle est creee avec le role client. Les demandes simultanees avec le meme nouvel email reutilisent la fiche creee par la premiere demande.

GET /reservations/{externalId}

Lit une reservation creee par l'API pour ce club.

curl "$BASE_URL/reservations/site-order-123" \
  -H "Authorization: Bearer $OKKRE_API_KEY"

Reponse :

{
  "reservation": {
    "id": "32ec69b4-7fd9-4508-9f9d-022bb2dc0f8c",
    "external_id": "site-order-123",
    "court_id": "8b5d5b7d-8b91-4b22-a6d8-3a6d5f5c2a10",
    "starts_at": "2026-09-12T16:00:00.000Z",
    "ends_at": "2026-09-12T17:30:00.000Z",
    "status": "confirmed",
    "cancellation_reason": null
  }
}

DELETE /reservations/{externalId}

Annule une reservation creee par l'API. La reservation reste dans l'historique avec le statut cancelled.

curl -X DELETE "$BASE_URL/reservations/site-order-123" \
  -H "Authorization: Bearer $OKKRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Annulation client" }'

Le corps JSON est optionnel. reason est tronque a 300 caracteres.

Reponse :

{
  "reservation": {
    "id": "32ec69b4-7fd9-4508-9f9d-022bb2dc0f8c",
    "external_id": "site-order-123",
    "court_id": "8b5d5b7d-8b91-4b22-a6d8-3a6d5f5c2a10",
    "starts_at": "2026-09-12T16:00:00.000Z",
    "ends_at": "2026-09-12T17:30:00.000Z",
    "status": "cancelled",
    "cancellation_reason": "Annulation client"
  },
  "idempotent_replay": false
}

Rejouer l'annulation d'une reservation deja annulee est idempotent et renvoie idempotent_replay: true.

POST /reservations/{externalId}/cancel

Fait la meme annulation logique que DELETE /reservations/{externalId}. Ce format est utile pour les clients qui ne veulent pas envoyer de corps avec une requete DELETE.

curl -X POST "$BASE_URL/reservations/site-order-123/cancel" \
  -H "Authorization: Bearer $OKKRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Annulation client" }'

Conseils d'integration

  • Stocker la cle API cote serveur, jamais dans du JavaScript public.
  • Utiliser une cle read pour afficher les disponibilites publiques.
  • Utiliser une cle book uniquement sur un backend controle par le club.
  • Generer un external_id unique et stable, par exemple l'identifiant de commande du site.
  • Verifier la disponibilite juste avant de creer une reservation.
  • Traiter 409 slot_unavailable comme un conflit normal : demander au client de choisir un autre creneau.
  • Ne pas parser message pour la logique applicative ; utiliser error.code.

Tests locaux

Avec la base Supabase locale demarree :

pnpm test:api

Le test lance un serveur Next sur le port 3107, cree ses donnees de test, puis les supprime. Il verifie les cles, les terrains actifs, la creation, la lecture, l'annulation, les conflits et les restrictions d'administration.