> ## 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.

# Alert ordini su Slack o sul telefono

> Avvisi Slack o SMS quando arriva un ordine grande, viene creata una consegna o fallisce un dispatch al POS, tramite webhook storekit e regole.

Una piccola app che tiene d'occhio i tuoi ordini e avvisa la persona giusta di quelli che contano: ordini di importo elevato, consegne e ordini che non sono mai arrivati alla cassa. Le regole sono tue e le modifichi da una pagina impostazioni — nessun redeploy per cambiare una soglia.

> [!TIP]
>
> Se vuoi solo che ogni ordine venga pubblicato su un canale Slack senza regole, non devi costruire nulla: il portale webhook di storekit può pubblicare direttamente su Slack. Vedi [Notifiche Slack](/docs/it/developers/webhooks/slack-integration). Costruisci questa recipe quando hai bisogno di filtri, SMS o persone diverse per eventi diversi.

## Come funziona

1. storekit invia `order.created.v2` e `order.pos.dispatch.failed` alla tua app.
2. La tua app controlla ogni evento rispetto alle regole che imposti (valore dell'ordine, tipo di ordine, parole chiave nelle note) e sceglie un canale.
3. Pubblica su Slack tramite un incoming webhook e, opzionalmente, invia un SMS via Twilio.

## Cosa ti serve

* I webhook abilitati sul tuo piano storekit (**Settings** → **Developers**).
* Un account [Lovable](https://lovable.dev) o [v0](https://v0.dev). Entrambi hanno bisogno di un backend per l'endpoint webhook — il prompt chiede al builder di deployarlo e darti l'URL. Anche [Replit](https://replit.com) funziona ed è la scelta più semplice se il builder fatica con la parte backend.
* Un URL di incoming webhook Slack per il canale in cui vuoi gli alert (creane uno dall'app "Incoming Webhooks" nella directory delle app di Slack, scegli il canale e copia l'URL).
* Opzionale, per gli SMS: un account [Twilio](https://twilio.com) con un numero di telefono. Gli SMS costano per messaggio; Slack è gratis.

## Step 1: costruisci l'app

Incolla nel builder l'intero blocco in un unico messaggio. Modifica prima le regole di esempio sotto **MY RULES** in base alla tua attività.

[![](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-CRltBtH4jSkTz4FPEjEBCfj4FYUeHYOpC8FyBPAqCRRfhNQLBikOXmUyFOV0TBD6B0AcB8ENBKVgC-BmglXGCQEYEmmQAEG6CQUUDuSoDwBFUBk5BwHoBoJoHHUeGV24jGgPT7V8i0J0MrBgH0NYWfRkl5A313R8igNVzSOkCPWUBPXPTpxvRq3vUfTpz-RywBSBQDlUgVykD6lKP3SZw12klxwiy4j1yrxt3bF4mkhNzNwt0YCtwNxr14g6Kg0T1KMGJq14y0VE2kjwD1FwCpzSHSCSk0Xwi1WwGXBgH4lRFx35R8GsifggigiKWkE8MWKX1Qw4UYGGyOXkjPXXQIJkIlGTGLHoLQEgACJcnOxFX4gUBWGgGcTyHEGJ33CrAcLgHyDvD5HOJqQ8GmnSNNE1hhGdCdG9BACeFRGAExFRUeAHweOgnEOfDEOMLgEABQCF2VGIIRYM6C6PaOGd+Xab2bGd2fGTAaGMmAgCmCiCReYFWX0AMOELWHWPWA2I2E2M2eAUyCaVcRYHgIoO6LaZpFCPpf2YFFMJ2BGAQGoEecucJdhAbbgYwVudorVFYU8GyMBduaw-QdAJmUoFgEUUNeYbeMGYeNUOJU1DIH4BoYgPUEqYIg6YQG2JAX6OxCJKaY8XxAQGEXYHAQqHKAKIdYoTQ2+bQiwbI3I7LewTyaJfqNhBoAoMAHAaQNURM05JIOyEVESMSZoVqC1Vss8b2Lhe4IKAQDPYUUUIpHCE0X8f8McjIYEf5BANY5JCUe44SakVtN6IQTsWRT2RAMIaBQpYxBWITETOQEkOoX4MIGoEOGofc+gJcRIfMD1JMApGbcZUoWUNhMxKAPKGaWaepRE1QAQYbb+Xc6mRdAdQKIKfiL5LVatEoU5AmEkLOSOEqPchNNIGYEaBgIgJoVxGAOIaw3NSsWlYgfMGKKPLspFA80JBAMg5KVzDC2ACZfNEwWaOiyUNi8AUwM8zUSQf6MFKQeaQgAwHYUwhNHQChR+AIcNAAcjkHjXuXmSfLlBKFOJgnvyKBJB1TWGaQGwJF3BhBhHfBDhDmKCMpMrMqzjhGABDltF42tFtBZAECLKHCyL0KAtYVCIKCYtPF3OhPdVBKrFGFiIIuqCwEwFCT+T9JwHkokugFPKuhugYA8rPFnOoEGSBPbKpifgSrKDciQU8kCX9IysbngB6FvmGRngyEEMKjBEMFyuE3yu0vSPkAcFqxisRXaviqaswCRVcXumcvuDPQtPqC0BXypkSBjI2wLCIFzX7IkOJEwhHAcFqvSvPMxGdDNENnEyVMNkwiYirmwHcBFBgGcpAC2ToFQC1IyGDIKW9gvIaDiuQD7mkDACgH4iXHsNC36CLD2Q7mRTFOLFqrMA4E8AeD9gtJvO5Bgw5OmoCE0k8E0S8jPDhE1gpOAAtHVi2stFRBtCNmAFRTCDRoxqxudA9BhHVm9D9DUOKBJsxExvVi2XRAtBDnVitFRBDieFtHRHblyBovoCPIDVkw+RWvCoIlnOCNmgIkRqhFyBlhej5HHIohcUEuSgImvJREapEwFVIjnH9R0KVtsizhsQG0GxVGbLDW+jEB3CSVRIAmemEGkE8glv9LitbIapPLKAyXoVKsRhAD9F2UoFKA6DkBKkMGzha3aNyp4EqUHAeFzgEAAHFbQnQ2Czb1wQBWSBZTkhkqlmAulwJ+RoQuATpvZnRUUQ5gArR1ZERnQagahNYfRUUBBMRJQ5BZyM4To0hfycYELiBiBRQwgcAwqGQHcwh7BqR5hZUBsMhO7PzQiEBOIahwpaR2BOJuzFQUwUxpLOqd5HZMqCrvZ3AjhuReQBAngyg7xXah6WJr7FgEs4B2N2jdLvooS1KVg7zHE6iwhZzOwvahcaQm08Q+FYakAMFdll5SRDwNaxrClZbkaZFBKhqWspbTo4GmgEHchuZ7TRZHbupfA-8Fh3cP63pX5KxXIr4YADKwwnUIYCKPTdw+stACJdLqAKyIhwytxJRxFuFeFCGqZ5QIG6lMoRTwoHg2tk7U6QA8oPo0AToHZCH7S5BHTihsdNAxs+pVJihJwaFSBvbEZHg7KG7nQU6QA7QQ5ERNq7QagZC016w3pXJxk7B1B5k8AwzM1cAdEJS7B-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 completo (clicca per espandere)**
>
> ```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.
> ```

Apri `/settings`, premi "Send test" sulla regola "Big order" e verifica che il messaggio arrivi su Slack prima di collegare storekit.

## Step 2: collega 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.

Spunta `order.created.v2` e `order.pos.dispatch.failed` per questo endpoint.

## Step 3: prova con un ordine reale

Effettua un ordine sul tuo storefront sopra la soglia di "Big order" (oppure abbassa la soglia a £1 in `/settings` per il test). Il messaggio Slack dovrebbe arrivare entro pochi secondi dalla conferma dell'ordine. Rimetti la soglia originale dopo.

Per testare l'alert di till-failure senza rompere la tua cassa, usa l'opzione di test nel portale webhook e scegli `order.pos.dispatch.failed` come tipo di evento.

## Idee

* **Canali diversi per turno**: aggiungi una condizione sul giorno della settimana e instrada gli alert del weekend su un canale Slack diverso.
* **Conteggio giornaliero**: una regola senza condizioni che incrementa un contatore e un messaggio di riepilogo alle 22:00.
* **Valutazioni basse**: aggiungi `order.rating.updated` e avvisa il GM quando una valutazione è di 2 stelle o meno.
* **Stampante offline**: aggiungi `printer.status.offline` e invia un SMS a chi è di turno; il payload ha il nome della stampante in `data.printer.name`.

## Cosa non fa

* **Non sostituisce gli alert di storekit.** I suoni degli ordini nella dashboard, le email di stampante offline e la gestione dei fallimenti POS continuano come prima.
* **Non può accettare, rifiutare o correggere un ordine.** I webhook sono a senso unico. L'alert avvisa una persona; la persona agisce nella dashboard.
* **Gli SMS dipendono da Twilio**, comprese le sue verifiche di registrazione e i prezzi per messaggio. Slack è gratis e immediato, ed è per questo che le regole iniziali lo usano.
* **È il tuo servizio.** Il supporto di storekit può confermare che un evento è stato consegnato al tuo URL e il codice di risposta; le regole e i messaggi sono tuoi.

## Correlati

> **[Notifiche Slack](/docs/it/developers/webhooks/slack-integration)**
>
> Ogni ordine direttamente su Slack senza codice.

> **[Scrivere un prompt che funziona](/docs/it/guides/build/prompting-guide)**
>
> La struttura dietro questo prompt e cosa dire quando il builder sbaglia.

> **[order.pos.dispatch.failed](/docs/it/developers/webhooks/webhook-events#order-pos-dispatch-failed)**
>
> Il payload dietro l'alert di till-failure.

> **[Gestire gli ordini live](/docs/it/guides/orders/managing-live-orders)**
>
> Cosa fare nella dashboard una volta che arriva l'alert.


## Related topics

- [Board ordini in tempo reale per il pass](/docs/it/guides/build/recipes/live-order-board.md)
- [Ordini Deliverect](/docs/it/guides/integrations/pos/deliverect/orders.md)
- [Ordini](/docs/it/guides/integrations/pos/comtrex/orders.md)
- [Log esaurimenti e riepilogo mattutino](/docs/it/guides/build/recipes/out-of-stock-log.md)
- [Food truck e pop-up](/docs/it/guides/use-cases/food-trucks.md)


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