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

# Board ordini in tempo reale per il pass

> Board ordini a schermo intero che mostra ogni comanda aperta e la sposta tra Nuovo, In preparazione, Pronto e Fatto secondo gli eventi storekit.

Uno schermo a parete per il pass, il bar o il bancone che mostra gli ordini aperti come card e li fa avanzare mentre il loro stato cambia in storekit. Codici ordine grandi, elenchi di articoli, un timer che diventa rosso quando un ordine ha atteso troppo, e la scelta di cosa mostrare è tua. Nessuno lo tocca: segue la dashboard.

> [!TIP]
>
> storekit ha un [Kitchen Display](/docs/it/guides/orders/kitchen-display) integrato con cui la cucina può bumpare le comande. Costruisci questa recipe quando vuoi uno schermo in sola lettura con un layout diverso — un board "pronti" rivolto al cliente, una vista bancone che mostri solo i ritiri, o uno schermo bar che mostri solo le bevande.

## Come funziona

1. storekit invia gli eventi del ciclo di vita dell'ordine alla tua app: `order.created.v2` porta l'ordine completo; `order.preparing`, `order.ready_for_pickup`, `order.out_for_delivery`, `order.completed` e `order.canceled` portano solo id, codice e nuovo stato.
2. La tua app mantiene una card per ordine e ne aggiorna la colonna a ogni evento.
3. Una pagina del browser si aggiorna ogni pochi secondi e mostra le card in colonne.

## 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 e di un piccolo database — il prompt chiede al builder di deployarlo e darti l'URL. Anche [Replit](https://replit.com) funziona.
* Uno schermo con un browser (una TV con una stick economica, un vecchio iPad o un laptop).

## Step 1: costruisci l'app

Incolla nel builder l'intero blocco in un unico messaggio. Se vuoi una variante rivolta al cliente o dedicata alle bevande, modifica prima **MY BOARD**.

