> ## Documentation Index
> Fetch the complete documentation index at: https://storekit.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Alertes de commande vers Slack ou votre téléphone

> Alertes Slack ou SMS pour les grosses commandes, les livraisons passées ou les envois POS échoués, à l'aide des webhooks storekit et d'un moteur de règles.

Une petite application qui surveille vos commandes et prévient la bonne personne à propos de celles qui comptent : grosses commandes, livraisons et commandes qui n'ont jamais atteint la caisse. Les règles sont les vôtres, à modifier depuis une page de réglages — pas de redéploiement pour changer un seuil.

> [!TIP]
>
> Si vous voulez simplement que chaque commande soit postée dans un canal Slack sans aucune règle, vous n'avez rien à construire : le portail webhooks de storekit peut poster directement sur Slack. Voir [Notifications Slack](/docs/fr/developers/webhooks/slack-integration). Construisez cette recette lorsque vous avez besoin de filtrage, de SMS ou de destinataires différents selon les événements.

## Fonctionnement

1. storekit envoie `order.created.v2` et `order.pos.dispatch.failed` à votre application.
2. Votre application confronte chaque événement aux règles que vous avez définies (valeur de commande, type de commande, mots-clés dans les notes) et choisit un canal.
3. Elle poste sur Slack via un incoming webhook, et envoie éventuellement un SMS via Twilio.

## Ce dont vous avez besoin

