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

# Live-Bestell-Board für den Pass

> Vollbild-Bestellboard, das jeden offenen Bon zeigt und ihn zwischen Neu, In Zubereitung, Bereit und Fertig verschiebt, wenn storekit-Events eintreffen.

Ein Wand-Bildschirm für den Pass, die Bar oder die Theke, der offene Bestellungen als Karten zeigt und sie weiterbewegt, sobald sich ihr Status in storekit ändert. Große Bestellcodes, Artikellisten, ein Timer, der rot wird, wenn eine Bestellung zu lange gewartet hat, und Ihre eigene Auswahl, was angezeigt wird. Niemand fasst es an: Es folgt dem Dashboard.

> [!TIP]
>
> storekit hat ein eingebautes [Kitchen Display](/docs/de/guides/orders/kitchen-display), auf dem die Küche Bons wegbumpen kann. Bauen Sie dieses Rezept, wenn Sie einen schreibgeschützten Bildschirm mit einem anderen Layout wollen – ein kundenseitiges „Bereit"-Board, eine Thekenansicht, die nur Abholungen zeigt, oder ein Bar-Bildschirm, der nur Getränke zeigt.

## So funktioniert es

1. storekit sendet Bestell-Lebenszyklus-Events an Ihre App: `order.created.v2` bringt die vollständige Bestellung; `order.preparing`, `order.ready_for_pickup`, `order.out_for_delivery`, `order.completed` und `order.canceled` bringen nur ID, Code und neuen Status.
2. Ihre App hält pro Bestellung eine Karte und aktualisiert deren Spalte aus jedem Event.
3. Eine Browser-Seite aktualisiert sich alle paar Sekunden und zeigt die Karten in Spalten.

## Was Sie brauchen

* Webhooks in Ihrem storekit-Plan aktiviert (**Settings** → **Developers**).
* Ein [Lovable](https://lovable.dev)- oder [v0](https://v0.dev)-Konto. Beide brauchen ein Backend für den Webhook-Endpoint und eine kleine Datenbank – der Prompt bittet den Builder, eines zu deployen und Ihnen die URL zu geben. [Replit](https://replit.com) funktioniert ebenfalls.
* Einen Bildschirm mit Browser (einen TV mit einem günstigen Stick, ein altes iPad oder Laptop).

## Schritt 1: Die App bauen

Fügen Sie den gesamten Block in einer einzigen Nachricht in den Builder ein. Passen Sie zuerst **MY BOARD** an, wenn Sie eine kundenseitige oder nur-Getränke-Variante möchten.

[![](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.

> **Vollständiger Prompt (zum Ausklappen klicken)**
>
> ```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.
> ```

## Schritt 2: storekit verbinden

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

Haken Sie für diesen Endpoint `order.created.v2`, `order.preparing`, `order.ready_for_pickup`, `order.out_for_delivery`, `order.completed` und `order.canceled` an.

## Schritt 3: Mit einer echten Bestellung testen

Öffnen Sie die Board-URL (mit ihrem Token) auf dem Bildschirm und geben Sie dann eine Bestellung in Ihrem eigenen Storefront auf. Die Karte erscheint in Neu; bewegen Sie die Bestellung durch ihre Status im Dashboard (siehe [Live-Bestellungen verwalten](/docs/de/guides/orders/managing-live-orders)) und beobachten Sie, wie die Karte folgt. Stornieren Sie eine Testbestellung, um zu sehen, wie sie verschwindet.

Das Annehmen einer Bestellung sendet keinen Webhook, daher bleibt die Karte in Neu, bis die Küche sie als „preparing" oder „ready" markiert.

## Ideen

* **Sounds**: ein Gong, wenn eine Karte in Neu erscheint, ein anderer, wenn sie in Bereit landet.
* **Stationen-Boards**: Taggen Sie Artikel nach Kategorie (der Builder kann anhand des Artikelnamens oder `plu` matchen) und zeigen Sie ein Board pro Station, so wie es der [individuelle Küchen-Bon](/docs/de/guides/build/recipes/custom-kitchen-ticket) auf Papier tut.
* **Späte-Bestellung-Alert**: Wenn eine Karte rot wird, posten Sie in Slack mit dem Muster aus [Order Alerts](/docs/de/guides/build/recipes/order-alerts).

## Was dieses Rezept nicht tut

* **Es kann keine Bestellung ändern.** Das Board ist schreibgeschützt; Annehmen, Als-bereit-markieren und Abschließen passieren weiterhin im Dashboard oder an Ihrer Kasse – dafür gibt es das eingebaute [Kitchen Display](/docs/de/guides/orders/kitchen-display).
* **Es weiß nur, was die Events sagen.** Es gibt kein `order.accepted`-Event, daher steht eine Karte in Neu, bis die Küche sie als „preparing" oder „ready" markiert. Eine abgelehnte Bestellung sendet ebenfalls kein Event; sie bewegt sich einfach nie. Bewegt sich eine Karte nicht, prüfen Sie das Webhook-Zustell-Log im Portal, um zu sehen, was gesendet wurde.
* **Die URL ist der Schlüssel.** Jeder mit der vollständigen Board-URL kann Live-Bestellcodes, Vornamen und Artikel sehen, behandeln Sie sie also wie ein Passwort: teilen Sie sie nicht außerhalb des Teams und ändern Sie BOARD\_TOKEN, wenn ein Bildschirm verloren geht.
* **Es startet leer.** Bestellungen, die vor der Verbindung des Endpoints aufgegeben wurden, erscheinen nicht.
* **Es ist Ihr Service.** Der storekit-Support kann bestätigen, dass die Events Ihre URL erreicht haben und mit welchem Antwortcode; das Board gehört Ihnen.

## Verwandt

> **[Order-Events](/docs/de/developers/webhooks/webhook-events#order-events)**
>
> Jedes Bestell-Lebenszyklus-Event und dessen Payload.

> **[Kitchen Display](/docs/de/guides/orders/kitchen-display)**
>
> storekits eingebauter, bumpbarer Küchenbildschirm.

> **[Bestellstatus](/docs/de/guides/orders/order-statuses)**
>
> Was jeder Status bedeutet und wie sich Bestellungen zwischen ihnen bewegen.

> **[Einen Prompt schreiben, der funktioniert](/docs/de/guides/build/prompting-guide)**
>
> Die Struktur hinter diesem Prompt und was zu sagen ist, wenn der Builder es falsch macht.


## Related topics

- [Eigene Tools auf storekit bauen](/docs/de/guides/build/overview.md)
- [Live-Bestellungen verwalten](/docs/de/guides/orders/managing-live-orders.md)
- [Bestellstatus](/docs/de/guides/orders/order-statuses.md)
- [Übersicht der Bestell-Agenten](/docs/de/developers/agents/ordering/overview.md)
- [storekit-Dokumentation: Online-Bestellung, Guides und APIs](/docs/de/index.md)


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