[![](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%20live%20order%20board%20for%20my%20restaurant%3A%20a%20full-screen%20web%20page%20that%20shows%20open%20orders%20as%20cards%20in%20columns%20and%20moves%20them%20along%20as%20storekit%20tells%20it%20about%20status%20changes.%20Nobody%20interacts%20with%20the%20board%3B%20it%20just%20stays%20accurate.%20storekit%20sends%20the%20status%20changes%20as%20webhooks.%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%20the%20current%20orders%2C%20and%20a%20front%20end%20designed%20for%20a%20TV.%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%20STATUS%20EVENTS%0A%0ABesides%20order.created.v2%2C%20storekit%20sends%20these%20events%20for%20the%20same%20order%20as%20it%20moves%20through%20the%20kitchen.%20order.preparing%2C%20order.ready_for_pickup%2C%20order.out_for_delivery%2C%20order.completed%20and%20order.canceled%20all%20have%20this%20smaller%20payload%2C%20with%20data.order.status%20set%20to%20the%20new%20status%3A%0A%0A%7B%0A%20%20%22event%22%3A%20%22order.preparing%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%22status%22%3A%20%22preparing%22%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%0A%20%20%7D%0A%7D%0A%0ASo%20the%20order%20id%20is%20data.id%20for%20the%20full%20payload%20and%20data.order.id%20for%20the%20smaller%20one.%20Write%20one%20function%20that%20returns%20the%20id%20and%20code%20from%20either%20shape.%20Treat%20canceled%20as%20%22remove%20from%20board%22%20and%20out_for_delivery%20as%20%22Done%22.%20There%20is%20no%20accepted%20or%20rejected%20event%3A%20an%20order%20stays%20in%20New%20until%20its%20first%20status%20event%20arrives.%0A%0AEvents%20can%20arrive%20out%20of%20order%20or%20twice.%20Store%20a%20rank%20per%20status%20\(created%200%2C%20preparing%202%2C%20ready_for_pickup%203%2C%20out_for_delivery%204%2C%20completed%204%2C%20canceled%209\)%20and%20never%20move%20a%20card%20to%20a%20lower%20rank%20than%20it%20already%20has.%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%3B%20update%20the%20board%20state%20afterwards.%20Ignore%20any%20svix-id%20already%20saved.%0A2.%20An%20orders%20table%20keyed%20by%20storekit%20order%20id%20with%3A%20code%2C%20status%2C%20rank%2C%20orderType%2C%20table%20name%20\(or%20null\)%2C%20customer%20first%20name%2C%20items%20\(name%2C%20quantity%2C%20modifier%20names%2C%20notes\)%2C%20order%20notes%2C%20createdAt%2C%20deliveryTime%2C%20venue%20name%2C%20last%20updated.%20The%20full%20order.created.v2%20payload%20fills%20or%20refreshes%20every%20field%3B%20small%20payloads%20update%20only%20status%2C%20rank%20and%20last%20updated.%20If%20a%20small%20payload%20arrives%20for%20an%20order%20the%20board%20has%20never%20seen%2C%20create%20a%20card%20with%20just%20the%20code%20and%20status%20so%20it%20is%20not%20lost.%0A3.%20GET%20%2Fboard%2F%3CBOARD_TOKEN%3E%20%E2%80%94%20the%20full-screen%20page%2C%20where%20BOARD_TOKEN%20is%20a%20long%20random%20secret%20from%20an%20environment%20variable.%20There%20is%20no%20login%20because%20it%20runs%20on%20a%20screen%20behind%20the%20counter%2C%20so%20the%20token%20in%20the%20URL%20is%20the%20only%20thing%20keeping%20strangers%20out%3A%20any%20request%20to%20%2Fboard%20or%20%2Fapi%2Fboard%20without%20the%20exact%20token%20gets%20404%20and%20nothing%20else%2C%20and%20the%20token%20must%20never%20appear%20in%20logs%20or%20error%20pages.%20Below%20I%20write%20%2Fboard%20for%20short%3B%20always%20include%20the%20token%20segment.%20The%20page%20must%20not%20include%20customer%20surname%2C%20phone%2C%20email%20or%20delivery%20address%20anywhere%20in%20the%20page%20or%20its%20data%20requests.%20Columns%2C%20left%20to%20right%3A%20New%20\(created\)%2C%20Preparing%2C%20Ready%20\(ready_for_pickup\)%2C%20Done%20\(completed%2C%20out_for_delivery\).%20Cards%20show%3A%20the%20order%20code%20very%20large%2C%20orderType%20and%20table%20name%2C%20the%20customer's%20first%20name%2C%20the%20item%20list%20as%20%222%20%C3%97%20Margherita%20Pizza%22%20with%20modifiers%20indented%20and%20notes%20in%20italics%2C%20and%20a%20timer%20showing%20minutes%20since%20createdAt.%20Cards%20are%20ordered%20oldest%20first%20inside%20each%20column.%20Cards%20in%20Done%20disappear%20DONE_MINUTES%20after%20they%20entered%20Done%20\(default%2010\).%20Cards%20for%20canceled%20orders%20disappear%20immediately.%0A4.%20The%20page%20refreshes%20its%20data%20every%205%20seconds%20without%20flicker%20\(fetch%20JSON%20from%20GET%20%2Fapi%2Fboard%2F%3CBOARD_TOKEN%3E%20and%20re-render%2C%20or%20use%20server-sent%20events\).%20If%20a%20refresh%20fails%2C%20keep%20showing%20the%20last%20data%20and%20show%20a%20small%20%22reconnecting%22%20label%3B%20never%20show%20a%20blank%20board.%0A5.%20Timer%20colours%3A%20default%20until%20WARN_MINUTES%20\(default%2010\)%2C%20amber%20until%20LATE_MINUTES%20\(default%2020\)%2C%20red%20after.%20For%20orders%20with%20a%20deliveryTime%20in%20the%20future%2C%20count%20down%20to%20deliveryTime%20instead%20and%20label%20it%20%22for%2011%3A00%22.%0A6.%20Design%20for%20a%201080p%20TV%20viewed%20from%20three%20metres%3A%20dark%20background%2C%20minimum%2028px%20body%20text%2C%20order%20codes%20at%20least%2096px%2C%20no%20hover-only%20information%2C%20no%20scrollbars%20%E2%80%94%20if%20a%20column%20overflows%2C%20shrink%20cards%20gracefully%20and%20show%20%22%2BN%20more%22%20at%20the%20bottom.%0A7.%20Filters%20via%20query%20string%20so%20I%20can%20point%20different%20screens%20at%20different%20views%3A%20%3Ftypes%3DPickup%2CDelivery%20shows%20only%20those%20orderTypes%3B%20%3Fcolumns%3DReady%20shows%20only%20that%20column%20with%20much%20bigger%20cards%20for%20a%20customer-facing%20%22ready%20to%20collect%22%20screen%3B%20%3Fvenue%3D%3Cslug%3E%20if%20the%20account%20has%20more%20than%20one%20venue.%0A8.%20GET%20%2Fhealth%20that%20returns%20200%20and%20%7B%20%22ok%22%3A%20true%20%7D%20and%20nothing%20else.%20Every%20other%20route%20must%20be%20either%20%2Fboard%2F%3CBOARD_TOKEN%3E%2C%20%2Fapi%2Fboard%2F%3CBOARD_TOKEN%3E%20or%20the%20webhook.%0A%0AMY%20BOARD%0A%0A-%20Timezone%3A%20TIMEZONE%20environment%20variable%3B%20show%20all%20times%20in%20it.%0A-%20Show%20the%20item%20list%20on%20cards%3A%20yes.%0A-%20Customer-facing%20variant%20I%20will%20run%20on%20a%20second%20screen%3A%20%2Fboard%2F%3CBOARD_TOKEN%3E%3Fcolumns%3DReady.%0A%0ADEFINITION%20OF%20DONE%0A%0A-%20%5B%20%5D%20A%20signed%20order.created.v2%20creates%20a%20card%20in%20New%20within%205%20seconds%2C%20showing%20the%20code%2C%20items%20and%20a%20running%20timer.%0A-%20%5B%20%5D%20order.preparing%2C%20order.ready_for_pickup%2C%20order.completed%20for%20the%20same%20id%20move%20the%20card%20one%20column%20at%20a%20time%2C%20and%20it%20disappears%20DONE_MINUTES%20after%20completed.%0A-%20%5B%20%5D%20Receiving%20order.preparing%20after%20order.ready_for_pickup%20leaves%20the%20card%20in%20Ready%20\(it%20never%20goes%20backwards\).%0A-%20%5B%20%5D%20The%20same%20event%20delivered%20twice%20changes%20nothing%20the%20second%20time.%0A-%20%5B%20%5D%20A%20bad%20signature%20returns%20400%20and%20the%20board%20does%20not%20change.%0A-%20%5B%20%5D%20order.canceled%20removes%20the%20card%20immediately.%0A-%20%5B%20%5D%20%2Fboard%2F%3CBOARD_TOKEN%3E%3Fcolumns%3DReady%20shows%20only%20Ready%20cards%2C%20large%2C%20with%20no%20item%20list.%0A-%20%5B%20%5D%20%2Fboard%20and%20%2Fapi%2Fboard%20with%20a%20missing%20or%20wrong%20token%20return%20404.%0A-%20%5B%20%5D%20Neither%20the%20HTML%20nor%20the%20JSON%20contains%20an%20email%20address%2C%20phone%20number%2C%20surname%20or%20delivery%20address.%0A-%20%5B%20%5D%20Turning%20the%20backend%20off%20and%20on%20loses%20no%20cards.%0A%0AWHAT%20TO%20GIVE%20ME%20WHEN%20YOU%20ARE%20DONE%0A%0A1.%20The%20public%20webhook%20URL%20\(%E2%80%A6%2Fwebhooks%2Fstorekit\)%20and%20the%20full%20%2Fboard%20URL%20including%20the%20token.%0A2.%20The%20environment%20variables%20to%20set%20\(STOREKIT_WEBHOOK_SECRET%2C%20BOARD_TOKEN%2C%20TIMEZONE%2C%20optionally%20DONE_MINUTES%2C%20WARN_MINUTES%2C%20LATE_MINUTES\)%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%20open%20the%20board%20in%20full-screen%20mode%20on%20a%20TV%20browser.%0A)

[![Open in Replit](https://replit.com/badge?caption=Open%20in%20Replit)](https://replit.com/?stack=Build\&prompt=JIAg7ghgdgLiEgDYEsBuBTEB7ATgE3RxACMsJ8QAzXEAWwE8Qd0BnGCAVx2hgC54qHRIgC0LAMbN0UcOmIgADhADmmGAAsIcFuqxgW2BdOz5CBiAfHk8B5DPFZEHWlHNQ8dLBgMb0teIhYUMrwBmy46ADWyHAw6MK2cBCkHNrsMByWmsGsAHQgAHJYpHiMdnHc4jAGYDHqIL4kZPgA3CAxIABWmWkQ9Obi4lxa6PnhzNHa0jYN6phsWpkg4tmq5jVyuliRLLkAUHsAQhzIiB4dtRoCxBDikdOzWiCa5oocxCjiIAASACq-AAUAMogACqACUADJUGiNMCbLDbEAACgICkCZSS7ga8UQdDUczBUIAlAAaAQsWgQYQgPBaZIWTDUIiNIY4ZiwEwEHAscnQDwISg4IJwB4EFjIZRQdAeZkCX4ANX2ewAwgB5Aq-ACiAA1fiAAIKHNWg-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-aPIus-c7YRIiA3-NEVLVQhAKwkoZ2Yqlxbfme0qjmAy1HrHNm7f4BHSDxFjuwFO4Tli6IOD-cp3dh7NOH0QHe5925Vs+I-bdT13i963Vtcqv58dh2p2PcJ8ui2W3ofLYog7Qa21ODcFgBVlgThlA9oYCIYs7BSxCYl0YvlAY7OA8nWwKQMBQ49ryyAYbc44XzeIibpKMA90UTt3x8nxFIQ9yCK752bA6uboosLUOBoQDB4NK7+ZsB1o9tBNaCPkboD0Ax9LxgQ0SwK7gJCGAj2XsOBUnYEYRn+BQ7zJ2DIAeQDh1Drke5RXxfEUCMEGIHAK+4dyIu0r7PAfc7Xa13j8nuW8v5YboXDvKHm4ooVmBEAV4GgwErqhjvnfEUmaXkAe6Jdgzoj2z37hvcS99zAf3sOtShxAAVg0BQKuR6oYhiiseKuGZpz1vjiJ8AF7iEXziDejbl-81XmvCOcOFiRvSCP-DiNvK2IrayBtHvCdOA7nbnPYQRQQGkFANeNxZOOiIwAVMlZtGYB8eAKcXVBQWScKcKeCGAJLcKMucQFgGg0iQIIwHkcKeEdcREHYVgw8SIEQPKA4X4b4LUOOX4A0X4UEEELUBULUTUIEA4Q4VgS6A6PtfjAdaya6eFFsDOGOHCHRPKFGXRWNUyExDoDhbwWYYUDgUbQ6SYJHKAfIPtSmSSdmYIckPtbxegQWZkQWFDKFKKdGGATw3AQWAfUFKKaMCtTJOMDqKtKMaACSJ+AIPETuAkQgykWRfZPofA8kQGNOXIPtSJMIShFORoaUMAQOc+VtQXEiZqGdGIxwpQdFVXADViekEfaDKtMdYiadCiWdedPLXHDdWHbdXdXHAonteo5w1XPiPnaQKqTo4XPbMXFiGHFbVPOXbXUYlXNXegDXdYjPIiLvdnJAoEBeStYxS6LVXIi4mxQkIKCmTIsgAUbEXIvta42EQkNInmbNaUWVcbFyJMIKVuaSBVJ4EmLgVwQ6C49MQYquMNemOoNyHQVVLRX4Q1VseI8hAwIiZgUwpkauJoawA41+VIQInAYIj9ZGIBIiQLDLQSMbX5deYCW4CSKSFKGgZgFWSIrSRxeMKtQOfoNhOhMohZU4cJAwRzNeAojxeAPabwZUVabMSwOmcgTZROfw7ALqfyRJGAWoCSfIOFCIAQBXFeZg8opYZEFQlKYnCYxo9fXOdqDwrwnwocJdVwkkrwkIy2YqSNBSSI+vcRDEjwH9F+bEaUCpXEgQXaDwJsAQQIeEIgY0x4GQDoakdwwBXYA4YWb4UQkAC0EAQ4UEYASEAFA4avV8d8fULg9go8CgjQjoQAFAIQB9Y-pGgFolopopRPpMBAY-JKAQYwYIYYZ4ZEZyAuFsQ+YrRbRfgRYxYJYpYZY5YFZp5Z415GhuAyjNoxo4BMI2hrY2cgxH4uAtF45E5Ghk4KEMgcAZBC42cxUsx6kRg5FjIFA2ICQnJmgPAz4f4KhIB8BY5gBAlJpE9To3ooSvEHTgw-F9hrJ8gYk2VKVOZLF0B6AUpiAFw6y4AtSLi5p+BBj1Cg5c5oBIhXCq1vkjBi4qVfVDDkQaBuNYxrMyoqAs414YdVkOsL5WKQBScy9QjgcDY3IYdyxDNYwtTDNipDUZRBNRksV1pFMKpZiqKsxyQfN9IXzLJczbibUwiJKQobJG18CmKEgml0AhRWA5gDB6Ful4g8A2hPi8Q8DHiDBsFXzsAoA6UCjCKoAV50wVKsE1K6124upT4qR7im1HiZTVSDo5Q6YtTGhkIKBsIwzESko55lgJLIzrBj56huhVzCQYSXp0glgWBgIOhCDR5t4qC9gl18gABxLUSs+KvAcKSiY0A0cEAFQWC0a0aQhiEARsxoO40QCQKQGQeJbZXNQgTAVq9qzqqWaQrVBAUApgfkOEjOGtOAIUOEumBmLOIIFmOANmTZSiukyarVdsJALASCGQTeKwEyDoJ0CE5BYMGtYwTePBaMvKkDCofVRoJse4ZMhVTAUCLVPyNyxgDWM1JKD0fBBHHIHkbAVIHkjaEaLclOcKRqxJcKVVZAdGj8rK9Us8stVWP64wVQHMa2C2KIxkiGkIeIDOHyD6tQbYYwQpFisJTNCyIgOcQIZQQMIgQgYUIgMa2OeQuM9ucAP4iKDGuUHQXAGANoakSAAUuwcQJwXqX65mmQDOZQfak6jMBJVmuAUeFWtWrmUNRi+KK82NdBdLbZMLUUmgT0vXflNWCa45QG-WytMUvqCbTc7aWOOrJwFwcsBSX+FOTZUbPgQodAMoi0nS2MAEZxSY8kIaIxRgZEdw0k7wiFbBWMGkzAC0n0yhGUN0gIj0ik+gYkfIXFP84MXQMAOSQkLUmE6VPMNbbZGDIwKm9gRCzi1kc2wgAAcnFOYqNutshI63hjXipIbQAHWrcRsxtPRJsZs5ssqdl+L4a7ACBYByFQz0lbBkyBlQZyx0wUExVET67VwLlrVP8ppNE0ra1JKqCQAa6ZhyAzjJqOozhtomLs5upFD6ZrxlhHBnA7DX7rBD6QB87aQHwObyBoGNQtRBY7ZgAChTQtQQRuE3JfBHZd66loHv4UQCAsohA4BiMq6IHa65QAz4g2Sq0DAgN4GubaB7zwY4g5F9gLY9axqPZTKdADoYhGH6RD5kZI41qe5g4NB1TKBPh7giBkRKBKED5fx-xNr-A6rKzsbcbrBmrpqOquqeqqbmBdj3A0FEkTIM5SlCAxAj48pKHgAgq+Hix6hH5yx7hJI669BNZCRfK04qbZayjgrZFiJmBo5pQqhUwDi8wLM2gkqiBAnrg8wvKCT8B9hw5BIL6iAHBAguBZJaQTLOBEB9Iyc8RhY2qCgUG0GMGQRURCmyHQ8rZYxhF00sFSmQBIRRDkHUH0HtRamSGim4BC5YwCHsGzIQBJkaB-IpH6gEAQjFM2EBrUgjzvSFlaQ9BYJgJ5mL7uo4gjEqaYn4hwliI5RQ4tMbYiJ9gCt8ggUJQpR9CEBiMSsrYhxFQmz9p4RZR8SNApB8RF98m6QAEbg7hlALD3ByQb6xVnB18SsFAA5MIcQGoSLjFBjzA4AFILA4Af0Cs4XyRzrdA1oRBWE7ACwjYgg8XgJhrHBEB6wDBGyuxIzQGXBylCBZG9BywdB0UV4oyDBQXbgTKbUxzPz67iJMsChPBmAiTRx3zdUw19git8hJlTgKg9ZwYuKqpkYTdVxirxbxFFAXZORdklGORtAXqISngjXJrWYPn8mAB+bA1gAAXgJUhRGXg2lUCdpXBrdE-pwDItYDaFtZybAZYEddTp8Xrq9ceB2iZZkEBkKQPmIElFUGycgYeZDVKhsayjBkJmxIgpjJyYUiqAOOGpSsDf50dcomV0sN6oZcaGZK+vTIlYJBiqTH532BK1qvqoikMWKfqC1jgDBKvIMBvKpqh22BPSaz4ipr0jwVpsQAzhWmlQ7DGyYH8MwENp9XhN8CIB0fwD0bVDaoMbmoKAYnJCxo9D3aapasPZmsMdPe1MXm4OVDtgAE18zb2SyKVFMptv5+BfhgA7YtRKMkGklGY9qj5DqOYFJbKRWQnUEoGaEKUgQRXGgnUp7ML7BIH+AUKMyLxEVM2cARBs3VwoOeBxbyY8QHrXKiZo5PyzX+Ar2D2j3ZrurT2g3Y3Q3w3yU9gAUtRJk0G7RgB-w1RJlEGCgtQDgLwXUQA3VDQOyZptKn7dKG1LTXgozBSY6sq5xxGvJJHror7CZWQsACA2K-ABUnFnQoBNYsmBoZO5OHCk7GjkXCBooHSs7nSXPq0i7IibihERELiIzWRMqiHg3mWnhz6lKqaEI4GZxyADAAUkGqnenMH4Bf43JwjfSZQ7PZPZcJI0BVxHOnDbSxm0p3OnSc6hwMWzDguKA5xuOUQOh4mQBlAgsDBgXIhfybAq6KV7ONL-PMBk4B8UodStllhVgDpZ2fH5g9PfIL6cu5OQ8bhPyPpLzMAh2IS9zu6MI8ay5JuOxxusZRhevcvlC4i6GPAcSvADpavzhWGZR2H4hyVpPcumOb2WP72GIOOg7XAw2ILPXXK6UGueXlKRtxqvxzr0P0DKqXu5Or2qaL2caMafZjVclCuiAwAmYQgSaZANvLYrZuGTu5O6EESWRCQ-g7ZoR2wyfMBVHxXo52BWp3F7a8RnaAwbaiHrUONzHLaYdEknah8AwFvczwTpuSBbh-qOo+yqagxt59uKw-zlQsycy8yargApCrchCsz5rX2TRDQrRxPJO9gyyUCCoPhQY1wNwiRoRkRAAyAirI3HoMoJDMZtQLxHh+BpNpbzF5x+gr1p2qZn2qbPZkop8EpaKORAnIFmnKYznOlllnlnqvJH0dY+kPJAA6A5A4k9cKkmkVkUYES4k+S5qfJHKfBEqZ6ZL46a6eL76Zd5CVOpjIzmlf8CDA1nylLwLH2GqtfqCEcypGBOjcOg64eAWAFKJWw2eHRnhrmb6Cpr24MFHmVyhp9R1JSo9i2nGi4fyG3DKJjKwCvmH7xrnEGrEDNZ2X+PlAVBIGFH0Fc72CAA\&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 live order board for my restaurant: a full-screen web page that shows open orders as cards in columns and moves them along as storekit tells it about status changes. Nobody interacts with the board; it just stays accurate. storekit sends the status changes as webhooks.
>
> 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 the current orders, and a front end designed for a TV.
>
> ```
>
> ```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 STATUS EVENTS
>
> Besides order.created.v2, storekit sends these events for the same order as it moves through the kitchen. order.preparing, order.ready_for_pickup, order.out_for_delivery, order.completed and order.canceled all have this smaller payload, with data.order.status set to the new status:
>
> {
>   "event": "order.preparing",
>   "data": {
>     "order": { "id": "ord_abc123", "code": "A1B2", "status": "preparing" },
>     "venue": { "id": 1234, "name": "My Restaurant", "slug": "my-restaurant" }
>   }
> }
>
> So the order id is data.id for the full payload and data.order.id for the smaller one. Write one function that returns the id and code from either shape. Treat canceled as "remove from board" and out_for_delivery as "Done". There is no accepted or rejected event: an order stays in New until its first status event arrives.
>
> Events can arrive out of order or twice. Store a rank per status (created 0, preparing 2, ready_for_pickup 3, out_for_delivery 4, completed 4, canceled 9) and never move a card to a lower rank than it already has.
>
> 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; update the board state afterwards. Ignore any svix-id already saved.
> 2. An orders table keyed by storekit order id with: code, status, rank, orderType, table name (or null), customer first name, items (name, quantity, modifiers names, notes), order notes, createdAt, deliveryTime, venue name, last updated. The full order.created.v2 payload fills or refreshes every field; small payloads update only status, rank and last updated. If a small payload arrives for an order the board has never seen, create a card with just the code and status so it is not lost.
> 3. GET /board/<BOARD_TOKEN> — the full-screen page, where BOARD_TOKEN is a long random secret from an environment variable. There is no login because it runs on a screen behind the counter, so the token in the URL is the only thing keeping strangers out: any request to /board or /api/board without the exact token gets 404 and nothing else, and the token must never appear in logs or error pages. Below I write /board for short; always include the token segment. The page must not include customer surname, phone, email or delivery address anywhere in the page or its data requests. Columns, left to right: New (created), Preparing, Ready (ready_for_pickup), Done (completed, out_for_delivery). Cards show: the order code very large, orderType and table name, the customer's first name, the item list as "2 × Margherita Pizza" with modifiers indented and notes in italics, and a timer showing minutes since createdAt. Cards are ordered oldest first inside each column. Cards in Done disappear DONE_MINUTES after they entered Done (default 10). Cards for canceled orders disappear immediately.
> 4. The page refreshes its data every 5 seconds without flicker (fetch JSON from GET /api/board/<BOARD_TOKEN> and re-render, or use server-sent events). If a refresh fails, keep showing the last data and show a small "reconnecting" label; never show a blank board.
> 5. Timer colours: default until WARN_MINUTES (default 10), amber until LATE_MINUTES (default 20), red after. For orders with a deliveryTime in the future, count down to deliveryTime instead and label it "for 11:00".
> 6. Design for a 1080p TV viewed from three metres: dark background, minimum 28px body text, order codes at least 96px, no hover-only information, no scrollbars — if a column overflows, shrink cards gracefully and show "+N more" at the bottom.
> 7. Filters via query string so I can point different screens at different views: ?types=Pickup,Delivery shows only those orderTypes; ?columns=Ready shows only that column with much bigger cards for a customer-facing "ready to collect" screen; ?venue=<slug> if the account has more than one venue.
> 8. GET /health that returns 200 and { "ok": true } and nothing else. Every other route must be either /board/<BOARD_TOKEN>, /api/board/<BOARD_TOKEN> or the webhook.
>
> MY BOARD
>
> - Timezone: TIMEZONE environment variable; show all times in it.
> - Show the item list on cards: yes.
> - Customer-facing variant I will run on a second screen: /board/<BOARD_TOKEN>?columns=Ready.
>
> DEFINITION OF DONE
>
> - [ ] A signed order.created.v2 creates a card in New within 5 seconds, showing the code, items and a running timer.
> - [ ] order.preparing, order.ready_for_pickup, order.completed for the same id move the card one column at a time, and it disappears DONE_MINUTES after completed.
> - [ ] Receiving order.preparing after order.ready_for_pickup leaves the card in Ready (it never goes backwards).
> - [ ] The same event delivered twice changes nothing the second time.
> - [ ] A bad signature returns 400 and the board does not change.
> - [ ] order.canceled removes the card immediately.
> - [ ] /board/<BOARD_TOKEN>?columns=Ready shows only Ready cards, large, with no item list.
> - [ ] /board and /api/board with a missing or wrong token return 404.
> - [ ] Neither the HTML nor the JSON contains an email address, phone number, surname or delivery address.
> - [ ] Turning the backend off and on loses no cards.
>
> WHAT TO GIVE ME WHEN YOU ARE DONE
>
> 1. The public webhook URL (…/webhooks/storekit) and the full /board URL including the token.
> 2. The environment variables to set (STOREKIT_WEBHOOK_SECRET, BOARD_TOKEN, TIMEZONE, optionally DONE_MINUTES, WARN_MINUTES, LATE_MINUTES) 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 open the board in full-screen mode on a TV browser.
> ```

## 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`, `order.preparing`, `order.ready_for_pickup`, `order.out_for_delivery`, `order.completed` e `order.canceled` per questo endpoint.

## Step 3: prova con un ordine reale

Apri l'URL del board (con il suo token) sullo schermo, poi effettua un ordine sul tuo storefront. La card appare in New; fai avanzare l'ordine attraverso i suoi stati nella dashboard (vedi [Gestire gli ordini live](/docs/it/guides/orders/managing-live-orders)) e osserva la card seguirlo. Cancella un ordine di prova per vederla scomparire.

L'accettazione di un ordine non invia un webhook, quindi la card resta in New finché la cucina non lo segna come preparing o ready.

## Idee

* **Suoni**: un chime quando una card entra in New, uno diverso quando entra in Ready.
* **Board per postazione**: tagga gli articoli per categoria (il builder può fare match sul nome dell'articolo o su `plu`) e mostra un board per postazione, come fa la [comanda cucina personalizzata](/docs/it/guides/build/recipes/custom-kitchen-ticket) su carta.
* **Alert per ordini in ritardo**: quando una card diventa rossa, invia un messaggio su Slack usando il pattern di [Alert ordini](/docs/it/guides/build/recipes/order-alerts).

## Cosa non fa

* **Non può modificare un ordine.** Il board è in sola lettura; accettare, segnare come ready e completare avvengono ancora nella dashboard o sulla cassa, che è a cosa serve il [Kitchen Display](/docs/it/guides/orders/kitchen-display) integrato.
* **Sa solo ciò che dicono gli eventi.** Non esiste un evento `order.accepted`, quindi una card resta in New finché la cucina non la segna come preparing o ready. Neanche un ordine rifiutato invia un evento; semplicemente non si muove. Se una card non si muove, controlla il registro di consegna webhook nel portale per vedere cosa è stato inviato.
* **L'URL è la chiave.** Chiunque abbia l'URL completo del board può vedere codici ordine live, nomi di battesimo e articoli, quindi trattalo come una password: non condividerlo fuori dal team e cambia BOARD\_TOKEN se uno schermo viene perso.
* **Parte vuoto.** Gli ordini effettuati prima che l'endpoint venisse collegato non appariranno.
* **È il tuo servizio.** Il supporto di storekit può confermare che gli eventi hanno raggiunto il tuo URL e il codice di risposta; il board è tuo.

## Correlati

> **[Eventi ordine](/docs/it/developers/webhooks/webhook-events#order-events)**
>
> Ogni evento del ciclo di vita dell'ordine e il suo payload.

> **[Kitchen Display](/docs/it/guides/orders/kitchen-display)**
>
> Lo schermo cucina bumpable integrato in storekit.

> **[Stati degli ordini](/docs/it/guides/orders/order-statuses)**
>
> Cosa significa ogni stato e come gli ordini si spostano tra di essi.

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


## Related topics

- [Costruisci i tuoi strumenti su storekit](/docs/it/guides/build/overview.md)
- [Gestione degli ordini in tempo reale](/docs/it/guides/orders/managing-live-orders.md)
- [Archiviazione degli ordini](/docs/it/guides/orders/archiving-orders.md)
- [Panoramica degli ordini](/docs/it/guides/orders/overview.md)
- [Abilitare il ritiro](/docs/it/enabling-pickup.md)


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