* Les webhooks activés sur votre forfait storekit (**Settings** → **Developers**).
* Un compte [Lovable](https://lovable.dev) ou [v0](https://v0.dev). Les deux ont besoin d'un backend pour l'endpoint webhook — le prompt demande au builder d'en déployer un et de vous fournir son URL. [Replit](https://replit.com) fonctionne aussi et est le choix le plus simple si le builder peine à mettre en place le backend.
* Une URL d'incoming webhook Slack pour le canal dans lequel vous voulez recevoir les alertes (créez-en une depuis l'application « Incoming Webhooks » dans le répertoire d'applications Slack, choisissez le canal et copiez l'URL).
* Facultatif, pour les SMS : un compte [Twilio](https://twilio.com) avec un numéro de téléphone. Les SMS sont facturés au message ; Slack est gratuit.

## Étape 1 : construire l'application

Collez l'intégralité du bloc dans le builder en un seul message. Modifiez d'abord les règles d'exemple sous **MY RULES** pour qu'elles correspondent à votre activité.

[![](https://mintcdn.com/storekit/IGeB_84apyho3Z6U/images/logos/lovable.svg?fit=max\&auto=format\&n=IGeB_84apyho3Z6U\&q=85\&s=cc21d11769d5e6b686fed56390a88f5e) Build with Lovable](https://lovable.dev/#prompt=I%20want%20a%20small%20alerting%20app%20for%20my%20restaurant.%20storekit%20sends%20it%20a%20webhook%20whenever%20an%20order%20is%20placed%20or%20an%20order%20fails%20to%20reach%20my%20till%2C%20and%20it%20decides%20whether%20anyone%20needs%20to%20know%20and%20tells%20them%20on%20Slack%20or%20by%20text.%20It%20must%20never%20miss%20an%20alert%2C%20never%20send%20the%20same%20alert%20twice%2C%20and%20never%20make%20storekit%20wait%20for%20a%20reply.%0A%0ABuild%20it%20with%20a%20backend%20that%20has%20a%20public%20HTTPS%20URL%20for%20the%20webhook%20\(deploy%20it%20and%20tell%20me%20the%20URL\)%2C%20a%20small%20database%20for%20rules%20and%20history%2C%20and%20a%20settings%20page%20I%20can%20use%20from%20my%20phone.%0A%0ACONTEXT%20ABOUT%20STOREKIT%0A%0AI%20run%20a%20hospitality%20business%20on%20storekit%20\(storekit.com\)%2C%20an%20online%20ordering%20and%20payments%20platform%20for%20restaurants%2C%20caf%C3%A9s%20and%20bars.%20storekit%20can%20notify%20my%20own%20app%20about%20things%20that%20happen%20in%20my%20store%20by%20sending%20webhooks.%0A%0AHow%20storekit%20webhooks%20work%3A%0A-%20Each%20event%20is%20an%20HTTP%20POST%20with%20a%20JSON%20body%20to%20a%20URL%20I%20register%20in%20the%20storekit%20dashboard.%0A-%20The%20body%20has%20the%20shape%20%7B%20%22event%22%3A%20%22%3Cevent%20type%3E%22%2C%20%22data%22%3A%20%7B%20...%20%7D%20%7D.%20Two%20exceptions%3A%20the%20legacy%20order.created%20event%20\(do%20not%20use%20it%3B%20use%20order.created.v2\)%20sends%20the%20bare%20order%20object%2C%20and%20the%20order.refund.created%20%2F%20order.refund.succeeded%20%2F%20order.refund.failed%20events%20put%20order%2C%20customer%2C%20venue%20and%20refund%20next%20to%20event%20instead%20of%20inside%20data.%0A-%20Requests%20are%20signed%20with%20Svix.%20Every%20request%20carries%20the%20headers%20svix-id%2C%20svix-timestamp%20and%20svix-signature.%20Verify%20them%20with%20the%20official%20%60svix%60%20library%20for%20your%20language%2C%20using%20a%20secret%20I%20will%20provide%20in%20an%20environment%20variable%20called%20STOREKIT_WEBHOOK_SECRET.%20Reject%20anything%20that%20fails%20verification%20with%20HTTP%20400.%0A-%20My%20endpoint%20must%20respond%20with%20a%202xx%20status%20within%2015%20seconds.%20Save%20the%20event%20to%20the%20database%20first%2C%20respond%20200%2C%20then%20do%20the%20work%20from%20the%20saved%20copy.%0A-%20Once%20I%20have%20responded%20200%2C%20storekit%20will%20not%20send%20that%20event%20again%2C%20so%20the%20work%20must%20not%20be%20lost%3A%20store%20each%20event%20with%20a%20status%20\(pending%2C%20done%2C%20failed\)%20and%20only%20mark%20it%20done%20after%20the%20work%20has%20actually%20succeeded.%20On%20startup%20and%20on%20a%20timer%2C%20pick%20up%20anything%20still%20pending%20or%20failed%20and%20retry%20it.%20Never%20do%20the%20work%20only%20in%20memory%20after%20responding.%0A-%20The%20same%20event%20can%20occasionally%20be%20delivered%20more%20than%20once.%20Use%20the%20svix-id%20header%20as%20the%20unique%20key%20for%20the%20saved%20event%3A%20a%20repeat%20of%20an%20event%20already%20saved%20is%20ignored%2C%20whatever%20its%20status.%0A-%20Any%20page%20or%20endpoint%20protected%20by%20a%20password%20must%20be%20served%20over%20HTTPS%20only%3B%20redirect%20or%20refuse%20plain%20HTTP.%0A-%20Money%20fields%20\(total%2C%20tip%2C%20deliveryFee%2C%20discountTotal%2C%20item%20price%2C%20modifier%20price\)%20are%20integers%20in%20minor%20units%3A%202500%20means%20%C2%A325.00.%0A-%20orderType%20is%20one%20of%20Delivery%2C%20Pickup%2C%20InStore%2C%20Curbside%2C%20CateringDelivery%2C%20CateringPickup%20or%20Billpay.%0A-%20table%20is%20only%20present%20for%20in-store%20orders%3B%20deliveryAddress%20and%20pickUpTime%20only%20for%20delivery%20orders.%20When%20they%20do%20not%20apply%20the%20key%20is%20omitted%2C%20so%20treat%20a%20missing%20key%20the%20same%20as%20null.%20notes%20and%20items%5B%5D.note%20can%20be%20null%20or%20empty.%20customer.companyName%20and%20customer.vatNumber%20appear%20only%20when%20supplied.%0A%0AExample%20order.created.v2%20payload%3A%0A%0A%7B%0A%20%20%22event%22%3A%20%22order.created.v2%22%2C%0A%20%20%22data%22%3A%20%7B%0A%20%20%20%20%22id%22%3A%20%22ord_abc123%22%2C%0A%20%20%20%20%22code%22%3A%20%22A1B2%22%2C%0A%20%20%20%20%22asap%22%3A%20true%2C%0A%20%20%20%20%22total%22%3A%202500%2C%0A%20%20%20%20%22tip%22%3A%20250%2C%0A%20%20%20%20%22deliveryFee%22%3A%20299%2C%0A%20%20%20%20%22discountTotal%22%3A%200%2C%0A%20%20%20%20%22orderType%22%3A%20%22Delivery%22%2C%0A%20%20%20%20%22pickUpTime%22%3A%20%222024-01-15T10%3A45%3A00Z%22%2C%0A%20%20%20%20%22channel%22%3A%20%22WEB%22%2C%0A%20%20%20%20%22poNumber%22%3A%20null%2C%0A%20%20%20%20%22createdAt%22%3A%20%222024-01-15T10%3A30%3A00Z%22%2C%0A%20%20%20%20%22deliveryTime%22%3A%20%222024-01-15T11%3A00%3A00Z%22%2C%0A%20%20%20%20%22notes%22%3A%20%22Ring%20doorbell%22%2C%0A%20%20%20%20%22customer%22%3A%20%7B%0A%20%20%20%20%20%20%22firstName%22%3A%20%22John%22%2C%0A%20%20%20%20%20%20%22lastName%22%3A%20%22Doe%22%2C%0A%20%20%20%20%20%20%22email%22%3A%20%22john%40example.com%22%2C%0A%20%20%20%20%20%20%22phone%22%3A%20%22%2B44123456789%22%2C%0A%20%20%20%20%20%20%22marketingConsent%22%3A%20true%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22items%22%3A%20%5B%0A%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%22name%22%3A%20%22Margherita%20Pizza%22%2C%0A%20%20%20%20%20%20%20%20%22printName%22%3A%20%22Margherita%22%2C%0A%20%20%20%20%20%20%20%20%22price%22%3A%201200%2C%0A%20%20%20%20%20%20%20%20%22quantity%22%3A%201%2C%0A%20%20%20%20%20%20%20%20%22plu%22%3A%20null%2C%0A%20%20%20%20%20%20%20%20%22posId%22%3A%20null%2C%0A%20%20%20%20%20%20%20%20%22taxRate%22%3A%2020%2C%0A%20%20%20%20%20%20%20%20%22note%22%3A%20null%2C%0A%20%20%20%20%20%20%20%20%22modifiers%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%7B%20%22name%22%3A%20%22Extra%20cheese%22%2C%20%22printName%22%3A%20%22Cheese%22%2C%20%22price%22%3A%20150%2C%20%22quantity%22%3A%201%2C%20%22plu%22%3A%20null%2C%20%22posId%22%3A%20null%2C%20%22taxRate%22%3A%2020%20%7D%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%5D%2C%0A%20%20%20%20%22venue%22%3A%20%7B%0A%20%20%20%20%20%20%22id%22%3A%201234%2C%0A%20%20%20%20%20%20%22name%22%3A%20%22My%20Restaurant%22%2C%0A%20%20%20%20%20%20%22slug%22%3A%20%22my-restaurant%22%2C%0A%20%20%20%20%20%20%22address%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%22street1%22%3A%20%22123%20Main%20St%22%2C%0A%20%20%20%20%20%20%20%20%22street2%22%3A%20%22%22%2C%0A%20%20%20%20%20%20%20%20%22city%22%3A%20%22London%22%2C%0A%20%20%20%20%20%20%20%20%22postCode%22%3A%20%22W1A%201AA%22%2C%0A%20%20%20%20%20%20%20%20%22country%22%3A%20%22UK%22%2C%0A%20%20%20%20%20%20%20%20%22companyName%22%3A%20%22My%20Restaurant%20Ltd%22%2C%0A%20%20%20%20%20%20%20%20%22coordinates%22%3A%20%7B%20%22latitude%22%3A%2051.5074%2C%20%22longitude%22%3A%20-0.1278%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22deliveryAddress%22%3A%20%7B%0A%20%20%20%20%20%20%22street1%22%3A%20%22456%20Oak%20Ave%22%2C%0A%20%20%20%20%20%20%22street2%22%3A%20%22Flat%202%22%2C%0A%20%20%20%20%20%20%22city%22%3A%20%22London%22%2C%0A%20%20%20%20%20%20%22postCode%22%3A%20%22E1%206AN%22%2C%0A%20%20%20%20%20%20%22country%22%3A%20%22UK%22%2C%0A%20%20%20%20%20%20%22notes%22%3A%20null%2C%0A%20%20%20%20%20%20%22coordinates%22%3A%20%7B%20%22latitude%22%3A%2051.5155%2C%20%22longitude%22%3A%20-0.0722%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%0AThe%20full%20list%20of%20event%20types%20and%20payloads%20is%20at%20https%3A%2F%2Fstorekit.com%2Fdocs%2Fdevelopers%2Fwebhooks%2Fwebhook-events%0A%0ATHE%20SECOND%20EVENT%3A%20order.pos.dispatch.failed%0A%0Astorekit%20also%20sends%20this%20event%20when%20an%20order%20could%20not%20be%20pushed%20to%20my%20point-of-sale%20system.%20It%20has%20a%20different%2C%20smaller%20payload%3A%0A%0A%7B%0A%20%20%22event%22%3A%20%22order.pos.dispatch.failed%22%2C%0A%20%20%22data%22%3A%20%7B%0A%20%20%20%20%22order%22%3A%20%7B%20%22id%22%3A%20%22ord_abc123%22%2C%20%22code%22%3A%20%22A1B2%22%2C%20%22total%22%3A%202500%20%7D%2C%0A%20%20%20%20%22venue%22%3A%20%7B%20%22id%22%3A%201234%2C%20%22name%22%3A%20%22My%20Restaurant%22%2C%20%22slug%22%3A%20%22my-restaurant%22%20%7D%2C%0A%20%20%20%20%22pos%22%3A%20%7B%20%22name%22%3A%20%22Zonal%22%2C%20%22error%22%3A%20%22Connection%20timeout%3A%20Unable%20to%20reach%20POS%20endpoint%22%20%7D%2C%0A%20%20%20%20%22retryCount%22%3A%203%0A%20%20%7D%0A%7D%0A%0AThis%20one%20is%20always%20urgent%3A%20it%20means%20the%20kitchen%20may%20not%20know%20about%20a%20paid%20order.%0A%0AWHAT%20TO%20BUILD%0A%0A1.%20POST%20%2Fwebhooks%2Fstorekit%20%E2%80%94%20verify%20the%20Svix%20signature%20with%20the%20official%20svix%20library%20and%20STOREKIT_WEBHOOK_SECRET%20against%20the%20raw%20request%20body%3B%20400%20on%20failure.%20Save%20the%20event%20and%20return%20200%20immediately%2C%20then%20evaluate%20rules%20and%20send%20messages%20in%20the%20background.%20Ignore%20any%20svix-id%20already%20saved.%20Handle%20order.created.v2%20and%20order.pos.dispatch.failed%3B%20save%20and%20acknowledge%20any%20other%20event%20type%20but%20do%20nothing%20with%20it.%0A2.%20A%20rules%20engine.%20Each%20rule%20has%3A%20a%20name%2C%20which%20event%20it%20applies%20to%2C%20conditions%2C%20one%20or%20more%20channels%20\(Slack%2C%20SMS%2C%20or%20both\)%2C%20a%20message%20template%2C%20and%20an%20on%2Foff%20switch.%20Conditions%20for%20order.created.v2%3A%20minimum%20total%20\(in%20pounds%2C%20convert%20to%20minor%20units%20when%20comparing\)%2C%20order%20type%20is%20one%20of%20a%20list%2C%20notes%20contain%20any%20of%20a%20list%20of%20words%20\(case-insensitive%2C%20also%20check%20each%20item's%20note%20field\)%2C%20and%20a%20time%20window%20\(only%20alert%20between%20HH%3AMM%20and%20HH%3AMM%20in%20TIMEZONE\).%20order.pos.dispatch.failed%20has%20no%20conditions%3A%20it%20always%20alerts%20on%20all%20of%20its%20rule's%20channels.%20Every%20matching%20rule%20fires%20on%20every%20channel%20it%20has%3B%20a%20rule%20fires%20at%20most%20once%20per%20order%20per%20channel%20\(order%20id%20%2B%20rule%20id%20%2B%20channel%20is%20unique\).%0A3.%20Slack%20delivery%20through%20an%20incoming%20webhook%20URL%20stored%20per%20rule%20\(SLACK_WEBHOOK_URL%20as%20the%20default\).%20Format%20the%20message%20with%20Slack's%20mrkdwn%3A%20bold%20first%20line%2C%20then%20one%20line%20per%20detail.%0A4.%20SMS%20delivery%20through%20Twilio%20using%20TWILIO_ACCOUNT_SID%2C%20TWILIO_AUTH_TOKEN%20and%20TWILIO_FROM_NUMBER%2C%20to%20one%20or%20more%20numbers%20stored%20on%20the%20rule.%20If%20the%20Twilio%20variables%20are%20unset%2C%20the%20SMS%20channel%20is%20shown%20as%20disabled%20in%20the%20settings%20page%20and%20is%20skipped%2C%20not%20errored%3B%20the%20rule's%20other%20channels%20still%20fire.%20Keep%20texts%20under%20160%20characters.%0A5.%20GET%20%2Fsettings%20%E2%80%94%20protected%20by%20HTTP%20basic%20auth%20with%20ADMIN_PASSWORD.%20Lists%20rules%20with%20on%2Foff%20toggles%2C%20lets%20me%20add%2C%20edit%20and%20delete%20rules%2C%20and%20has%20a%20%22Send%20test%22%20button%20on%20each%20rule%20that%20fires%20it%20with%20fake%20data.%20Below%20the%20rules%2C%20show%20the%20last%20100%20alerts%20sent%3A%20time%2C%20order%20code%2C%20rule%2C%20channel%2C%20and%20whether%20delivery%20succeeded%20\(store%20the%20Slack%20or%20Twilio%20response\).%0A6.%20If%20Slack%20or%20Twilio%20return%20an%20error%2C%20retry%20three%20times%20with%20a%20pause%20between%20attempts%2C%20then%20mark%20the%20alert%20failed%20in%20the%20history.%20Never%20retry%20a%20successful%20send.%0A7.%20GET%20%2Fhealth%20that%20returns%20200%20and%20%7B%20%22ok%22%3A%20true%20%7D%20and%20nothing%20else.%0A%0AMESSAGE%20TEMPLATES%0A%0ATemplates%20use%20placeholders%20in%20curly%20braces%3A%20%7Bcode%7D%2C%20%7Btotal%7D%2C%20%7BorderType%7D%2C%20%7BcustomerFirstName%7D%2C%20%7BitemCount%7D%2C%20%7Bitems%7D%20\(one%20line%20per%20item%20as%20%222%20x%20Margherita%20Pizza%22\)%2C%20%7Bnotes%7D%2C%20%7BdeliveryPostcode%7D%2C%20%7Btime%7D%20\(createdAt%20in%20TIMEZONE%2C%20HH%3AMM\)%2C%20%7BposName%7D%2C%20%7BposError%7D%2C%20%7BretryCount%7D.%20Format%20%7Btotal%7D%20from%20minor%20units%20with%20the%20CURRENCY%20environment%20variable%2C%20e.g.%20%2225.00%20GBP%22.%20Never%20put%20the%20customer's%20email%2C%20full%20surname%20or%20full%20phone%20number%20in%20a%20message.%20If%20a%20placeholder%20is%20null%2C%20replace%20it%20with%20%22-%22.%0A%0AMY%20RULES%20\(create%20these%20as%20the%20starting%20set\)%0A%0A-%20%22Big%20order%22%3A%20order.created.v2%2C%20minimum%20total%20100.00%2C%20Slack.%20Template%3A%0A%20%20*Big%20order%20%7Bcode%7D%20%E2%80%94%20%7Btotal%7D*%0A%20%20%7BorderType%7D%20%C2%B7%20%7BitemCount%7D%20items%20%C2%B7%20%7Btime%7D%0A%20%20%7Bitems%7D%0A-%20%22Delivery%20placed%22%3A%20order.created.v2%2C%20order%20type%20in%20Delivery%2C%20CateringDelivery%2C%20Slack.%20Template%3A%0A%20%20*Delivery%20%7Bcode%7D%20%E2%80%94%20%7Btotal%7D*%0A%20%20%7BdeliveryPostcode%7D%20%C2%B7%20for%20%7Btime%7D%0A-%20%22Allergy%20note%22%3A%20order.created.v2%2C%20notes%20contain%20allergy%2C%20allergic%2C%20intolerance%2C%20coeliac%2C%20Slack.%20Template%3A%0A%20%20*Allergy%20note%20on%20%7Bcode%7D*%0A%20%20%7Bnotes%7D%0A-%20%22Till%20failure%22%3A%20order.pos.dispatch.failed%2C%20channels%20Slack%20and%20SMS%20\(SMS%20skipped%20until%20Twilio%20is%20configured\).%20Template%3A%0A%20%20TILL%20FAILURE%20%7Bcode%7D%20%7Btotal%7D%20%E2%80%94%20%7BposName%7D%3A%20%7BposError%7D.%20Enter%20this%20order%20by%20hand.%0A%0ADEFINITION%20OF%20DONE%0A%0A-%20%5B%20%5D%20A%20signed%20order.created.v2%20for%20a%20%C2%A3120%20pickup%20order%20sends%20exactly%20one%20%22Big%20order%22%20Slack%20message%20and%20nothing%20else.%0A-%20%5B%20%5D%20The%20same%20event%20delivered%20twice%20sends%20one%20message%2C%20not%20two.%0A-%20%5B%20%5D%20A%20bad%20signature%20returns%20400%20and%20sends%20nothing.%0A-%20%5B%20%5D%20A%20%C2%A330%20Delivery%20order%20with%20the%20note%20%22severe%20nut%20allergy%22%20fires%20%22Delivery%20placed%22%20and%20%22Allergy%20note%22%2C%20not%20%22Big%20order%22.%0A-%20%5B%20%5D%20An%20order.pos.dispatch.failed%20event%20fires%20%22Till%20failure%22%20on%20Slack%2C%20and%20on%20SMS%20if%20Twilio%20is%20configured.%0A-%20%5B%20%5D%20Rules%20edited%20in%20%2Fsettings%20take%20effect%20on%20the%20next%20event%20without%20a%20redeploy.%0A-%20%5B%20%5D%20The%20example%20payload%20in%20the%20context%20\(a%20%C2%A325.00%20delivery%20with%20the%20note%20%22Ring%20doorbell%22\)%20fires%20only%20the%20%22Delivery%20placed%22%20rule%2C%20once.%0A-%20%5B%20%5D%20A%20Slack%20URL%20that%20returns%20an%20error%20shows%20as%20failed%20in%20the%20history%20after%20three%20attempts%2C%20and%20the%20app%20keeps%20accepting%20events.%0A%0AWHAT%20TO%20GIVE%20ME%20WHEN%20YOU%20ARE%20DONE%0A%0A1.%20The%20public%20webhook%20URL%20\(%E2%80%A6%2Fwebhooks%2Fstorekit\)%20and%20the%20%2Fsettings%20URL.%0A2.%20The%20environment%20variables%20to%20set%20\(STOREKIT_WEBHOOK_SECRET%2C%20ADMIN_PASSWORD%2C%20SLACK_WEBHOOK_URL%2C%20CURRENCY%2C%20TIMEZONE%2C%20the%20three%20Twilio%20variables\)%20and%20where%20to%20set%20them%20on%20this%20platform.%0A3.%20Confirmation%20that%20the%20backend%20stays%20up%2024%20hours%20a%20day%20and%20does%20not%20sleep%20between%20requests.%0A4.%20How%20to%20run%20the%20%22Send%20test%22%20button%20and%20what%20I%20should%20see%20in%20Slack.%0A)

[![Open in Replit](https://replit.com/badge?caption=Open%20in%20Replit)](https://replit.com/?stack=Build\&prompt=JIAg7ghgdgLiEgM4FsIBs3zQUwE4wEsoBzeABzJADMB7XEZATxF20RggFddoYA6JDDrYA1gTiJsUACaIQ4+OGwAjABY0aI8KqnYAbnnhQQdaYYJyyaCAGNs0k-WiOz9KhAJo5QltluqGZkIMABojBwUzGwIzOTAdGB0nKEYaKGwQdPtvGhARKBowcJAYbAxvHWQTYwBlaxstOhBlIOwAD34QYDhkTnZM-UNkCzlndDwYMPSDekkZEp0kCGQM8fwSsAI7MOgHaaGIEQz2YTE4SAVaJ18rRj4AKHuAIU5PCPPxAIRlWyP5xIgcFUEFGIDInGUaC2IAAEgAVOEABRqIAAqgAlAAy1CaiQyYBU6k0IAAFGYrDRmApdiUypgVgsMhjMQBKHZIVAYEDSQEQH6SHH0XCcHCjeaqCxCXCMHbzBCSGCEEiWCDEDKgGzOPoZKi4GhVJhg9TpB73ADCAHkAHJwgCiAA04SAAIJPC2op01OEW9G2gDSwDhj1AwuMCHUiDI4nQ4mYyj6RDYcjSglOChJJ1YZz4Nn1bKM1Sh6RceCIpBpZAgjBWsEs1hgVyqV187C4PFrYU1VAAl2KHD9cIgBJnRApNcYCoQqMxDYUwxR4MoaJw4IkyxVASBgRQpPJjIaR81mHNpGWlGoNCIh48YYVU1mFASL5o4nQRAAue4AWhAtv8IEGWB5DFWEEUREBEQtL1wE+RQACkamtZoaGkIJcgQZkul8YhJXMYw8XvUc4B5RBVCXCBcGkB4fzhRYl1QrcQUZJBtwyABvEAACJAJgTj3y4gAeHiSkYMhsAAPk4sJOJ5Dg+JADi+CUkAAF9VIEOEwFydo7DIQg0kQfiCJwYhbGYUw8BzVhAXsACDCAslcknEBtXkGAAG4XIFCzcCsvxSiovQACYWSQKRZGYgcMh8kxlAAK2wGxJmKAifL4VgqE4GQ-JshwAHoS18jKsqoxBOBsOx7Fsgq0uK7L3E8WyeMsFdCs7PohBWXAwnszhVnmOq9naVdtPsuAiHYPwHBoKg90QGIMlkiBqJAdFsAARz69hRlYJACGIdIHE2RIQBqPQCDaARbRmZhWE2tg4E1XBcAINhmJ0CBXDkRBzraL8YjCH6Lq-QgVlbZBKBpIG-vmg7AW4bABAANVLadGSqY6AlSqgqC2Ah0BAAADaHCZAKFlB4aVBRAVJuDJ6BiE4VVsDCBMSEUSQbFYOBQE2LkyD1c6zD3AspHOvUoBrOA9Ao-HIQyTUMFsr0fX9QMAH0AHVbSeGELQtP11ZqW0zV9OEBDWhKkqMRg13ZgE4AarwQBmAhcc1fTjEx0CkRAAAWAAGAOVoAWWYcKyBoIgeg6ltI-mb2ECCto2kEeG4k+IgQAARgAVjC3MZCHU6IAMZjhJ8Ailv5HUCEHZLWEjNIHCCoOwjxYxpFyAitNwLRdX1ZjEFL2zczIO5vxAC0oDsLDgTLxv47MFu28Is4YK5ZyTwWTdhNVDwoEB7vFl7rRen6ZzlAyNAaHYfjDz8GwAmExO05gPpSTEmQyzCLv0jCJ29hQo0jSGgGcFEtCRDSKsKgpR6A9zfIxUYSUmYYGPOVSqy8BDTzTvgTgkN5gpgQKDPAYQowNBcgQ22Ep2bsE8JgL+p52ZNEAQ4Gk3MqbiAEFaQY9Au7MVPoWKk+5sDIDoMwCAsDDCL2bmWFatFjjLAyMJccJgKoggIGkdAYDmiLTKAQGYtkxG7QBMYNIdgBCogFARaG-0HAfVcPACoGQsoEHunkbAzBmw2JHg4Hi-EECsDEpuGaosxpYGsgxYeBgIhyH2gUVg0gwjxBsjMNy30ODv2vD+Z0KQwTM0cABGQkdo5gj1KUJKtkWiKErIgRAvcHDnzgFfMKuAYkmDSfCJEKJQGME8okuuiU4BNGKgKKwB8faIlDtArxr00ARRJEIDgaB24EDIL-fRN0ABi2AWbcgsLmLKMA4Q0GWWEcQoiylbD2WI08uNDAC2ucA3a0dsBqkHCLYYCSXJQHEIZEAQVc5BwYH4KAcgADFgK+BBxWj5OEokMgWGqNFWaAARTZeAZQQS2CIfBYRgBQBqFKPZZpuDKHmmYMIZobIvRIOiqEN0qU0rLIiHF+DClPHoZWCeP4ODy2AkIspbApCOyaEQL8h4fKIE8mYBlmLnTSGkI3PsYIcWojIHCAgDJenU1lQYzFhVi6ax0PhHQzB+HOQgBQHRBEjhUmTMMRU9gj4lGsnABAww6lnjtUPJRTjMgijQAIScb0aQXOQIgAA2gAXT4CGkAqiWlQEDYU0Rek7gJo6vqSyuYIbQEYFaP1NIbBZq6nwGWMArScGQFfJwO4KKCviLuMq1rXpUUeLaNoywrDRUojmt19hy1BXyYwG+n1Pz3DYvcEAXEeLyU4mlLm-lB3BSktOriS15JTpnTOziMR52mHVnyGw2cgoAGY107q4rmMw87nTZyeEFS9O7OIgitfJGAwoWbrt3Us9A8lAVtx-VxQgZAANApCMBmSGLpQ7OwABgAnAhyDV6ZIHOXLAE5yz5IBxQy+uFCL530v1dKZ9u7yEiHVZqlY87W5BT9l+AO2cvx5zhNnAO74-a53fEHAAWmR69wIoDpDQPO7WTwBOcUjlWmteB5LJtCFBpduVnS8X4pxOjDGmMsdzmxjjZ6ON8ck3qm61H4Pqc04x5jrHs7Zx44ZgO-G8O7pDYged6IzxdzoFfDAkmS0nC6lu4Du7cb10LTR9TcEaCqCgAJ3d1h2DhfM1xVFNB4POZfaIjwon1NxWi1AAAAu0btOAcz6ji1xMgxpkucQANR+z9qes9XGABsAB2AAHAhirnFUB92wEqYgZoDIio-V+4DKkMt7tKBG+SkbgsKQWy5pR86Q4UWIEkaM2KABe22IAVfI7SytK31NrdwBt0sckMuoceXYeSp6gNXtQ5tXgsZ7vXZfVYTg8nA0ffI7fYA0gfuKaey+jgbR0Q2QA7hpbXEQ3A5WbD3rKE3avUHHN2HM6OKcSgCdrinbP0ICfrsyQUlKtHaS-Os0OhhVk6ky9O7-E864a4i92Ab2mfSS+wjrnAOgf8QUyskDEAIdQ-4q3VSsPo0LZUsB6NU3erJe3U9vd-Oc7nr9h9nHePOJh1Wg9NsvAeuIDQJwYg86mBfkbhwbgRutefSVUmILoPd3sFYAN7O86msgDW1nIlB2uJu92TAJ96mA+cWiDARg87MTNzSOHyO7Bhu3vU5rbOzoc7OmdOHw5sBSPqdRH6HP+pKwpEp6d5ga1Wy26ApiGAQO-vXo0JRIgNk3P8Wx-WcQnAU8gFztnPgQK2ua64jfEg3fe+Mb4KezrkvQey6vZNqDJn5WKuVc7lXQePfzta1PQ4LoDDG8-cH0PXEtn1gBT1yP0f1Ox5kPHrXieYDJ5q7abOIAWvOitFfjDn6b9cULx61cx5wWwj2byYTby3VH0BAn2S370HzzlzmkjHxwnfkn2DgDjayCmHQXx3VwNl1l3uAUWoBTShH6FCQrgRRVW5THQiiRU3FUEVDIEMjyjyhHGzFzTyi7hsEQC4MGBvjEkHDyifCJCvGEMJEvC-GakeDhBhFtFOhNmtFRV-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-k2I6jJsFJmjAm2ICMxIQn-NOo8Atk65EslEQnw0vjYAEmZtEA1JtLiw-r6r6Bw1-UNMQBU4zsLsXoOAds9tOJ8w2JXMQmJrGBERKqAmwg2ISF0nlMApVMRYbK7KHKrRbQwgLLTLKnE8ksQnE9bR8GQmPikmYAVIBBLrcBrqgnEK0A1IB4DRcL6B8Ku6sZFgzQMRfQrQzQABNIpcWNIKWF2WWI2ievgYgAQDTRO4FJOp4RETiPhtJcEG6zNALPAOKrLTwABFNMqXANYwpURhharYW2tEWZ8upZmNBhAZx7AVxxxJFQXX+7AJFo+2CTiL8N5oxk59EVETEW0FEEkNpjIPEAUQ6xYVsfAM8BUFkR4H8TiTlUgEojQvEilqCsIWC3oKoZonOGFVeR6kQDSexmyT8GdAAKjZbqv8ZQmwDUlZOaeWZUmlfXVCfSPhXCZAAAHaFJEnf81Jw05ADXmnTjcC2JTXZcWXiNkqkW1cILl0eW6rKLEVjB7XMUmU4EywvXpQryxrxWIYHGpWQBpX-XmAFWzBlWlnll1XNXan6n2AAn9XqYLWVhbWuJnQlZztmB4dOXXA8yV0gophc65BC4wawxc3iAsVtE8AcIbBzlYAaBYjoBtgML9FbBA3fhg33zsAw3pWc3Yja3UTopjBo2lWNWsdqnJ5OJNUuQzTWB5JXKSzdCcjPKOH-68rnZRXihNbSQD3EAbaxIHAjlPBzG+ZkakVC5cZGZElzq4QJXSgw2bLMRsQtlnQKSMR5DJ21JVX42s6FJhn4mO8xmJmrpYBDA1xkxWrqkhN217hUVbQtlq7AxMarQp4tkQBUVHLmWQBI0QBo0XQeTDpczuWCzmwEBwUHtVUGh2UYpzCAIu0kodEDzWX9pCoN6927rLb5hdGzwDGVpCPiPiDh4GRhIJrbJqHrkwoi5AbeO9lnJqGaBhOiOSOfgHBYZcc+S567SQW5BA4X7AzwoFK+ySA1PiOM9wUDMcOwGYoBTFh41OJJBDEA1AqR3o8-a5BOJI2wR6h7AN6aROJh2G383c6ydnIOP2X0j8WfwROXQzE8TMjSyPKDCOH2ygJQs3p53fal34NwrRWF6UwD23ZL2kbcgb20g72EZ214v1P0R-S5BJ6AoRZ07FRM6OBT7jqIjrYUwCJ0gOhMuPhEgsTAkqoKQeUCP1PiDisQ2aqqxaCRYCJK3hpSRqOoVgVamYIFGnPc6uIPN2YvNcAfNRNQpsugSbVFhfOwHHWN6-7qgLFJ4EuM893MJFGcGDO8Hdi76wBRg5AvKTbFhASpQJEpF4FVASHAQ3yGGUpFgrVKAjhMXkFdJBthvrx7gCSiTzGLQQAk7gBVCfd5CCTaajn3QXRfQcO8P7gaTiDwRIRoQRDLw0QsRSRAAyAnpNEN4KZOAX+EWHa-NpZ8xAeGHPMcWDFjrnOY7IVrlnHJ8AVEPe9FlI1l2v1kNmNlNlTrCArqrprrrobqbvRCJtOk2u2oVN1jV-VmZCpX2bUOOeJtsvsscsYeId2XK7lsucVvlkQF56OiSEpbMIG3RnFsBP88BEbAeBGpABAtC2uuOP3sil+FXtbHBPZXoy3GXA+QQB5ClIcC7jei3hwExd0Wod2WMD1IemvEhthGvuwaymYmXtXtKHXs3qEDDATmBB5jvpFC07d79yDfuCAA\&referrer=docs.storekit.com)

Either button opens the builder with the whole prompt below already filled in. Nothing starts until you press send, so read it through and edit the parts marked as yours first.

> **Prompt complet (cliquez pour développer)**
>
> ```text theme={null}
> I want a small alerting app for my restaurant. storekit sends it a webhook whenever an order is placed or an order fails to reach my till, and it decides whether anyone needs to know and tells them on Slack or by text. It must never miss an alert, never send the same alert twice, and never make storekit wait for a reply.
>
> Build it with a backend that has a public HTTPS URL for the webhook (deploy it and tell me the URL), a small database for rules and history, and a settings page I can use from my phone.
>
> ```
>
> ```text theme={null}
> CONTEXT ABOUT STOREKIT
>
> I run a hospitality business on storekit (storekit.com), an online ordering and payments platform for restaurants, cafés and bars. storekit can notify my own app about things that happen in my store by sending webhooks.
>
> How storekit webhooks work:
> - Each event is an HTTP POST with a JSON body to a URL I register in the storekit dashboard.
> - The body has the shape { "event": "<event type>", "data": { ... } }. Two exceptions: the legacy order.created event (do not use it; use order.created.v2) sends the bare order object, and the order.refund.created / order.refund.succeeded / order.refund.failed events put order, customer, venue and refund next to event instead of inside data.
> - Requests are signed with Svix. Every request carries the headers svix-id, svix-timestamp and svix-signature. Verify them with the official `svix` library for your language, using a secret I will provide in an environment variable called STOREKIT_WEBHOOK_SECRET. Reject anything that fails verification with HTTP 400.
> - My endpoint must respond with a 2xx status within 15 seconds. Save the event to the database first, respond 200, then do the work from the saved copy.
> - Once I have responded 200, storekit will not send that event again, so the work must not be lost: store each event with a status (pending, done, failed) and only mark it done after the work has actually succeeded. On startup and on a timer, pick up anything still pending or failed and retry it. Never do the work only in memory after responding.
> - The same event can occasionally be delivered more than once. Use the svix-id header as the unique key for the saved event: a repeat of an event already saved is ignored, whatever its status.
> - Any page or endpoint protected by a password must be served over HTTPS only; redirect or refuse plain HTTP.
> - Money fields (total, tip, deliveryFee, discountTotal, item price, modifier price) are integers in minor units: 2500 means £25.00.
> - orderType is one of Delivery, Pickup, InStore, Curbside, CateringDelivery, CateringPickup or Billpay.
> - table is only present for in-store orders; deliveryAddress and pickUpTime only for delivery orders. When they do not apply the key is omitted, so treat a missing key the same as null. notes and items[].note can be null or empty. customer.companyName and customer.vatNumber appear only when supplied.
>
> Example order.created.v2 payload:
>
> {
>   "event": "order.created.v2",
>   "data": {
>     "id": "ord_abc123",
>     "code": "A1B2",
>     "asap": true,
>     "total": 2500,
>     "tip": 250,
>     "deliveryFee": 299,
>     "discountTotal": 0,
>     "orderType": "Delivery",
>     "pickUpTime": "2024-01-15T10:45:00Z",
>     "channel": "WEB",
>     "poNumber": null,
>     "createdAt": "2024-01-15T10:30:00Z",
>     "deliveryTime": "2024-01-15T11:00:00Z",
>     "notes": "Ring doorbell",
>     "customer": {
>       "firstName": "John",
>       "lastName": "Doe",
>       "email": "john@example.com",
>       "phone": "+44123456789",
>       "marketingConsent": true
>     },
>     "items": [
>       {
>         "name": "Margherita Pizza",
>         "printName": "Margherita",
>         "price": 1200,
>         "quantity": 1,
>         "plu": null,
>         "posId": null,
>         "taxRate": 20,
>         "note": null,
>         "modifiers": [
>           { "name": "Extra cheese", "printName": "Cheese", "price": 150, "quantity": 1, "plu": null, "posId": null, "taxRate": 20 }
>         ]
>       }
>     ],
>     "venue": {
>       "id": 1234,
>       "name": "My Restaurant",
>       "slug": "my-restaurant",
>       "address": {
>         "street1": "123 Main St",
>         "street2": "",
>         "city": "London",
>         "postCode": "W1A 1AA",
>         "country": "UK",
>         "companyName": "My Restaurant Ltd",
>         "coordinates": { "latitude": 51.5074, "longitude": -0.1278 }
>       }
>     },
>     "deliveryAddress": {
>       "street1": "456 Oak Ave",
>       "street2": "Flat 2",
>       "city": "London",
>       "postCode": "E1 6AN",
>       "country": "UK",
>       "notes": null,
>       "coordinates": { "latitude": 51.5155, "longitude": -0.0722 }
>     }
>   }
> }
>
> The full list of event types and payloads is at https://storekit.com/docs/developers/webhooks/webhook-events
> ```
>
> ```text theme={null}
> THE SECOND EVENT: order.pos.dispatch.failed
>
> storekit also sends this event when an order could not be pushed to my point-of-sale system. It has a different, smaller payload:
>
> {
>   "event": "order.pos.dispatch.failed",
>   "data": {
>     "order": { "id": "ord_abc123", "code": "A1B2", "total": 2500 },
>     "venue": { "id": 1234, "name": "My Restaurant", "slug": "my-restaurant" },
>     "pos": { "name": "Zonal", "error": "Connection timeout: Unable to reach POS endpoint" },
>     "retryCount": 3
>   }
> }
>
> This one is always urgent: it means the kitchen may not know about a paid order.
>
> WHAT TO BUILD
>
> 1. POST /webhooks/storekit — verify the Svix signature with the official svix library and STOREKIT_WEBHOOK_SECRET against the raw request body; 400 on failure. Save the event and return 200 immediately, then evaluate rules and send messages in the background. Ignore any svix-id already saved. Handle order.created.v2 and order.pos.dispatch.failed; save and acknowledge any other event type but do nothing with it.
> 2. A rules engine. Each rule has: a name, which event it applies to, conditions, one or more channels (Slack, SMS, or both), a message template, and an on/off switch. Conditions for order.created.v2: minimum total (in pounds, convert to minor units when comparing), order type is one of a list, notes contain any of a list of words (case-insensitive, also check each item's note field), and a time window (only alert between HH:MM and HH:MM in TIMEZONE). order.pos.dispatch.failed has no conditions: it always alerts on all of its rule's channels. Every matching rule fires on every channel it has; a rule fires at most once per order per channel (order id + rule id + channel is unique).
> 3. Slack delivery through an incoming webhook URL stored per rule (SLACK_WEBHOOK_URL as the default). Format the message with Slack's mrkdwn: bold first line, then one line per detail.
> 4. SMS delivery through Twilio using TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN and TWILIO_FROM_NUMBER, to one or more numbers stored on the rule. If the Twilio variables are unset, the SMS channel is shown as disabled in the settings page and is skipped, not errored; the rule's other channels still fire. Keep texts under 160 characters.
> 5. GET /settings — protected by HTTP basic auth with ADMIN_PASSWORD. Lists rules with on/off toggles, lets me add, edit and delete rules, and has a "Send test" button on each rule that fires it with fake data. Below the rules, show the last 100 alerts sent: time, order code, rule, channel, and whether delivery succeeded (store the Slack or Twilio response).
> 6. If Slack or Twilio return an error, retry three times with a pause between attempts, then mark the alert failed in the history. Never retry a successful send.
> 7. GET /health that returns 200 and { "ok": true } and nothing else.
>
> MESSAGE TEMPLATES
>
> Templates use placeholders in curly braces: {code}, {total}, {orderType}, {customerFirstName}, {itemCount}, {items} (one line per item as "2 x Margherita Pizza"), {notes}, {deliveryPostcode}, {time} (createdAt in TIMEZONE, HH:MM), {posName}, {posError}, {retryCount}. Format {total} from minor units with the CURRENCY environment variable, e.g. "25.00 GBP". Never put the customer's email, full surname or full phone number in a message. If a placeholder is null, replace it with "-".
>
> MY RULES (create these as the starting set)
>
> - "Big order": order.created.v2, minimum total 100.00, Slack. Template:
>   *Big order {code} — {total}*
>   {orderType} · {itemCount} items · {time}
>   {items}
> - "Delivery placed": order.created.v2, order type in Delivery, CateringDelivery, Slack. Template:
>   *Delivery {code} — {total}*
>   {deliveryPostcode} · for {time}
> - "Allergy note": order.created.v2, notes contain allergy, allergic, intolerance, coeliac, Slack. Template:
>   *Allergy note on {code}*
>   {notes}
> - "Till failure": order.pos.dispatch.failed, channels Slack and SMS (SMS skipped until Twilio is configured). Template:
>   TILL FAILURE {code} {total} — {posName}: {posError}. Enter this order by hand.
>
> DEFINITION OF DONE
>
> - [ ] A signed order.created.v2 for a £120 pickup order sends exactly one "Big order" Slack message and nothing else.
> - [ ] The same event delivered twice sends one message, not two.
> - [ ] A bad signature returns 400 and sends nothing.
> - [ ] A £30 Delivery order with the note "severe nut allergy" fires "Delivery placed" and "Allergy note", not "Big order".
> - [ ] An order.pos.dispatch.failed event fires "Till failure" on Slack, and on SMS if Twilio is configured.
> - [ ] Rules edited in /settings take effect on the next event without a redeploy.
> - [ ] The example payload in the context (a £25.00 delivery with the note "Ring doorbell") fires only the "Delivery placed" rule, once.
> - [ ] A Slack URL that returns an error shows as failed in the history after three attempts, and the app keeps accepting events.
>
> WHAT TO GIVE ME WHEN YOU ARE DONE
>
> 1. The public webhook URL (…/webhooks/storekit) and the /settings URL.
> 2. The environment variables to set (STOREKIT_WEBHOOK_SECRET, ADMIN_PASSWORD, SLACK_WEBHOOK_URL, CURRENCY, TIMEZONE, the three Twilio variables) and where to set them on this platform.
> 3. Confirmation that the backend stays up 24 hours a day and does not sleep between requests.
> 4. How to run the "Send test" button and what I should see in Slack.
> ```

Ouvrez `/settings`, appuyez sur « Send test » sur la règle « Big order » et vérifiez que le message arrive bien dans Slack avant de connecter storekit.

## Étape 2 : connecter storekit

**1. Open the webhooks portal**

In the dashboard sidebar, go to **Settings** → **Webhooks**. If your plan includes webhooks and they are not yet enabled, click **Enable Webhooks**. If the page shows **Upgrade to enable webhooks**, [contact support](/docs/getting-started/contact-support) to discuss adding webhooks to your plan.

**2. Add your app as an endpoint**

In the embedded portal, add a new endpoint, paste the webhook URL your app builder gave you, and tick only the event types the recipe needs.

**3. Copy the signing secret into your app**

Open the endpoint you just created and copy its signing secret. In your app builder, save it as the environment variable `STOREKIT_WEBHOOK_SECRET` (builders call this "secrets" or "environment variables"). Redeploy if the builder asks you to.

**4. Send a test event**

Use the portal's test option on the endpoint to send a sample event. The delivery log shows the response code from your app. A `2xx` means your app accepted it; anything else, read the response body in the log — it is usually a missing secret.

Cochez `order.created.v2` et `order.pos.dispatch.failed` pour cet endpoint.

## Étape 3 : tester avec une vraie commande

Passez une commande sur votre propre boutique au-dessus du seuil « Big order » (ou abaissez le seuil à £1 dans `/settings` pour le test). Le message Slack devrait arriver dans les quelques secondes suivant la confirmation de la commande. Remettez ensuite le seuil à sa valeur d'origine.

Pour tester l'alerte d'échec de caisse sans casser votre caisse, utilisez l'option de test dans le portail webhooks et sélectionnez `order.pos.dispatch.failed` comme type d'événement.

## Idées

* **Canaux différents selon le service** : ajoutez une condition de jour de la semaine et routez les alertes du week-end vers un autre canal Slack.
* **Comptage quotidien** : une règle sans conditions qui incrémente un compteur, et un message récapitulatif à 22 h.
* **Notes basses** : ajoutez `order.rating.updated` et alertez le GM lorsqu'une note est de 2 étoiles ou moins.
* **Imprimante hors ligne** : ajoutez `printer.status.offline` et envoyez un SMS à la personne de service ; le payload contient le nom de l'imprimante dans `data.printer.name`.

## Ce que cela ne fait pas

* **Cela ne remplace pas les alertes propres à storekit.** Les sons de commande dans le tableau de bord, les e-mails d'imprimante hors ligne et la gestion des échecs POS continuent comme avant.
* **Cela ne peut ni accepter, ni refuser, ni corriger une commande.** Les webhooks sont à sens unique. L'alerte prévient une personne ; cette personne agit dans le tableau de bord.
* **Les SMS dépendent de Twilio**, y compris ses vérifications d'inscription et sa tarification au message. Slack est gratuit et immédiat, c'est pourquoi les règles de départ l'utilisent.
* **C'est votre service.** Le support storekit peut confirmer qu'un événement a été livré à votre URL et le code de réponse ; les règles et les messages sont les vôtres.

## Voir aussi

> **[Notifications Slack](/docs/fr/developers/webhooks/slack-integration)**
>
> Chaque commande directement dans Slack sans code.

> **[Écrire un prompt qui fonctionne](/docs/fr/guides/build/prompting-guide)**
>
> La structure derrière ce prompt, et quoi dire quand le builder se trompe.

> **[order.pos.dispatch.failed](/docs/fr/developers/webhooks/webhook-events#order-pos-dispatch-failed)**
>
> Le payload derrière l'alerte d'échec de caisse.

> **[Gérer les commandes en direct](/docs/fr/guides/orders/managing-live-orders)**
>
> Ce qu'il faut faire dans le tableau de bord une fois l'alerte reçue.


## Related topics

- [Journal des ruptures et digest matinal](/docs/fr/guides/build/recipes/out-of-stock-log.md)
- [Intégration Slack](/docs/fr/developers/webhooks/slack-integration.md)
- [Food trucks et pop-ups](/docs/fr/guides/use-cases/food-trucks.md)
- [Créer tes propres outils sur storekit](/docs/fr/guides/build/overview.md)
- [Tableau des commandes en direct pour le pass](/docs/fr/guides/build/recipes/live-order-board.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.