Pour les développeurs
L’API Areza
Cherche des clubs, lis leurs créneaux libres, réserve et paie depuis ton application. C’est l’API dont se sert notre propre site : même contrat, mêmes règles, aucun passe-droit.
Démarrer en quatre appels
- Connecte-toi et crée une clé dans l’espace développeur. Commence en bac à sable.
- Passe-la dans l’en-tête de chaque appel. Elle n’est montrée qu’une fois : garde-la côté serveur.
- Cherche, lis les créneaux, réserve, paie :
export AREZA_KEY=areza_test_… # ta clé, créée dans l'espace développeur
API=https://areza.jrec.fr/api/v1
# 1. Les clubs de padel à moins de 10 km
curl -s "$API/establishments?lat=48.8566&lng=2.3522&radius_km=10&sport=padel" \
-H "Authorization: Bearer $AREZA_KEY"
# 2. Les créneaux d'un club, un jour donné
curl -s "$API/establishments/court-central-padel-bercy/availability?date=2026-10-21" \
-H "Authorization: Bearer $AREZA_KEY"
# 3. Réserver un créneau libre (resourceId et startsAt viennent de l'appel 2)
curl -s -X POST "$API/bookings" \
-H "Authorization: Bearer $AREZA_KEY" -H "Content-Type: application/json" \
-d '{"resourceId":"…","startsAt":"2026-10-21T19:00:00+02:00"}'
# 4. Payer, si le club encaisse en ligne (statut PENDING_PAYMENT)
curl -s -X POST "$API/bookings/$BOOKING_ID/payment" \
-H "Authorization: Bearer $AREZA_KEY" -H "Content-Type: application/json" \
-d '{"paymentMethod":"pm_card_visa"}'S’authentifier
Authorization: Bearer areza_test_… ou, si ton outil préfère, X-Api-Key: areza_test_…. Une clé agit au nom du compte qui l’a créée : ce qu’elle réserve est à ce compte. Remplacer une clé en crée une nouvelle ; l’ancienne fonctionne encore 24 h, le temps de déployer. Révoquer l’arrête tout de suite.
Les périmètres
Une clé n’ouvre que ce qu’on lui a donné. Un appel hors de ses périmètres répond 403 insufficient_scope.
| Périmètre | Ce qu’il ouvre |
|---|---|
availability:read | Établissements, créneaux libres, parties ouvertes |
bookings:read | Réservations, reçus, fils avec les clubs |
bookings:write | Réserver, payer, annuler, ouvrir ou rejoindre une partie |
club:manage | L'espace club des clubs dont je suis membre |
recordings:write | Pour la caméra d'un court équipé : les replays des matchs de mes clubs |
La gestion des clés et des webhooks reste réservée à l’utilisateur connecté : une clé ne crée pas de clé.
Le bac à sable
Une clé de test (areza_test_…) lit tout, mais ne réserve que dans les trois clubs de démonstration (Court Central Padel à Bercy, Tennis Club de la Cité à Boulogne, Five Arena à Saint-Ouen). Les paiements y passent par des cartes de test : pm_card_visa et pm_card_mastercard sont acceptées, pm_card_chargeDeclined est refusée. Elle n’est jamais facturée.
Débit et quotas
120 appels par minute et par clé ; 1 000 appels par jour pour une clé de test, 10 000 pour une clé de production. Chaque réponse le dit : X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-Quota-Limit et X-Quota-Remaining. Au-delà, 429 avec Retry-After, en secondes. Un appel refusé n’est pas compté.
Ce que ça coûte
La lecture est gratuite dans le quota. Une réservation confirmée par une clé de production coûte 0,10 € ; le relevé du mois, jour par jour et clé par clé, est dans l’espace développeur. Le bac à sable ne coûte rien.
Les webhooks
Areza prévient ton serveur de ce qui arrive aux réservations prises par tes clés, que le changement vienne de ton application, du joueur ou du club :
booking.created— Réservation crééebooking.confirmed— Réservation confirmée (payée ou accordée)booking.cancelled— Réservation annulée ou libérée
Chaque envoi est un POST JSON signé. Réponds 2xx pour l’accuser ; sinon il est rejoué après 1 min, 5 min, 30 min, 2 h et 12 h, puis abandonné. L’adresse doit être en HTTPS et publique.
POST /ton/adresse
Areza-Event: booking.confirmed
Areza-Delivery: 5d1c…
Areza-Signature: t=1760428800,v1=f0e5684b…
{
"id": "8f2a…",
"type": "booking.confirmed",
"createdAt": "2026-10-14T08:00:05Z",
"data": {
"booking": { "id": "…", "status": "CONFIRMED", "startsAt": "2026-10-21T19:00:00+02:00", … },
"apiKey": { "id": "…", "prefix": "areza_live_3f9a1c", "mode": "live" }
}
}Vérifier la signature, en Node :
import crypto from "node:crypto";
// secret : le secret du webhook, affiché dans l'espace développeur (whsec_…)
export function verify(secret, signatureHeader, rawBody) {
const parts = Object.fromEntries(signatureHeader.split(",").map((part) => part.split("=")));
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
const given = Buffer.from(parts.v1 ?? "");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300; // refuser un envoi rejoué
return fresh && given.length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), given);
}Connecter un agent (MCP)
Areza parle aussi MCP : un assistant comme Claude cherche un créneau et réserve pour le joueur, avec les mêmes règles que le site. L’adresse du serveur : https://areza.jrec.fr/api/mcp.
- Avec le compte du joueur : dans Claude, ajouter un connecteur personnalisé avec cette adresse. Claude envoie le joueur sur Areza, qui se connecte et donne son accord ; l’agent agit ensuite en son nom, sans clé, et rien n’est facturé.
- Avec une clé d’API, pour un agent à toi : la passer dans l’en-tête, comme pour l’API. Mêmes périmètres, mêmes quotas, même facturation.
# Claude Code, avec le compte du joueur (OAuth)
claude mcp add --transport http areza https://areza.jrec.fr/api/mcp
# Claude Code, avec une clé d'API
claude mcp add --transport http areza https://areza.jrec.fr/api/mcp --header "Authorization: Bearer areza_live_…"| Outil | Ce qu’il fait |
|---|---|
search_clubs | Chercher un club autour d'un point, par sport ou par nom |
get_club | La fiche d'un club : adresse, terrains, prix, annulation, paiement |
get_availability | Les créneaux libres d'un club un jour donné, terrain par terrain |
book_slot | Réserver un créneau, après l'accord du joueur |
list_my_bookings | Les réservations du joueur |
cancel_booking | Annuler une réservation, après l'accord du joueur |
list_sports | Les sports qu'on peut réserver |
L’agent ne réserve et n’annule qu’après l’accord du joueur. Si le club encaisse en ligne, il lui donne un lien pour payer lui-même : il ne voit jamais sa carte.
Exemples
JavaScript (Node 18 et plus)
const api = "https://areza.jrec.fr/api/v1";
const headers = { Authorization: `Bearer ${process.env.AREZA_KEY}`, "Content-Type": "application/json" };
const day = await fetch(`${api}/establishments/court-central-padel-bercy/availability?date=2026-10-21`, { headers })
.then((response) => response.json());
const court = day.resources[0];
const slot = court.slots.find((candidate) => candidate.status === "AVAILABLE");
const response = await fetch(`${api}/bookings`, {
method: "POST",
headers,
body: JSON.stringify({ resourceId: court.resourceId, startsAt: slot.startsAt }),
});
if (!response.ok) {
const error = await response.json(); // { code: "slot_taken", message: "…" }
throw new Error(error.code);
}
const booking = await response.json(); // status : CONFIRMED, ou PENDING_PAYMENT à payerPython
import os, requests
api = "https://areza.jrec.fr/api/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['AREZA_KEY']}"
day = session.get(f"{api}/establishments/court-central-padel-bercy/availability",
params={"date": "2026-10-21"}).json()
court = day["resources"][0]
slot = next(s for s in court["slots"] if s["status"] == "AVAILABLE")
booking = session.post(f"{api}/bookings",
json={"resourceId": court["resourceId"], "startsAt": slot["startsAt"]})
booking.raise_for_status()
print(booking.json()["status"], booking.headers["X-Quota-Remaining"])Les erreurs
Toujours la même forme : {"code": "slot_taken", "message": "…"}. Le code est stable, fais-lui confiance ; le message est pour les humains.
| HTTP | Code | Quand |
|---|---|---|
| 401 | invalid_api_key | Clé inconnue, révoquée ou mal formée |
| 403 | insufficient_scope | La clé n'a pas le périmètre de cet appel |
| 403 | api_key_not_allowed | Appel réservé à l'utilisateur connecté (gérer ses clés, par exemple) |
| 403 | sandbox_only | Une clé de test ne réserve que dans les clubs de démonstration |
| 409 | slot_taken | Quelqu'un vient de prendre le créneau |
| 402 | card_declined | Carte refusée : la réservation attend toujours, on peut réessayer |
| 429 | rate_limited | Trop d'appels dans la minute : attendre Retry-After secondes |
| 429 | quota_exceeded | Quota du jour atteint : il se renouvelle à minuit, heure de Paris |
La référence complète, endpoint par endpoint : Swagger UI et le document OpenAPI.