API BilletWeb — Référence complète

Plateforme : BilletWeb.fr — billetterie en ligne Compte : Parc de la Luge (user=268537) Dernière mise à jour : 29/05/2026


1. Authentification

L'API BilletWeb utilise une authentification par query parameters (pas de token Bearer).

user=<user_id>
key=<api_key>
version=1

L'API key se trouve dans le compte BilletWeb : Réglages → Outils → API.

⚠️ Pas de JSON-RPC, pas de REST auth standard — clé en query string.


2. Endpoints

2.1 Lister les événements

GET https://www.billetweb.fr/api/user/events
  ?user=<user_id>
  &key=<api_key>
  &version=1

Retourne la liste des événements du compte.

Réponse :

[
  {
    "id": 1350897,
    "name": "Parc de la Luge - Billetterie",
    "date_start": "2026-01-01",
    "date_end": "2026-12-31",
    "status": "active"
  }
]

2.2 Lister les participants

GET https://www.billetweb.fr/api/event/{event_id}/attendees
  ?user=<user_id>
  &key=<api_key>
  &version=1
  &since=<YYYY-MM-DD HH:MM:SS>

Paramètres :

Paramètre Description
event_id ID de l'événement BilletWeb
since Optionnel — filtre les ventes après cette date (format YYYY-MM-DD HH:MM:SS)
ticket_id Optionnel — filtre par type de billet

Réponse (tableau de participants) :

[
  {
    "id": "12345678",
    "barcode": "6743097169",
    "ref": "BW-XXXXXX",
    "ticket": "Luge - Forfait 4 tours",
    "ticket_id": 12345,
    "name": "Jean Dupont",
    "email": "jean@email.com",
    "used": "0",
    "date": "2026-05-15 10:30:00",
    "price": "11.00",
    "event_id": "1350897"
  }
]

Champs importants :

Champ Type Description
id string ID unique de la commande (référence de commande)
barcode string Code barre unique (servira de lien entre BilletWeb et Odoo)
ref string Référence BilletWeb (format BW-XXXXXX)
ticket string Nom du billet
ticket_id int ID du type de billet
name string Nom du participant
email string Email du participant
used string "0" = pas encore composté, "1" = déjà utilisé
date string Date d'achat
price string Prix payé
event_id string ID de l'événement

2.3 Composter un billet (check)

POST https://www.billetweb.fr/api/event/{event_id}/check
  ?user=<user_id>
  &key=<api_key>
  &version=1

Body: {"code": "6743097169"}

Comportement :

  • Valide que le billet existe et n'a pas déjà été utilisé
  • Composte le billet (le marque comme used=1)
  • Idempotent ? Non — une fois composté, un deuxième appel échoue

Réponse succès :

{"success": true, "message": "Billet composté avec succès"}

Réponse erreur (billet déjà utilisé) :

{"error": "Ce billet a déjà été utilisé"}

3. Événements du Parc de la Luge

ID BilletWeb Nom Événement Odoo
1350897 Parc de la Luge - Billetterie Event ID 1
1353693 BON CADEAU Event ID 2

4. Mapping produits (18 billets)

Intitulé BilletWeb Code barre Odoo
Journée Luge illimitée BW-LUGE-JOUR
Luge - Forfait 4 tours BW-LUGE-4T
Luge - Forfait 6 tours BW-LUGE-6T
Luge - Forfait 10 tours BW-LUGE-10T
Luge - Forfait 12 tours BW-LUGE-12T
Poney BW-PONEY
Mon ticket Promo BW-PROMO
OFFRE LIMITÉE - SPÉCIALE TRIBU BW-LUGE-TRIBU
Tir à l'arc - 20 min BW-TIR-20
Tir à l'arc - 40 min BW-TIR-40
Kids électrique - 10 min BW-KIDS-E10
Trottinettes ETT - 20 min BW-TROTT-20
Bon cadeau Luge 4 tours BW-CADEAU-LUGE4
Bon cadeau Luge 3 tours BW-CADEAU-LUGE3
Bon cadeau Poney BW-CADEAU-PONEY
Bon cadeau Kids électrique BW-CADEAU-KIDS
Bon cadeau Tir à l'arc 20 min BW-CADEAU-TIR20
Bon cadeau Trottinettes ETT BW-CADEAU-TROTT

5. Architecture de synchronisation

┌─────────────┐     ┌──────────────┐     ┌──────────────┐
│  BilletWeb  │◄────│  n8n.n8n-1   │────►│ Sync Server  │
│  (API REST) │     │  (orchestre) │     │  (Python)    │
└─────────────┘     └──────┬───────┘     └──────┬────────┘
                           │                    │
                           │ Schedule: 15 min   │ POST /sync
                           │                    ▼
                           │           ┌────────────────┐
                           │           │ sync_billetweb │
                           │           │  (Python)      │
                           │           └───────┬────────┘
                           │                   │
                           │                   ▼
                           │           ┌────────────────┐
                           └──────────►│  Odoo Online   │
                                       │  (JSON-RPC)    │
                                       └────────────────┘

Composants

Service Technologie Port Accès
n8n n8n v2.21.7 Docker 5678 https://n8n.delgard.cloud
Sync Server Python 3.12-slim 8855 Interne (Docker network)
Traefik Reverse proxy 80/443 Let's Encrypt

