API RiLoBook — v1
API REST complète pour bâtir des intégrations à RiLoBook : POS, CRM, agenda, BI, kiosk, app mobile. Réservations bidirectionnelles, gestion clients, plan de salle, pointage, paiements, et webhooks sortants signés pour la synchronisation temps réel.
- Authentification
- Erreurs & codes
- Rate limiting
- Idempotence
- Pagination cursor
- Webhooks sortants
/me- Restaurant & services
- Disponibilités
- Réservations CRUD
- Clients (guests) CRUD
- Liste d'attente CRUD
- Employés
- Plan de salle & tables
- Pointage & planning
- Paiements
- Audit logs
- Endpoints Webhooks
- Exemples (Node, Python, cURL)
Authentification
Tous les endpoints /api/v1/* exigent un jeton Bearer. Créez-en un depuis Paramètres → API (rôle owner requis). Le jeton plaintext est affiché une seule fois.
Format : rlb_…. En-tête :
Authorization: Bearer rlb_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Ou X-Api-Key: rlb_… si votre client ne supporte pas Bearer.
Scopes disponibles
| Scope | Autorise |
|---|---|
bookings.read | Lecture réservations, disponibilités |
bookings.write | Création / modification / annulation réservations |
waitlist.read / waitlist.write | Liste d'attente |
guests.read / guests.write | Fichier clients |
settings.read / settings.write | Paramètres restaurant + services |
employees.read / employees.write | Équipe + planning + pointage |
payments.read | Historique paiements Stripe |
webhooks.read / webhooks.write | Abonnements webhooks sortants |
audit.read | Journal d'audit |
Base URL
https://votre-instance.rilobook.app/api/v1
Erreurs
Réponses JSON, codes HTTP standard. Corps :
{ "code": "unauthenticated", "message": "invalid_token", "meta": {} }
| HTTP | code | Quand |
|---|---|---|
| 400 | bad_request | Champ manquant ou invalide |
| 401 | unauthenticated | Jeton absent, invalide, révoqué |
| 403 | forbidden / insufficient_scope | Permission manquante |
| 404 | not_found | Ressource inexistante |
| 409 | conflict / capacity_exhausted / immutable_field / idempotency_mismatch | Conflit d'état |
| 429 | rate_limited | Limite dépassée |
| 500 | internal_error | Bug serveur — à signaler |
Rate limiting
120 requêtes par minute par jeton (bucket). Dépassement → 429. Backoff exponentiel recommandé.
Idempotence
Sur POST / PATCH de mutations, envoyez un en-tête Idempotency-Key (UUID ou hash métier, max 120 chars). Le serveur cache la réponse 24 h ; rejouer la même requête renvoie la même réponse avec l'en-tête Idempotent-Replay: true.
Si la même clé est utilisée avec un body différent → 409 idempotency_mismatch.
POST /api/v1/reservations
Authorization: Bearer $RLB_TOKEN
Idempotency-Key: 7e1c1a31-…
Content-Type: application/json
{ "servicePeriodId": "…", "serviceDate": "2026-06-12", ... }
Pagination cursor
Les listes utilisent un curseur opaque. Réponse :
{ "reservations": [...], "nextCursor": "MjAyNi0w…", "hasMore": true }
Page suivante : ?cursor=MjAyNi0w…. Paramètre limit (1–200, défaut 50).
Webhooks sortants
Abonnez une URL HTTPS à un sous-ensemble d'événements. Chaque déclenchement POST le JSON suivant à votre endpoint :
{
"id": "<event UUID>",
"type": "reservation.confirmed",
"createdAt": "2026-05-28T18:01:23Z",
"restaurantId": "<your restaurant id>",
"data": { ...resource object... }
}
En-têtes envoyés
X-RiLoBook-Event: reservation.confirmed
X-RiLoBook-Delivery: <delivery UUID>
X-RiLoBook-Signature: t=1748448083,v1=<hex HMAC-SHA256>
User-Agent: RiLoBook-Webhooks/1.0
Content-Type: application/json
Vérifier la signature (Node.js)
import crypto from 'node:crypto';
function verify(rawBody, headerSig, secret, toleranceSec = 300) {
const m = /t=(\d+),v1=([0-9a-f]+)/.exec(headerSig || '');
if (!m) return false;
const [, t, sig] = m;
if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSec) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${t}.${rawBody}`)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}
Événements supportés
| Type | Payload data |
|---|---|
reservation.created | Reservation |
reservation.confirmed | Reservation |
reservation.updated | Reservation |
reservation.cancelled | Reservation |
reservation.no_show | Reservation |
waitlist.added / waitlist.removed | WaitlistEntry |
guest.created / guest.updated | Guest |
ping | { message: 'test delivery' } |
Retry & livraisons
Si votre endpoint ne renvoie pas un 2xx en moins de 8 s, la livraison est ré-essayée selon un backoff exponentiel (1 s, 5 s, 25 s, 125 s, 625 s, 3125 s, 6 h, 6 h) — maximum 8 tentatives. Après échec final → status dead. Inspectez les livraisons via GET /api/v1/webhooks/{id}/deliveries.
GET /me
Healthcheck — renvoie le contexte du jeton.
{
"userId": "…", "restaurantId": "…",
"fullName": "Loris Dupont", "email": "loris@example.com",
"role": "owner",
"permissions": ["bookings.read", "bookings.write", "…"]
}
Restaurant & services
Champs PATCH : name, timezone, locale, capacityTotal.
Corps POST :
{ "name": "Dîner", "dayOfWeek": 5, "startTime": "19:00",
"endTime": "23:00", "defaultDiningDurationMinutes": 90,
"maxCoversPerSlot": 16, "depositRequired": false, "isActive": true }
Disponibilités
{ "date": "2026-06-12", "partySize": 4,
"slots": [ { "servicePeriodId": "…", "servicePeriodName": "Dîner",
"slotTime": "19:00:00", "available": true }, ... ] }
Réservations
Filtres : date, from, to (range), status, source, guestId, updatedSince (sync incrémental). Pagination cursor.
Crée et confirme immédiatement (pas de checkout Stripe — réservé au widget public). Mêmes verrous de capacité que le dashboard.
{
"servicePeriodId": "…",
"serviceDate": "2026-06-12",
"slotTime": "19:30:00",
"partySize": 4,
"channel": "phone",
"skipConfirm": false,
"guest": {
"fullName": "Marie Curie",
"email": "marie@example.com",
"phone": "+33611223344",
"specialRequests": "Anniversaire"
}
}
Combine actions de transition + mises à jour. action ∈ confirm | cancel | no_show. Champs modifiables : specialRequests, channel, guestId (swap), guest (édite le client lié).
partySize, slotTime, serviceDate, servicePeriodId sont immuables — annulez et recréez (réservé pour préserver les verrous de capacité).
Alias de { "action": "cancel" }.
Clients (guests) CRUD
Filtres : q, hasEmail=1, hasPhone=1. Pagination cursor.
{ "fullName": "Marie Curie", "email": "marie@example.com",
"phone": "+33611223344", "notes": "VIP", "tags": ["vip","gluten-free"] }
Liste d'attente CRUD
Employés
Plan de salle & tables
Pointage & planning
Paiements
Filtres : reservationId, status. Pagination cursor.
Audit logs
Filtres : entityType, entityId, action. Pagination cursor.
Endpoints Webhooks
POST /api/v1/webhooks
{
"url": "https://votre-backend/webhooks/rilobook",
"events": ["reservation.created","reservation.confirmed","reservation.cancelled"],
"description": "Sync POS"
}
La réponse contient secret (à conserver pour vérifier la signature) — affiché uniquement à la création.
Exemples complets
Node.js — synchroniser les réservations modifiées
const TOKEN = process.env.RLB_TOKEN;
const BASE = 'https://votre-instance.rilobook.app/api/v1';
async function syncSince(isoDate) {
let cursor = null, page = 0;
do {
const url = new URL(`${BASE}/reservations`);
url.searchParams.set('updatedSince', isoDate);
url.searchParams.set('limit', '100');
if (cursor) url.searchParams.set('cursor', cursor);
const res = await fetch(url, { headers: { Authorization: `Bearer ${TOKEN}` } });
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
for (const r of data.reservations) await upsertToPOS(r);
cursor = data.nextCursor;
if (++page > 200) throw new Error('cursor loop guard');
} while (cursor);
}
Python — créer une réservation avec idempotency
import os, uuid, requests
TOKEN = os.environ["RLB_TOKEN"]
BASE = "https://votre-instance.rilobook.app/api/v1"
H = {
"Authorization": f"Bearer {TOKEN}",
"Idempotency-Key": str(uuid.uuid4()),
}
r = requests.post(f"{BASE}/reservations", headers=H, json={
"servicePeriodId": "…",
"serviceDate": "2026-06-12",
"slotTime": "19:30:00",
"partySize": 4,
"channel": "phone",
"guest": {"fullName": "Marie Curie", "phone": "+33611223344"},
})
r.raise_for_status()
print(r.json()["referenceCode"])
cURL — souscrire à un webhook
curl -X POST https://votre-instance/api/v1/webhooks \
-H "Authorization: Bearer $RLB_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://votre-backend/webhooks/rilobook",
"events": ["reservation.created","reservation.confirmed","reservation.cancelled"]
}'