> ## 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 Order Board for the Pass

> A full-screen order board that shows every open ticket and moves it across New, Accepted, Preparing, Ready and Done as storekit order events arrive.

A wall screen for the pass, the bar or the front counter that shows open orders as cards and moves them along as their status changes in storekit. Big order codes, item lists, a timer that turns red when an order has waited too long, and your own choice of what to show. No one touches it: it follows the dashboard.

<Tip>
  storekit has a built-in [Kitchen Display](/docs/guides/orders/kitchen-display) that the kitchen can bump tickets on. Build this recipe when you want a read-only screen with a different layout — a customer-facing "ready" board, a counter view that only shows pickups, or a bar screen that only shows drinks.
</Tip>

## How It Works

1. storekit sends order lifecycle events to your app: `order.created` and `order.accepted` carry the full order; `order.preparing`, `order.ready_for_pickup` and `order.completed` carry just the id, code and new status.
2. Your app keeps one card per order and updates its column from each event.
3. A browser page refreshes itself every few seconds and shows the cards in columns.

## What You Need

* Webhooks enabled on your storekit plan (**Settings** → **Developers**).
* A [Lovable](https://lovable.dev) or [v0](https://v0.dev) account. Both need a backend for the webhook endpoint and a small database — the prompt asks the builder to deploy one and give you its URL. [Replit](https://replit.com) also works.
* A screen with a browser (a TV with a cheap stick, an old iPad or laptop).

## Step 1: Build the App

Paste the whole block into the builder in a single message. Adjust **MY BOARD** first if you want a customer-facing or drinks-only variant.

<div className="sk-build-btns">
  <a className="sk-build-btn sk-build-btn--lovable" href="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%20always%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.%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%20and%20deliveryAddress%20can%20be%20null.%20notes%20can%20be%20null%20or%20empty.%0A%0AExample%20order.created%20payload%3A%0A%0A%7B%0A%20%20%22event%22%3A%20%22order.created%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%22Pickup%22%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%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%20null%2C%0A%20%20%20%20%20%20%20%20%22modifiers%22%3A%20%5B%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%22table%22%3A%20%7B%0A%20%20%20%20%20%20%22id%22%3A%20%22tbl_123%22%2C%0A%20%20%20%20%20%20%22name%22%3A%20%22Table%205%22%2C%0A%20%20%20%20%20%20%22covers%22%3A%204%2C%0A%20%20%20%20%20%20%22posId%22%3A%20%22pos_tbl_5%22%2C%0A%20%20%20%20%20%20%22area%22%3A%20%7B%20%22id%22%3A%20%22area_1%22%2C%20%22name%22%3A%20%22Main%20Floor%22%2C%20%22posId%22%3A%20null%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%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%2C%20storekit%20sends%20these%20events%20for%20the%20same%20order%20as%20it%20moves%20through%20the%20kitchen.%20order.accepted%20has%20the%20same%20full%20payload%20as%20order.created.%20order.preparing%2C%20order.ready_for_pickup%20and%20order.completed%20have%20a%20smaller%20payload%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.%20Also%20accept%20order.rejected%2C%20order.canceled%20and%20order.out_for_delivery%3A%20read%20the%20id%20from%20whichever%20of%20data.id%20or%20data.order.id%20is%20present%2C%20and%20treat%20rejected%20and%20canceled%20as%20%22remove%20from%20board%22%2C%20out_for_delivery%20as%20%22Done%22.%0A%0AEvents%20can%20arrive%20out%20of%20order%20or%20twice.%20Store%20a%20rank%20per%20status%20(created%200%2C%20accepted%201%2C%20preparing%202%2C%20ready_for_pickup%203%2C%20out_for_delivery%204%2C%20completed%204%2C%20rejected%2Fcanceled%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%20modifiers%20names%2C%20notes)%2C%20order%20notes%2C%20createdAt%2C%20deliveryTime%2C%20venue%20name%2C%20last%20updated.%20Full%20payloads%20(created%2C%20accepted)%20fill%20or%20refresh%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%20Accepted%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%20rejected%20or%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%20creates%20a%20card%20in%20New%20within%205%20seconds%2C%20showing%20the%20code%2C%20items%20and%20a%20running%20timer.%0A-%20%5B%20%5D%20order.accepted%2C%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%20before%20order.accepted%20leaves%20the%20card%20in%20Preparing%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" target="_blank" rel="noopener noreferrer" aria-label="Build with Lovable"><img src="https://mintcdn.com/storekit/IGeB_84apyho3Z6U/images/logos/lovable.svg?fit=max&auto=format&n=IGeB_84apyho3Z6U&q=85&s=cc21d11769d5e6b686fed56390a88f5e" alt="" width="20" height="20" noZoom data-path="images/logos/lovable.svg" /> Build with Lovable</a>

  <a className="sk-build-btn sk-build-btn--replit" href="https://replit.com/?stack=Build&prompt=JIAg7ghgdgLiEgDYEsBuBTEB7ATgE3RxACMsJ8QAzXEAWwE8Qd0BnGCAVx2hgC54qHRIgC0LAMbN0UcOmIgADhADmmGAAsIcFuqxgW2BdOz5CBiAfHk8B5DPFZEHWlHNQ8dLBgMb0teIhYUMrwBmy46ADWyHAw6MK2cBCkHNrsMByWmsGsAHQgAHJYpHiMdnHc4jAGYDHqIL4kZPgA3CAxIABWmWkQ9Obi4lxa6PnhzNHa0jYN6phsWpkg4tmq5jVyuliRLLkAUHsAQhzIiB4dtRoCxBDikdOzWiCa5oocxCjiIAASACq-AAUAMogACqACUADJUGiNMCbLDbEAACgICkCZSS7ga8UQdDUczBUIAlAAaAQsWgQYQgPBaZIWTDUIiNIY4ZiwEwEHAscnQDwISg4IJwB4EFjIZRQdAeZkCX4ANX2ewAwgB5Aq-ACiAA1fiAAIKHNWg-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-g3anq-rIoehNx7GDiRLNwedNGWBOGUA8hgIhizsFLAqmjlkxkBlI2R8ibApAwARg87tIAT1ziKQ+8T3cM4wGRTRJTZFYpMQeZCdGQRNO-TYDOuFNEZoIwNCACzBpNOGNgLpB5oJrS2bDUoXBWb6NkS+mJGSnAWNwEhDASDKGtOInwHYEYm7eLkTzJ2DIpmQBIwRrkQJA7qMxaCJBeL9HVW5DBcOoSeHl2rvYINUTNKKNko+FNbtY66MPN+H0zASMx0OB0lF6ju6yJGYgw8ozU0YDVZa4J6B3zyOQZonJCANX2KevjQ8+TMhtGBFwLN7rYHev8CAzSfD0KV0CtNRkkZwnaHldRRJ1T0maK9r7SANUEAjYGgwGOi7NV1PkWW08ZFNHtP0F0-p1NNGjMwBM55rUCMQB9oNAUVrXLu5-Zok52HMSItxCi6RMisWYgcAS0llLyMkYcUCMEbHCXcsvQHeDcGhW9sfPw-hvYS9BA0hQCbcBkCmJGFrBmeg5yZiJKeOoGAMAFAsF4AAenF-BGA9baDi6ZuIFg8vKKBCMDycX8J1yIh2Brw8kQRB4xYAcX43wtRjV+AaX4oIQRagVFqTUQIDiHFYPZUyTyXmytls2Doc6Zi+Fvob7Kd943JiIPhDok9vCzGFBwM9ZlJgrGkPkd3txhYbNGgnLmq8RENT6Hz1+7uZUnOT0K3IjV0BKBqcock7voGlCmsyKa5cJUDML659uJy8I42dlSEaRAzlkDwJcn5dyNaAtL+XyvqYUWcXpGdwV3Ixv-Im+RIFILascVhZ5hFSK1uYKi91kB-VghkSEkR6QJH+AY8q1Rji9WaLeaY3x-ze+ONcfoDx3z-HT+7cKwzoEesoe7Q8CtI9IuQ9kQejQOejceeg+AyRMuQ7uEBv8hIlIe8L8Uc+QM0F6+ySYIiQsnYQYasQMGQOArgZkEB6YW+7MYa7UdQL8OgGK18BoiALAwEqeFecAte6Au0VQMoNepeiyws7cAohcpeeUMADeuAU0h2Wi-AdeFBsoHMKCMUcwHC4CCBEBNACBSBIB5ec6FMAyKmTwzAvBneVB0AwhHcBgZEzAkeTIyhyE+As2EhUhOAMhdKWENhuaraWyGsEyLoxkOMEh2AlAQBsItQwsmMcsAgLGRsauMMrsKIReo0MsicaeneCMZcR+VeIA4MlMFk9ejezebS4KNeqQbhHh9SWU6W0Yeyne6WphFCeA4uQh8Qo0TKLi2I0oHC9hAgVgFATYAggQ8IRAcRF86CUChRjALwyoM03wluIAFoIAhwoIwAkIKSBwyWr474+ouuWuR4UucsLYgAKAQgCXQhSNCqQaTBh+SkH6xfiNCRTRSxTxTJRpQZTkBYTYjjRWi2i-CzTzSLTLSrTrSbTwBax2AmyNDcBgBAwGQmyYRtCvQvRJJUDFpcDXxYw4yNCQKdw1RcAyDSztC0BZjNwjD7xtBVxcQEiYBOEeAuzRwzyECQD4C7AgDACILnzQALjOSUGIB16wL-z7Dgz5A4Kh4+BNZfzoD0CUILjHEdBPLAGOzqD8Bb6yywyUzQCRACGxLxL0xSl0Yog0DbaICxhDDhDhpUBkwmx0bmLrpux2kgCfqwDejkhoZXRmCmzxrlheqxhKlerkgpFyqGGyHmqWq2LEaYBOkZpwDUmyr5DaIzI8585uzBl8jpzp54BBzRSrJjHoBCisA3gZLWnxB4BtBoG5686D4GDxlxBJL7yJGZBalQBGzpixmVwKA0l4D5DABhE957wplwHkDWJR5yiTJKmND0l4QGA9EMEZw6zLDHLRxGRKRfjdDQmEjUFeTpBLBsGTGJJmyWwy57Dgr5AADiWoex9J4utExoBo4IKSU0Fo1o9uLEIAZxUBMyYg1Uxg+CtiYA56mA95j5z5y09u7QrwxOIQLGTM-gJM1UcAQotBkyHUZMQQPUcAfU1iTW+QS858h5wEgQkESyVUnAt8HQTo5BRcwYv5pFtcHgrIcOpcwYgBTY9wMgc4jQoEkFEUUAjZh0FU9wFeq4EmhUXpEhQCuC8J0k0JwE4u05NA4uGKyAClzQa5GgIRuJOygi7FxgqgOYr0T0AyystcIQ8QJMfIqshIelMgjCtpaCGKoCRAc4xFgYRAhAwo-eJU7JzuIxHJ4AOBIAal1gQeOguAMAbQ2EfQtgQsTgLUjQtlqMygmFeFhI-5xscAZsdg4g8VQ0oaVpLAhJ8aZcLatiRapwhCYZWEoy4ycY9AgFhACSsE6VJUhCMQBgRMMlMk7JM6TgLg5Y7cM8QETAkoQu-A-ccJyIwZsYBomZJyWSORXsPmMCKIgplRJRCgsYPhmA017eNU-B2AFRje1VxI+QKo1gYQugYA-ATxQqywWALUJZeYOAqguphAIq0cqshpJVZkFpTY4aAA5AYDGrab9Y0BYv4KzkkDYdTgAOtyanrnqehXq3r3oql2KemeJ2AECwAdzdHkKxXoJeiK5WUCgNARlEDhW1AVS0B2CpCmQShXxLmvIyjyrnWXXwDnxPKjSODihIU2lwBQmu7tTXgPX9VQAc1smtQ7W0gPhOUWREApIahahTQfTAAFCmhagggxwvy+DfR418IgCy2ogFmcCIBwDapnUgAXXS1Fg8HNGEJtEiESly0sAK3kAklklxRxD7z7BPRpViJtXCLFhzCJCdX0hrxZQowIXoxwyaWpBUCfD3BEDIiUA1R2y-j-jIX+CXl7EqUhX4C3kgVPkvlvkDLMCf7uAsU+K3wkw4A6RiDryG7W19mxEFmh3onnTkjCVDjU1HSEgdldVeTXUUi954i2FoxQDShVDT4FSBptBzlU2j0IAfDalNAoR7BIx4WU3i15Q8j8AECnRCBxmul4gzQPkFBq0a1a0gim3H0W1WYvSxgrzMJEBGKVWQiW6q3q2a3ah31H3m1wC0yxhG263PIgDaI0BPLx31AIDVUWqrxcWEgiL3FBlw60h6CwTAQIMRkwRsCFEDJ5iBqTFkRyiOqupkT7B9r5BpIShShB4IDapDovRDiKjnEmTwhKG0EaBSD4gqZi6gGGwkC3CRDKAx7uDul2CWrOB5FDoKDQyYQ4jqSGFKlb7mBwDtwWBwBMp9oKPkjtjPBeCEAiBjx2AFg3RBAGPAQSDCjCD1gGBnFdj9GODODxg6SUAjHlg6A1JGwDEzDiO3AFkzLfEMmj1kRtoFCeDMCn5PBTkdgA37ADqJmnAVAXRxTOnSRZQSaiXASgCLKKB-Scj2Lp0cjaB0UaNy1RRNW9ScOCMAD8nOrAAAvOKnknUmaguNdYGPxYwJpbfE8p9SwG0PUw4BLSwM0+JKtdTT0wJZOOLW4xjYwnbMQJKB4quSDTQAgP9WGiY6dLFBVJPatUMWM+3FUKfrYwuSM1Gc07ROxrHu+c440KnhgwnGfASBOUmFGfsEOheVecFU-BbfUMQV3ISQYMSemBjtsAutJEJCZR2GZe1KwdfNpFotgL4GMRIZgPZXAMsugPQUQIXS0XeWqA+aXeBQUCxOSMpR6ES8XaS6BWXZS4QnCHrsqB9AAJorEMubE9KIPoDXpRz8C-DAAfRagGoq1EKdQYXrzYUDTtwVkr00glxE29w9JAij0Q3rppRs72CXX8Cym7A9KlKWl7O3Crhys8ABWKxMDOhonOxT0Ml0X8B0sktktgWvmUujOuMDWTPTHKgpJajaIa12jAD-hqjaLG0q0HAXhbogDYaGi3FSi82CHLkeApGvD+OtSTUqlzgx2OvePXUD1DSPW2KQ3c7ALOhQBHSU2iRxsJsp7zWHXu6T7H7V6h65DrXFE5J5Idt1Ed6jQoHLxIMMLGN-WhVRwLMuDwBJAU1Zhk2TEcoe2eLK0FA-033-3wDMlED9sHU9k9L1s+bCxoAtwT5LUVTMLMj7Kl4cFZlIAWRR6sihVzgAjnshDIgdBL0gDKB5oGA3B3Csk2BnUHvxtLGoEh6QJhmjQwCRFDSrCmSmXFuowOCqwRl1ugeWY3AMl3GYkkFgvPRBLpjxOhVMwIcdjLDwfocNuCGWHtEeB2HGMThDTPukkyg+3xDdKxugeusl0etvnevjN+vTPdMNmMbTEbPkgvVvUY2GOQ06snlccJtEsDI0uqXTlgx0APhM0hA0BgBdQhBJWgtkEEcB0gcJv9wEtmR-AfTQjtgsiEhZ1RMofsBQkQJUiVVCbjKlWTtAa0Bv2OTFWrzaGeHwC1UBhUdLGElIf-scUhxRSt4yCWxkcbNzELH6jLHnnAB25yZm7zEQUcsmiGhWhRtrtbGB1vAfAxRrgbhEjQjIiABkBPsRuErtLl0YxSg8mcpzxTlfFUh7ZSKeV2hV1Jhecf1E1j4DYzVCiL8ZNACXNAtEtCtGtBtFeeSLx0y+SCK2KxK2uzXhsjvHvIwKu+u3-dreSBfeCFfb-bfeSF-dqNfad0CG1ygk1SNSTKOJYkQWOAYOIjAAWPsGeTbUEDGlSIQS1XExhKIw8AsLhG0sqkY1wK8HSKE5g2R9oO3BXubDBwud1WwEawHT8DuEMVgB7GZNOXONAT+VIHZaW-a0sQqCQMKPoIcnsEAA&referrer=docs.storekit.com" target="_blank" rel="noopener noreferrer" aria-label="Open in Replit">
    <img src="https://replit.com/badge?caption=Open%20in%20Replit" alt="Open in Replit" height="36" noZoom />
  </a>
</div>

<p className="sk-build-btns__note">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.</p>

<Accordion title="Full prompt (click to expand)">
  ```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 always has the shape { "event": "<event type>", "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 and deliveryAddress can be null. notes can be null or empty.

  Example order.created payload:

  {
    "event": "order.created",
    "data": {
      "id": "ord_abc123",
      "code": "A1B2",
      "asap": true,
      "total": 2500,
      "tip": 250,
      "deliveryFee": 299,
      "discountTotal": 0,
      "orderType": "Pickup",
      "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",
          "price": 1200,
          "quantity": 1,
          "plu": null,
          "posId": null,
          "taxRate": null,
          "modifiers": []
        }
      ],
      "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 }
        }
      },
      "table": {
        "id": "tbl_123",
        "name": "Table 5",
        "covers": 4,
        "posId": "pos_tbl_5",
        "area": { "id": "area_1", "name": "Main Floor", "posId": null }
      },
      "deliveryAddress": {
        "street1": "456 Oak Ave",
        "street2": "Flat 2",
        "city": "London",
        "postCode": "E1 6AN",
        "country": "UK",
        "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, storekit sends these events for the same order as it moves through the kitchen. order.accepted has the same full payload as order.created. order.preparing, order.ready_for_pickup and order.completed have a smaller payload:

  {
    "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. Also accept order.rejected, order.canceled and order.out_for_delivery: read the id from whichever of data.id or data.order.id is present, and treat rejected and canceled as "remove from board", out_for_delivery as "Done".

  Events can arrive out of order or twice. Store a rank per status (created 0, accepted 1, preparing 2, ready_for_pickup 3, out_for_delivery 4, completed 4, rejected/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. Full payloads (created, accepted) fill or refresh 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), Accepted, 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 rejected or 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 creates a card in New within 5 seconds, showing the code, items and a running timer.
  - [ ] order.accepted, 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 before order.accepted leaves the card in Preparing (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.
  ```
</Accordion>

## Step 2: Connect storekit

<Steps>
  <Step title="Open the webhooks portal">
    In the dashboard sidebar, go to **Settings** → **Developers** and click **Manage Webhooks** (it reads **Enable Webhooks** the first time). Webhooks are a subscription feature — if you see **Upgrade to enable webhooks**, [contact support](/docs/getting-started/contact-support) first.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>
</Steps>

Tick `order.created`, `order.accepted`, `order.preparing`, `order.ready_for_pickup`, `order.out_for_delivery`, `order.completed`, `order.rejected` and `order.canceled` for this endpoint.

## Step 3: Test With a Real Order

Open the board URL (with its token) on the screen, then place an order on your own storefront. The card appears in New; move the order through its statuses in the dashboard (see [Managing Live Orders](/docs/guides/orders/managing-live-orders)) and watch the card follow. Cancel a test order to see it disappear.

If your store auto-accepts orders, the card will skip straight to Accepted, which is correct.

## Ideas

* **Sounds**: a chime when a card enters New, a different one when it enters Ready.
* **Station boards**: tag items by category (the builder can match on item name or `plu`) and show one board per station, like the [custom kitchen ticket](/docs/guides/build/recipes/custom-kitchen-ticket) does on paper.
* **Late-order alert**: when a card turns red, post to Slack using the pattern from [Order Alerts](/docs/guides/build/recipes/order-alerts).

## What This Does Not Do

* **It cannot change an order.** The board is read-only; accepting, marking ready and completing still happen in the dashboard or your till, which is what the built-in [Kitchen Display](/docs/guides/orders/kitchen-display) is for.
* **It only knows what the events say.** `order.rejected`, `order.canceled` and `order.out_for_delivery` are listed in the reference without a sample payload, which is why the prompt asks the builder to accept either shape. If a card does not move on one of them, check the webhook delivery log in the portal to see what was sent.
* **The URL is the key.** Anyone with the full board URL can see live order codes, first names and items, so treat it like a password: do not share it outside the team, and change BOARD\_TOKEN if a screen is lost.
* **It starts empty.** Orders placed before the endpoint was connected will not appear.
* **It is your service.** storekit support can confirm the events reached your URL and the response code; the board is yours.

## Related

<CardGroup cols={2}>
  <Card title="Order Events" icon="code" href="/docs/developers/webhooks/webhook-events#order-events">
    Every order lifecycle event and payload.
  </Card>

  <Card title="Kitchen Display" icon="tv" href="/docs/guides/orders/kitchen-display">
    storekit's built-in bumpable kitchen screen.
  </Card>

  <Card title="Order Statuses" icon="list-check" href="/docs/guides/orders/order-statuses">
    What each status means and how orders move between them.
  </Card>

  <Card title="Writing a Prompt That Works" icon="wand-magic-sparkles" href="/docs/guides/build/prompting-guide">
    The structure behind this prompt, and what to say when the builder gets it wrong.
  </Card>
</CardGroup>


## Related topics

- [Build Your Own Tools on storekit](/docs/guides/build/overview.md)
- [Managing Live Orders](/docs/guides/orders/managing-live-orders.md)
- [Orders Overview](/docs/guides/orders/overview.md)
- [Kitchen Display](/docs/guides/orders/kitchen-display.md)
- [Connecting Toast](/docs/guides/integrations/pos/toast/connect.md)