Flux de sync (script sync_billetweb.py)

1. 🔒 Charger tous les barcodes Odoo existants (anti-doublon)
2. 🌐 GET BilletWeb /api/event/{id}/attendees (2 events)
3. Pour chaque attendee nouveau :
   a. Trouver/créer client (res.partner)
   b. Trouver produit (product.product par barcode BW-*)
   c. Trouver/créer commande (sale.order)
   d. Créer ligne (sale.order.line)
   e. Créer inscription (event.registration)
   f. Lier ligne → inscription
4. 📊 Résultat : "X nouveaux importés"

6. Webhook de compostage (Odoo → BilletWeb)

Quand un billet est scanné au PDV Odoo (state: open → done), un webhook composte le billet BilletWeb.

Odoo (Automated Action)
  │  POST webhook
  ▼
n8n Webhook Trigger
  │  POST /webhook/billetweb-compost
  ▼
BilletWeb API
  │  POST /api/event/{id}/check
  ▼
Billet composté ✅

Webhook URL

https://n8n.delgard.cloud/webhook/billetweb-compost

Payload attendu

{
  "event_id": 1350897,
  "barcode": "6743097169",
  "name": "Jean Dupont",
  "state": "done"
}

Configuration Odoo (Automated Action)

  1. Activer le mode développeur
  2. Technique → Automatisation → Règles d'automatisation → Créer
  3. Modèle : event.registration
  4. Déclencheur : « Lors de la mise à jour » + champ state
  5. Action : « Envoyer une notification webhook »
  6. URL : https://n8n.delgard.cloud/webhook/billetweb-compost
  7. Headers : Content-Type: application/json
  8. Champs : barcode, name, state, event_id

Test manuel

curl -X POST https://n8n.delgard.cloud/webhook/billetweb-compost \
  -H "Content-Type: application/json" \
  -d '{"event_id": 1350897, "barcode": "6743097169", "name": "Test", "state": "done"}'
# → {"message":"Workflow was started"}

7. Pièges et bonnes pratiques

Import initial : respecter le champ used

BilletWeb used État réel Odoo state correct
"0" Pas encore venu open
"1" Déjà composté done

⚠️ Ne pas tout mettre en done par défaut — l'import initial du 26/05 avait ce bug.

Correction post-import :

# Repasser en "open" les billets used=0
bw_unused = {a['barcode'] for a in bw_attendees if a['used'] == '0'}
to_open = odoo_call("event.registration", "search_read",
    [["barcode", "in", list(bw_unused)], ["state", "=", "done"]])
odoo_call("event.registration", "write",
    [[r['id'] for r in to_open], {"state": "open"}])

# Repasser en "done" les billets used=1
bw_used = {a['barcode'] for a in bw_attendees if a['used'] == '1'}
to_done = odoo_call("event.registration", "search_read",
    [["barcode", "in", list(bw_used)], ["state", "=", "open"]])
odoo_call("event.registration", "write",
    [[r['id'] for r in to_done], {"state": "done"}])

Anti-doublon : cache vs Odoo direct

  • Toujours requêter Odoo directement pour la liste des barcodes existants
  • Ne pas se fier uniquement au fichier cache (sync_cache.json) — il peut être vidé
  • Le cache est une optimisation, pas une source de vérité

Commandes multi-tickets

Ne pas bloquer la création d'une commande si client_order_ref existe déjà :

# ✅ Réutiliser la commande existante
existing_so = odoo_call("sale.order", "search_read",
    [[["client_order_ref", "=", ref]]], {"fields": ["id"]})
if existing_so:
    so = existing_so[0]["id"]  # Ajouter des lignes à la commande existante
else:
    so = odoo_call("sale.order", "create", [{...}])  # Créer nouvelle commande

Rate limiting BilletWeb

L'API BilletWeb n'a pas de limite documentée, mais espacer les appels d'au moins 1 seconde en cas de bulk.


8. Maintenance

Sync manuelle

docker exec n8n-sync-server-1 python3 /app/sync_billetweb.py

Réinitialiser le cache anti-doublon

docker exec n8n-sync-server-1 rm -f /root/.hermes/scripts/sync_cache.json
# Prochaine sync : recharge TOUS les barcodes depuis Odoo

Logs

docker logs n8n-n8n-1 --tail 50
docker logs n8n-sync-server-1 --tail 50
docker exec n8n-sync-server-1 cat /tmp/sync_result.json

Workflows n8n

Nom ID Status
BilletWeb → Odoo Sync n4r0JG3BvHKi9nmC ✅ Actif (toutes les 15 min)
Compost BilletWeb (webhook) V1TCykwcoSWlBHyX ✅ Actif

9. Fichiers associés

Fichier Emplacement
sync_billetweb.py (Docker) /docker/n8n-gdkj/sync-server/sync_billetweb.py
sync_billetweb.py (host) /root/.hermes/scripts/sync_billetweb.py
server.py (sync-server) /docker/n8n-gdkj/sync-server/server.py
docker-compose n8n /docker/n8n-gdkj/docker-compose.yml
Workflow n8n (export) /root/workspace/n8n/workflow-billetweb-odoo.json
Architecture doc /root/workspace/n8n/ARCHITECTURE.md