Recevoir les commandes Tapfeed dans une caisse
Dernière mise à jour : 5 octobre 2026
Cette page s’adresse aux fournisseurs de caisse (POS) et aux intégrateurs. Tapfeed est une solution de commande et de paiement à table par code QR : quand un restaurant relie sa caisse, chaque commande lui est envoyée en temps réel, en JSON signé, à une adresse HTTPS que vous fournissez.
Par défaut, les serveurs saisissent les commandes Tapfeed dans la caisse depuis la liste « À saisir en caisse ». L’intégration automatique décrite ici est proposée sur demande aux établissements Premium qui utilisent Deliverect, une caisse ouverte ou un intégrateur : Tapfeed l’ouvre après échange avec le restaurant.
1. Fonctionnement
Le restaurateur saisit votre adresse de réception dans Tapfeed (Gestion → Caisse) et vous transmet la clé de signature affichée sur cette page. Tapfeed envoie ensuite une requête POST à chaque événement.
- Répondez par un code 2xx en moins de 10 secondes : l’envoi est alors considéré comme reçu.
- Sans réponse, ou avec un code 408, 425, 429 ou 5xx, Tapfeed réessaie automatiquement : après 15 s, 1 min, 5 min, 15 min, puis de plus en plus espacé, pendant environ 28 heures.
- Les autres codes 4xx sont un refus définitif (affiché au restaurateur, qui peut relancer l’envoi).
- Les redirections (3xx) ne sont pas suivies. L’adresse doit être en HTTPS et joignable depuis Internet.
2. Événements
tapfeed.test: envoyé par le bouton « Envoyer un test » (sans commande).order.created: une commande part en cuisine. Si le client a payé en commandant, le paiement est inclus.order.paid: la commande, déjà reçue, vient d’être payée en ligne (paiement de l’addition sur le téléphone).order.cancelled: la commande est annulée.
Pour une même commande, les événements arrivent toujours dans cet ordre : order.paid et order.cancelled ne partent qu’après la réception de order.created.
3. En-têtes
Content-Type: application/jsonTapfeed-Event: le type d’événement.Tapfeed-Signature:t=<horodatage>,v1=<signature>, où la signature est le HMAC SHA-256 (hexadécimal) det + "." + corpsavec la clé de signature.Idempotency-Key: identique à chaque nouvel essai du même envoi. Si vous l’avez déjà traité, répondez simplement 2xx sans le créer une deuxième fois.
4. Vérifier la signature
Refusez tout envoi dont la signature est invalide ou l’horodatage trop ancien (plus de 5 minutes).
// Node.js — vérifier la signature d’un envoi Tapfeed
import crypto from 'node:crypto';
function tapfeedSignatureOk(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
if (!parts.t || !parts.v1) return false;
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false; // 5 minutes
const expected = crypto.createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`, 'utf8').digest('hex');
return parts.v1.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}
// rawBody : le corps EXACT reçu (avant JSON.parse)
// header : en-tête « Tapfeed-Signature » ; secret : clé affichée dans Gestion → Caisse5. Contenu
{
"id": "evt_1842",
"type": "order.created",
"created": 1791403200,
"api_version": "2026-10-01",
"restaurant": { "id": "7c1e…", "name": "Café Boréal", "slug": "cafe-boreal" },
"order": {
"id": "b0f4…", "number": 42,
"table": { "id": "1d2c…", "label": "7" },
"status": "received", "lang": "fr", "pay_mode": "now",
"created_at": "2026-10-06T18:00:00Z", "currency": "CAD",
"lines": [{
"line_id": "9a1b…", "item_id": "3e5f…", "pos_code": "101",
"name": "Poutine", "name_fr": "Poutine", "name_en": "Poutine",
"station": "kitchen", "qty": 2,
"unit_price_cents": 1250, "total_cents": 2500,
"options": [{ "modifier_id": "4c6d…", "pos_code": "M-12", "name": "Grande",
"name_fr": "Grande", "name_en": "Large", "price_cents": 200 }],
"comment": "sans oignon", "happy_hour": false
}],
"subtotal_cents": 2500,
"taxes": [{ "code": "TPS", "rate": 5, "amount_cents": 125 },
{ "code": "TVQ", "rate": 9.975, "amount_cents": 249 }],
"total_cents": 2874,
"payment": { "status": "paid", "provider": "stripe", "reference": "pi_3Q…",
"covers_orders": ["b0f4…"], "amount_cents": 3249, "tip_cents": 375,
"card_brand": "visa", "card_last4": "4242", "paid_at": "2026-10-06T18:00:05Z" },
"missing_codes": 0
}
}- Montants en cents (entiers), dans la devise indiquée. unit_price_cents comprend le prix des options.
- pos_code : le code de l’article (ou de l’option) dans votre caisse, saisi ou importé par le restaurateur dans Tapfeed. Il peut être null : utilisez alors le nom et le prix. missing_codes indique combien de lignes n’ont pas de code.
- station : kitchen (cuisine) ou bar. comment : précision du client, à imprimer sur le bon.
- happy_hour : true si la ligne est facturée au prix happy hour. unit_price_cents est alors le prix réduit, et pos_code le code de l’article happy hour s’il a été renseigné (sinon le code habituel).
- payment : présent seulement si la commande est payée en ligne. Un paiement peut régler plusieurs commandes de la même table (covers_orders) : amount_cents et tip_cents sont ceux du paiement entier.
- Les champs ajoutés plus tard n’enlèveront ni ne changeront les champs existants : ignorez ceux que vous ne connaissez pas.
6. Réponse
Le corps de la réponse est facultatif. Si vous renvoyez du JSON avec pos_ref (ou reference, ou id), Tapfeed l’affiche au restaurateur comme numéro de la commande dans votre caisse.
7. Facturation obligatoire au Québec
Tapfeed n’est pas un système d’enregistrement des ventes (SEV) : la facture officielle doit être produite par la caisse certifiée du restaurant, qui communique avec le MEV-WEB de Revenu Québec. Les commandes et paiements reçus de Tapfeed doivent donc être enregistrés et facturés par votre caisse comme toute autre vente.
8. Partenariat et contact
Vous êtes fournisseur de caisse et souhaitez un connecteur direct (sans adresse à saisir pour le restaurateur), ou un environnement de test ? Écrivez-nous : support@tapfeed.com.