Développeurs

Référence Edge Functions

Batlr expose plusieurs edge functions Supabase hébergées à https://kgcligweyslnqatoirah.supabase.co/functions/v1/. Cette page documente celles utiles aux intégrateurs.


Auth

La plupart des endpoints publics utilisent l'anon key (visible dans le code du widget). Les endpoints sensibles (charge, refund, invite) nécessitent un JWT staff dans le header Authorization: Bearer <token>.


booking-widget

Sert le widget en XHTML (utilisé par Supabase Storage qui rewrite text/html).

GET /functions/v1/booking-widget?restaurant_id={UUID}

Response : XHTML complet du widget (alternative à https://www.batlr.app/widget.html?restaurant_id=...).

Préférer le hosting Vercel (batlr.app) pour les intégrations standard. Cet endpoint sert de fallback CSP-safe.


send-booking-confirmation

Envoie email + SMS de confirmation, lien de paiement, statut, annulation, demande d'avis.

POST /functions/v1/send-booking-confirmation
Content-Type: application/json

{
  "restaurant_id": "UUID",
  "guest_name": "Marie Dupont",
  "guest_email": "marie@exemple.fr",
  "guest_phone": "+33612345678",
  "date": "2026-04-20",
  "time": "19:30",
  "party_size": 4,
  "source": "app",
  "status": "confirmed",
  "send_email": true,
  "send_sms": true,
  "payment_link": "https://...",
  "payment_mode": "card_hold",
  "reservation_id": "UUID",
  "customer_id": "UUID",
  "cancellation_reason": null,
  "review_link": null,
  "confirm_url": null
}

Auth : anon key.
Effets : envoi via Resend (email) et Twilio (SMS) selon les toggles, log dans communication_events.
Quota SMS : vérifié via RPC get_sms_quota (fallback email si épuisé).


send-reminders

Envoi de rappels (mode auto via cron OU mode forcé par staff).

Mode auto (cron interne)

POST /functions/v1/send-reminders

Pas de body. Scanne tous les restaurants avec reminder_enabled = true, identifie les réservations dues, envoie selon les timings configurés.

Mode forcé (manuel par staff)

POST /functions/v1/send-reminders
Authorization: Bearer <staff JWT>
Content-Type: application/json

{
  "force": true,
  "reservation_id": "UUID",
  "restaurant_id": "UUID",
  "send_email": true,
  "send_sms": true
}

send-review-requests

Envoi de demandes d'avis post-visite (cron toutes les 30 min).

POST /functions/v1/send-review-requests

Auth : service role (interne). Sélectionne les réservations Terminées éligibles selon les critères :

  • Réservation > délai configuré
  • Client a ≥ N visites
  • Pas de demande envoyée dans les X jours (cooldown)
  • Email valide

send-waitlist-notification

Notifications liste d'attente.

POST /functions/v1/send-waitlist-notification
Content-Type: application/json

{
  "entry_id": "UUID",
  "restaurant_id": "UUID",
  "notification_type": "joined" | "spot_available" | "your_turn",
  "send_email": true,
  "send_sms": true
}

Auth : anon key.


stripe-checkout

Orchestration paiement Stripe (SetupIntent et PaymentIntent).

POST /functions/v1/stripe-checkout
Content-Type: application/json

{
  "action": "get_config" | "create_setup_intent" | "confirm_setup" | "create_payment_intent" | "confirm_payment" | "complete_session",
  "reservation_id": "UUID",
  "restaurant_id": "UUID",
  "amount_cents": 5000,
  "metadata": { ... }
}

Auth : anon (widget) ou staff JWT (links).

Actions

ActionEffet
get_configRetourne publishable_key + connected_account_id Stripe
create_setup_intentCrée un SetupIntent (mode card hold)
confirm_setupConfirme le SetupIntent + sauve stripe_payment_method_id sur la résa
create_payment_intentCrée un PaymentIntent (mode prépaiement)
confirm_paymentConfirme le PaymentIntent + marque payée
complete_sessionEndpoint legacy de finalisation

stripe-charge

Débit d'une carte sauvegardée (no-show ou annulation tardive).

POST /functions/v1/stripe-charge
Authorization: Bearer <staff JWT>
Content-Type: application/json

{
  "reservation_id": "UUID",
  "restaurant_id": "UUID",
  "reason": "no_show" | "late_cancellation"
}

Auth : staff requis. Charge le stripe_payment_method_id de la réservation.


stripe-refund

Remboursement total ou partiel.

POST /functions/v1/stripe-refund
Authorization: Bearer <staff JWT>
Content-Type: application/json

{
  "reservation_id": "UUID",
  "restaurant_id": "UUID",
  "amount_cents": 2500
}

amount_cents optionnel — omis = remboursement total.


stripe-connect

Onboarding Stripe Express (création / refresh du lien d'onboarding).

POST /functions/v1/stripe-connect
Authorization: Bearer <staff JWT>
Content-Type: application/json

{
  "action": "create_account_link" | "create_login_link" | "disconnect",
  "restaurant_id": "UUID"
}

stripe-webhook

Webhook entrant Stripe (signé HMAC-SHA256). Reçoit charge.succeeded, setup_intent.succeeded, charge.refunded, charge.failed.

POST /functions/v1/stripe-webhook
Stripe-Signature: <hmac>

N'appelez pas cet endpoint manuellement — il est appelé par Stripe.


reconfirm-reservation

Action depuis la page de reconfirmation client (/rc?token=...).

POST /functions/v1/reconfirm-reservation
Content-Type: application/json

{
  "token": "string",
  "action": "confirm" | "decline"
}

Auth : token-based. Met à jour reservations.reconfirmation_status.


verify-email

Vérification d'email staff.

POST /functions/v1/verify-email
Content-Type: application/json

{
  "action": "verify",
  "token": "string"
}

Réponses :

  • 200 + { success: true } — vérifié
  • 410 — lien expiré

invite-manager, delete-team-member

Gestion d'équipe (admin/manager only).

POST /functions/v1/invite-manager
Authorization: Bearer <staff JWT>
Content-Type: application/json

{
  "restaurant_id": "UUID",
  "email": "...",
  "role": "Manager"
}
POST /functions/v1/delete-team-member
Authorization: Bearer <staff JWT>
Content-Type: application/json

{
  "restaurant_id": "UUID",
  "team_member_id": "UUID"
}

apple-webhook

Webhook Apple Server-to-Server Notifications V2 (StoreKit). Vérification JWS via jose@5.

POST /functions/v1/apple-webhook

Appelé uniquement par Apple. Met à jour les statuts d'abonnement Pro.


Codes d'erreur communs

HTTPSens
400Bad request — payload manquant ou invalide
401Unauthorized — JWT manquant ou invalide
403Forbidden — JWT valide mais rôle insuffisant
404Not found — restaurant/réservation introuvable
410Gone — token expiré
429Too many requests — rate limit
500Server error — contactez le support avec l'ID de requête

Rate limits

  • Endpoints publics (anon) — 60 req/min par IP
  • Endpoints staff (JWT) — 300 req/min par utilisateur
  • Webhooks Stripe / Apple — pas de limite, validés par signature

À lire ensuite