Recettes & workflows
Patterns d'intégration éprouvés. Copiez-collez, adaptez, déployez.
Workflows métier
Workflow : Dashboard pending
Affichez les résas en attente, avec actions accepter / refuser inline.
php
<?php
$API_KEY = getenv('RESTAURATEUR_API_KEY');
$BASE = 'https://api.restaurateur.ch/api/v1';
function api($method, $path, $body = null) {
global $API_KEY, $BASE;
$ch = curl_init("$BASE$path");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => [
"X-API-Key: $API_KEY",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => $body ? json_encode($body) : null,
]);
$res = curl_exec($ch);
curl_close($ch);
return json_decode($res, true);
}
// Lister les pending
$pending = api('GET', '/bookings?status=pending&limit=50');
foreach ($pending['bookings'] as $b) {
echo "{$b['guest_name']} — {$b['party_size']} pers — {$b['booking_date']} {$b['booking_time']}\n";
if ($_POST['action'] === 'accept' && $_POST['token'] === $b['token']) {
api('POST', "/bookings/{$b['token']}/accept", ['message' => 'Au plaisir de vous accueillir !']);
}
if ($_POST['action'] === 'reject' && $_POST['token'] === $b['token']) {
api('POST', "/bookings/{$b['token']}/reject", ['reason' => 'Complet sur ce créneau']);
}
}javascript
const API_KEY = process.env.RESTAURATEUR_API_KEY;
const BASE = 'https://api.restaurateur.ch/api/v1';
const api = (method, path, body) => fetch(`${BASE}${path}`, {
method,
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
}).then(r => r.json());
const { bookings } = await api('GET', '/bookings?status=pending&limit=50');
for (const b of bookings) {
console.log(`${b.guest_name} — ${b.party_size} pers — ${b.booking_date} ${b.booking_time}`);
}
// Accepter une résa
await api('POST', `/bookings/${token}/accept`, { message: 'Au plaisir !' });
// Refuser
await api('POST', `/bookings/${token}/reject`, { reason: 'Complet' });python
import os, requests
API_KEY = os.environ['RESTAURATEUR_API_KEY']
BASE = 'https://api.restaurateur.ch/api/v1'
H = {'X-API-Key': API_KEY, 'Content-Type': 'application/json'}
def api(method, path, body=None):
return requests.request(method, BASE + path, headers=H, json=body).json()
pending = api('GET', '/bookings?status=pending&limit=50')
for b in pending['bookings']:
print(f"{b['guest_name']} — {b['party_size']} pers — {b['booking_date']} {b['booking_time']}")
# Accepter
api('POST', f"/bookings/{token}/accept", {'message': 'Au plaisir !'})
# Refuser
api('POST', f"/bookings/{token}/reject", {'reason': 'Complet'})Workflow : ajuster la capacité
Un car de 30 touristes vient demain au lunch ? Augmentez le max_total_guests pour absorber.
bash
# 1. Voir le service lunch et son usage actuel
curl "https://api.restaurateur.ch/api/v1/services?date=2026-06-15" \
-H "X-API-Key: VOTRE_CLE_API"
# 2. Augmenter la capacité
curl -X PUT https://api.restaurateur.ch/api/v1/services/12 \
-H "X-API-Key: VOTRE_CLE_API" \
-H "Content-Type: application/json" \
-d '{"max_total_guests": 50}'
# 3. Vérifier que les slots se rouvrent
curl "https://api.restaurateur.ch/api/v1/calendar/slots?date=2026-06-15" \
-H "X-API-Key: VOTRE_CLE_API"Workflow : congés d'une semaine
javascript
// Bloquer du 1er au 15 août 2026
const start = new Date('2026-08-01');
const end = new Date('2026-08-15');
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
const date = d.toISOString().slice(0, 10);
await api('POST', '/calendar/pause-day', { date, reason: 'Congés annuels' });
}Recettes PHP
Configurer le sender personnalisé
php
// Une fois pour configurer
api('PUT', '/mail', [
'api_key' => 'sm_live_xxxxxxxxxxxx',
'sender_email' => 'noreply@mrpickwick.ch',
]);
// Vérifier (envoie un test à restaurant.email)
$result = api('POST', '/mail/verify');
if ($result['ok']) {
echo "✓ Les futurs emails partiront depuis noreply@mrpickwick.ch\n";
} else {
echo "✗ Erreur : " . $result['error'];
}Lister les bookings du jour avec totaux
php
$today = date('Y-m-d');
$counts = api('GET', "/stats/counts?date=$today");
$slots = api('GET', "/calendar/slots?date=$today");
echo "📅 $today : {$counts['totals']['bookings']} résas, {$counts['totals']['guests']} couverts\n";
foreach ($slots['services'] as $s) {
$pct = $s['max_total_guests']
? round(100 * $s['guests_booked'] / $s['max_total_guests'])
: 0;
echo " {$s['label']} : {$s['guests_booked']}/{$s['max_total_guests']} ({$pct}%)\n";
}Recettes Node.js
Webhook sortant à chaque résa (polling)
javascript
// Cron toutes les 60s : détecter les nouveaux bookings et notifier Slack
import fetch from 'node-fetch';
let lastCheck = new Date().toISOString();
setInterval(async () => {
const now = new Date().toISOString();
const today = now.slice(0, 10);
const { bookings } = await api('GET', `/bookings?date=${today}&limit=50`);
const news = bookings.filter(b => b.created_at >= lastCheck);
for (const b of news) {
await fetch(process.env.SLACK_WEBHOOK, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `🆕 ${b.guest_name} — ${b.party_size}p — ${b.booking_date} ${b.booking_time}`,
}),
});
}
lastCheck = now;
}, 60000);Synchroniser vers Google Calendar
javascript
const { bookings } = await api('GET', '/bookings?status=confirmed&from=2026-06-01&to=2026-06-30');
for (const b of bookings) {
await googleCalendar.events.insert({
calendarId: 'primary',
requestBody: {
summary: `${b.guest_name} (${b.party_size}p)`,
description: b.notes || '',
start: { dateTime: `${b.booking_date}T${b.booking_time}:00`, timeZone: 'Europe/Zurich' },
end: { dateTime: addMinutes(`${b.booking_date}T${b.booking_time}:00`, 90), timeZone: 'Europe/Zurich' },
},
});
}Recettes Python
Export Excel des résas du mois
python
import pandas as pd
bookings = api('GET', '/bookings?from=2026-06-01&to=2026-06-30&limit=200')['bookings']
df = pd.DataFrame(bookings)
df = df[['booking_date', 'booking_time', 'guest_name', 'party_size', 'status', 'guest_email']]
df.to_excel(f'resas_juin_2026.xlsx', index=False)
print(f"✓ {len(df)} réservations exportées")Notification SMS no-show répétés
python
from collections import Counter
# Détecter les clients avec ≥ 3 no-show sur 90 jours
ninety_days_ago = (datetime.now() - timedelta(days=90)).strftime('%Y-%m-%d')
no_shows = api('GET', f'/bookings?status=no_show&from={ninety_days_ago}')['bookings']
counter = Counter(b['guest_email'] for b in no_shows)
for email, count in counter.items():
if count >= 3:
print(f"⚠️ {email} : {count} no-shows en 90 jours")