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

# Uitverkocht-log en ochtenddigest

> Elk uitverkocht item op storekit loggen met reden en bron uit item.out_of_stock, de laatste 30 dagen ranken en elke ochtend een Slack-digest sturen.

Elke keer dat een gerecht uitverkocht raakt — gesnoozed door het team, uitverkocht via voorraad of uitgeschakeld door je kassa — stuurt storekit een event. Dit recept slaat ze op, laat je patronen zien (welke gerechten, welke dagen, welk tijdstip) en post elke ochtend een digest naar Slack, zodat de inkoper en de chef-kok de dag beginnen met de wetenschap wat er op is.

> [!TIP]
>
> Het dashboard heeft al een snooze-rapport onder **Reports** (zie [Snooze-rapportage](/docs/nl/guides/menu/availability-snoozing#snooze-rapportage)). Bouw dit recept wanneer je ook voorraaduitverkopen en kassa-gedreven wijzigingen in dezelfde lijst wilt, of de digest gepusht wil krijgen naar Slack in plaats van hem op te zoeken.

## Hoe het werkt

1. storekit stuurt `item.out_of_stock` naar je app zodra een item onbeschikbaar wordt.
2. Je app registreert het item, het tijdstip, de reden en wat het veroorzaakte.
3. Een geplande taak draait elke ochtend op een door jou gekozen tijdstip en post de lijst van gisteren, plus een rollende "meest uitverkocht deze maand"-tabel, naar Slack.

## Wat je nodig hebt

* Webhooks ingeschakeld op je storekit-abonnement (**Settings** → **Developers**).
* Een [Replit](https://replit.com)-account. Dit recept heeft een publieke URL nodig die online blijft, een database en een scheduler voor de ochtendtaak — allemaal biedt Replit op één plek.
* Een Slack incoming webhook-URL voor het kanaal dat de digest moet ontvangen.

## Stap 1: bouw de app

Plak het hele blok in de builder in één bericht.

[![Open in Replit](https://replit.com/badge?caption=Open%20in%20Replit)](https://replit.com/?stack=Build\&prompt=JIAg7ghgdgLiEgM4FsIBs3gKYCN4Ad8QYALCOAayy30XhDQHsBzERgMxCwDcsAnAJ4hkWKAFcQASxhZkxMnGaMsdRmLgckMRgGMK8OMiF8VMCGL7QYAGnhQAJklH26CRCUZ849yc1PFGEABlNAg9Ll5BYU8oSShmADotTywKaWIsDDpSLAIiCBw1OERtPQBaIrocITBcD0YKJIAVElyIQmExEpAoHn4GRkQ2qAjRGx6+vhAdNVh5XMQIEVG5mDBJHSxbaEdeyOEIKmSTNLhIaQSAKEuAITFJNEd09dJ6e3ICiCGkQJyB1kQFm4kl4dBMJQgXkQ2xG6EgAkQFRG+DEODQGxAAAkmk0AApBEAAVQASgAZGGONw6Vr2MRoLCOABWjDw7E88xAPj8JSulwAwgB5AByTQAogANJogACCNwFhKlQSaAuJooA0sAmtdQHwxLCQB5EPhpOhpEIcF04ipVCMSilTiAABR2k4XGbIACUMLYUHRvTYfHs-DirB2IHwEAEIlgdHwoRgbL4ckTIHBZgsVmh0wg7AAl64HCAcJDEEkXal0jpoD1GDBJOwhEY2GBYR0CkV5CHsgoDe18KIpCMm+Wi0Ihg4Q9gcPUKKXrpjGGBjhWznVGA06GBPBQAFyXMogUVhEgrOCSAtYnG4kC4gVK8DSE8IABSQWFRcY9iE2noJNJIB1LBmHPGQpjiDlywdd53EKSF7CuA8WlyQov17bsFjIfsQAAbxAAAiPpYDwnd8IAHkIuAYAEfsAD48NsPD3jMYicJABJ2JAABfLjmi3LgAA9NnwOtGCgRASL+elmDCIRPCDPgEh0ExyAZU8nXsQIoFrEAulyaQAG4dO+OT+EU5SZHg7gACYPScBx0KLSFchMqYWUZLAdHGMM-hchITHYPV4KUrAVMcAB6AN5L8rAAocBJAR0TYGVUiLfP8wKEnYCAHlUijY3USL+FsHQum0EQ+FsXhxGGRx0sLXp+MowIKMHEoQscTQ4kQSQg05D4EJAYksAARzEUxXBMJBfF6RwXhPIJgX4pJRUiYwRrG7oqz4PhJBUDlWggeS6EQRayh62wTskfiyjrEQIWQfJC0u67uuYKByAsLAkgANWDBt5jkOaOQ4dgNkkdAQAAA2eyGGEkHBLCiFMBDUKZQniMQID8WxLXieghmCuBQHWDBwz4RhgV68Dq1EYFyagaM4G4SFwbRXIqwwVSlRVdVNQAfQAdVFG5MQFAU1T5oJRT5VUmiSIb3M8uwBFISdSHIEAsoeOhInrDZyEkUSH1ebE8RAAAWAAGS2BoAWSEZx8EYOJDFK1MVCdwsgYQKz+P4rQPs3R9wIARgAVicGZ7KSIIIF4DkWp-P4mM+b5Qb4EpbHBT3HCs63bByEYNI5Lc+H0dhybkP5Fl4RwZnwAQBoFKBNgA3t4+z0Sg1z-PlwdEnMC04pnHkDWWqx7KoAu35WnAbdOm6Iei1yJgShIkcQupNTvYDmAuidfsJ3iWwNN6WwtfpexbLDUS0EbSF9HSU+2nYUCS-nshXE8zGMDHMREuoN3JIzcA5eDEI9Dq+pbpFXDBsfQ4DlaqzxiUB4mBD4+DxuyC+qkwwmBgFEC4IAhSTE5DPXIpd9C3yEOBEQyBPBCBzG-TuR9Ej7hAEhJASxcgtSrCMXQVZuqiXQHfZenJMggn4KpOhk11Z8Jbl9Ik3xq6nR6gadq-Qvgcj1JIUauQqBCBTNXOOuUqowBIggEw-YNaaBpqY+AaBlKoRrqpc8Ug3opHsLYMACgSHSGOmYPec4DzSigEICMfgAxcAcE7F2ZNaweQsqOegEZECIFLo4ZAbscALH4LXNg+xTb4h9HfQyJgfAmCVuydK3w4yT0vHiO2oksAGN2o8OgjptBmDQAXSQ+AT7iNWgAMWoCfc8Mw9QwCaLWdAthpCyDJhsLY0QfCg36PgHamxr6TRdkBfgdAaFxHZNomA4kQBWTDtbYQIUxIgAAMXnISNbAaLkmjUT0jaZynAAAiAz+ACFsLiOB4DbDACgEEbQJhbB8gsDgbqQYoUqR2vEH56JVoItAiGQFegEHshuKgiMjc2FmDZlIG0Ij1kqDGJrdkcQygjhcogQyQZUV-OlPYew4ICyOGNHoQk+AmiSGWFQ6lUxmUSKiAypIAtWgjByEIYuS8+wiL+Po0lbBkDSAstPYg5l6AatSZOVVRjliaPEBgJIQ89phjmcgRAABtAAugkS12YRjZJ6HSTA7JZDCUbtMUqjByqKUDRGUJQouF2DrgGoNzMYBCjEMgbJUw+whVcr6GoMqkDgLjLteC1xRT8SWHGZygZTLBVCgkay4ZIxMEOnuS42FLggHwhRFieFfLlospWqy9Em34RTixRtzbm14R6m2uSfMCg6BDlZAAzL24d+EZhBjbdKEONwe3WD7SOr47QWL4LGluxdeFOnoBYuc-O278J1nwOei5R7h2MV+YIYZWBz0AE530PpHT4RA4zYBTK6SxS2378IvLeW2lF4qBALsfTyigfKBUiDbXnKy5syiWxDmUcOTQQ6Wx3ObMOO5rYAC1YMjupNAXoaA21CxuOR-CTt42Jv4CxM13Sr14U7QyaUMAUOWzQxhrDOG8M7lnfh0jDGn0ssEEht9JE8KofQ5h7DYdcMh2IxJy2ZHQN4UtYgNtxJJwaU8NkjAUmSp2nKoOq9I704lHDchhTz5GAkCgAxkdoQHNcMg8oDzLbUAPDbcyNzAABLAhaHr0mDcgfzeF8AeF6G2gA1Obc2M7Z2EYAGwAHYAAc764uoDLlgOs8Q+SiXHHxiSuosBXs4rpm1BmSJ2tszhNrI73pOfwrbSEzBWg7TMDeSQAAvEbEB-MjvWS7Rz8met9YGyaSbjGNlzZnZexdx7RpWDNCxEOoHj1xjEGxz1B24ODGAPYE7GAzsjrMPxYkKlz0gY6-hS112OObcfXQlZu0M4sVa19xduE9M+YUwW-BCBqTUCGPRFbM2wf4T5K0SlcP4urb2-e-C23YC7ZIvtxjaBjskXYwxJ2iBLsfYYvdx7MhntcVew6trnEr0Ot01VMaNmvujqu-jud5szug+63he2g1TDmEsERQXiAifMDbUYMoaYJdWDi4dDl1oudA7wiUEwpWQ5toyyAXr4FwXLe1-g6gMAe0KbNzoPH+FSRd1Emb8nMAKsroUwLEO0oQDe+lLb2Y+CYMKcJGqAPD1oACFm220XQ0IQZjmKSGAV3btLvXIGOIKlmusTwvGaQYgPcgDDiHBIFycsC-wkweI+fC8YYSDO-LDOvss8XQ1zjYrVpsvV6kzXx6deW-1wp7LIABSHBlLwOL-fSvW-woM+MZy4t26om2x3DhneC9d+7ubeFRQhxAFl6UQpF+B8EG20PcX9NU7a1x9PGCs+DsrwbPehfi+l-DmHBiVfgLP7m3Xy2OWrIrIm9h0W8GcWdLgOEApSZ0RuhNBE43kuVq0BBa0XA1UNYSAYAYBaAdwwowpII3RA0woNIdBEAiC+gmB+wM4wpahpx1xZxqC1wGgyg8prgmhMRRRDxvpRQRR2FMRgACRpRcRrxCQpYggSIbUEgig+YOA+Y7Q9BtR3EZFZ4XIBIi16R4BCheBDJVZXAOhhUtorVCgCoJCpCZC5CKAvESANgTwmANw4YjgdD60h0W1TE20TD1BpD2BZDSgKBYNGIPhe98IOc5sQcx0+dMsGIutt9Y9xcE8+MuJGsZBYsSJQjeci9cs8tIjEcRcFtgwhtAUxsJsycic21cRSRCQMNMM0dydKcFNyc+YbU+ZzZN18JEAKBid8Igg1QKjbZpRiQABxSo-XBIzjZSRAZ3BTRALSRgEbBkKTcYiwTYeXaAH+KTIMMwbWB-bXaY2Y0UBwfjQTFTETPLTTTTMjYAlncAg8MYo2VxJpNgdgdeHY1SDpH1TwFmERKw9lAcaoAOdgdgL0QcUxehPmIMYtRJZ0RgR4NgAqUgcmMQfrIEsYehaYQPRAQE39AoS+J0NJaQaHDqf4j0AaBYvgVuO4-0DgEiVAcQCGSEkQe48CZOL4EgWCQMQElQx0KHaNfoFQ3SRwSSL4DQXoDE59BJWwdEfrE5fsBkWwEbIRbpcMQYWQgQFuA+LoGkTWSuegOsUmGlWAICSwESKAIkthdY7KNAUsKY9cXYwsck8lcEKlFMG420Z4ykQsXhURUnK5aAScK0mYlxBwGKOIOZO+AaI7WwGot0xwNoiQD091djAaJCbZOgLSfCYscIcCcwvCU8ZoWePsd2GYQMTcTNJBZgTcKlIoQySsKjbSCgLSJcbxAcOVbMZYdMxoa4AWTEaUKUZUEAG4QkYAUkL5a4EvG8O8KUBg2gjcPAiFFcEAQAFAIQBdZ-o-gForopo3oPpJogYfJ-iwYIZno4YEZIQGFCxuZVQNQmhBZhZRZxZJZpZZZ4BpIupKJZ5LAlwTBdFugUIBBDIrZLYfRNZzTPoY5jEE47FcFSsLARg84ALBURAfAVJQyAJFDhgxwVFKQHF2oxxjF4IsQdh1D3CYBPDvDdAKBDJnFI14A9B6zL4IlI82Acgph4CsILRvBNJawrC8YgYLhLgrIkgfcmBWBiV1C5oSIKksAJF+TBVchnRZyiQmg+RRkjRQhqERgmhgBbZRQSNhRRRATgieguFZkkjDKRBjL5lzpwwicLp2is4Qpxip4fhFilk-SbS8KhpCz+TZ4KIABybIGS+AByaBEuRg-QSEHaWuK4WdJIfo0UCchcuJGQTyVSX4wpRybqHQeAdQE8IGaUL5W2YAIUPmXEaUIIIIAWFUL5XM3XTseIG0H0XIcJLAPcYdCAJIPCAATVMH4HeFPP5M-EjBYgQBgI0E4HMIqHUGOjiFbmrjMC8AeJAAEG6sDEjEHHYU0u0t0tsF6FqG6Hs3GHcEXDVhkvMuQDsq+CNjDBJLJORFCHAnSXaTwiCFdKSQhH+J0lx0wBDhOOtjRyCChI6lhJIHhMRLiGBKiEYQ0T4VLT4D+peHxIeM4ArkDRABI3lLwhNOHRwHattkGGKABphPGC8zgHEz6gRBYia1TGgCoEcF+PEBY1cjGp8ImpOS8UfA5H-TgG8lnjoU2kDToRGA8AsAWt6qkDgEwkPjnGHR0CSEGQeFAjoBTAMsdHrDbjIHjmkVyFkQasBOdKooQCYlyEl2xn1pAC+UXF9EYEOhAD5CCG+iLHUG0FlR7AiydihHAB8X2FcVBjQFAlUh3NnhmCJ2QBuWRrkBiTmH4suHNgEr6geHlV8H8Fd1Uh-BCDCH0GBAQCCFJGlD5Aljo1vIlj-AMDNuAFiqVD5g0q0qdExExB3FtltjWqrs2qFFFH6SyjpDgH-zE0tiJJttEhkFgFmRGDTvCGQDLnsBbBaubQACp-roSOwlq2oVqhBFzSIDKoiaJbBSJDaaIZ7t1m4V4rRwx+gbVh7iAAqXIFMQ5zYdw85m1es+B+s8iEACjxsErxiF6CoVaoBwaBAPRsz2Q8JvriMI5ggQo+yvg6BFzXKUqxwzB3qJkHgzkNNfqYr4SiBfiDLVamL3loglDqwmkrhh0kJ9Q0Rqa4Z-Qww8IZ7cbuhP7AbXzXEBbSAZ7sy2QMBFw4GORtAiBQZ45KagZOapbm1gBOAh4uKAQCbF7lreqIy8b8IhROLfTpGCol7QJeqEhsyYGdS0E8btVQA6zFwOR8zXFTReBiHm1cQFHk5E7YD5ET7RVVrCIpBOA-h8ylcoRxKPI5IORDaFqBTuguR-AqsqK2jelXGxa0J7FHFzRqBbRHT2R1ZvAVIrgw5Y6nqR5gnF5Fxsy2KnbAK-gmqRUMgUFj4PbrDFSSgHJsm4BkZZHVqTBpJAx6RUkFrGymKonIBXAsLDoxwxgrgssYq4qQAwoDpfaTxkn3Y94+AblYKqKQcGh91asuIqKJHJxMghheRCRvhm6dLW6SnJh5VVqjCHATyqLf1aklrpKRAkhzaaxFANpXAxEO7fbxDOA9ndK1U9QhhxhqktbAgIR5qwwhL6AdB6RIQrlUksYvprgvlRRBlCrNRgB3wBRBkzbdLrgDw7UQAHUZQNyZoxbZBJCPCzCfC1IU0Sw1rJIWBjYuL8YfHCxubuFolnY5g8FoLVJYKBocW8WOFFhlgWoO9JF+T1hW5uMPlUxFweXcX8XixozpotyjaoLZm6B-yqKhKUzlH4gZW+XvLIti0kCUCNCKYMJFxXA6Acin7Ft8jRt36YGXrfi3rOAkGvqfrLY8JdX2FZ5amqmTkS6vky7RQK7m61ntIJ5GSew5HBxwWC9JxIbk13YgWYAvXMnCxfX6zszXdshAhR7H5kAELwYZBQy2FeXvXchbb7aNIWxjXGBJa1q3AKVDp3BLc6WGqpWlxKCKXCw-gg6E0bkRqGQvW485qythK8yOhV49p1mdWOyuyeyBQQB+jgAuCjcODOzuCQAOr5QZRVQMXW6RzczGrUR0RMqaCZwiQyQnRAAyAknJnFIPwJgGvh7dnmKb-CuH4vLaiTplEkZiXJZixL2h-F+adHPN5ivILrFglilhljitsDyoKqKpKrKoquJC+VsGztzvzpvKg75j-FsE+dbtsEDfLqvObufdmgGwBacFfPmSNh0KsvIETGQCiqSAqygHTlQCNNHlo7yADgRB0iIDQwNFRmedFu5o1mrnxLpFUmZDwF1BuUbJGC0h-OiaKZhbYEPiuCAA\&referrer=docs.storekit.com)

[![](https://mintcdn.com/storekit/IGeB_84apyho3Z6U/images/logos/lovable.svg?fit=max\&auto=format\&n=IGeB_84apyho3Z6U\&q=85\&s=cc21d11769d5e6b686fed56390a88f5e) Build with Lovable](https://lovable.dev/#prompt=I%20want%20a%20small%20web%20app%20that%20keeps%20a%20log%20of%20every%20menu%20item%20that%20goes%20out%20of%20stock%20at%20my%20restaurant%2C%20and%20sends%20a%20short%20digest%20to%20Slack%20every%20morning.%20storekit%20tells%20the%20app%20about%20stock-outs%20by%20webhook.%20The%20app%20must%20never%20lose%20an%20event%2C%20never%20count%20the%20same%20event%20twice%2C%20and%20never%20make%20storekit%20wait.%0A%0ABuild%20it%20with%20a%20database%20so%20the%20log%20survives%20restarts%2C%20an%20always-on%20public%20HTTPS%20URL%2C%20and%20a%20scheduled%20job%20for%20the%20digest.%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%20EVENT%20THIS%20APP%20USES%3A%20item.out_of_stock%0A%0AIgnore%20the%20order%20example%20above%3B%20this%20app%20only%20cares%20about%20item.out_of_stock%2C%20which%20looks%20like%20this%3A%0A%0A%7B%0A%20%20%22event%22%3A%20%22item.out_of_stock%22%2C%0A%20%20%22data%22%3A%20%7B%0A%20%20%20%20%22venue%22%3A%20%7B%20%22id%22%3A%201234%2C%20%22name%22%3A%20%22My%20Restaurant%22%20%7D%2C%0A%20%20%20%20%22item%22%3A%20%7B%20%22id%22%3A%205678%2C%20%22name%22%3A%20%22Margherita%20Pizza%22%2C%20%22plu%22%3A%20%22PLU-001%22%2C%20%22posId%22%3A%20%22pos_item_42%22%2C%20%22sku%22%3A%20%22SKU-MARG-001%22%20%7D%2C%0A%20%20%20%20%22reason%22%3A%20%22snoozed%22%2C%0A%20%20%20%20%22source%22%3A%20%22manual%22%2C%0A%20%20%20%20%22details%22%3A%20%7B%20%22snoozeEnd%22%3A%20%222024-01-15T18%3A00%3A00Z%22%20%7D%0A%20%20%7D%0A%7D%0A%0A-%20reason%20is%20one%20of%3A%20snoozed%20\(temporarily%20hidden%20by%20staff\)%2C%20inventory_depleted%20\(sold%20out%20through%20inventory%20counts\)%2C%20disabled%20\(switched%20off\).%0A-%20source%20is%20one%20of%3A%20manual%20\(someone%20in%20the%20dashboard\)%2C%20order%20\(a%20customer%20order%20used%20the%20last%20one\)%2C%20deliverect%2C%20lightspeed%2C%20zonal%2C%20pos_sync%20\(pushed%20from%20a%20till%20or%20integration\).%0A-%20details.snoozeEnd%20is%20only%20present%20for%20reason%20snoozed%20and%20can%20be%20null%2C%20meaning%20snoozed%20indefinitely.%0A-%20plu%2C%20posId%20and%20sku%20can%20be%20null.%0A-%20There%20is%20no%20%22back%20in%20stock%22%20event.%20The%20app%20records%20when%20things%20went%20out%3B%20it%20cannot%20know%20when%20they%20came%20back.%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.%20Ignore%20any%20svix-id%20already%20saved.%20Handle%20item.out_of_stock%3B%20save%20and%20acknowledge%20any%20other%20event%20type%20but%20do%20nothing%20with%20it.%0A2.%20A%20log%20table%20with%3A%20received%20time%20\(store%20UTC%2C%20display%20in%20TIMEZONE\)%2C%20venue%20name%2C%20item%20name%2C%20item%20id%2C%20plu%2C%20sku%2C%20reason%2C%20source%2C%20snoozeEnd.%20Record%20the%20event's%20time%20as%20the%20time%20the%20webhook%20arrived.%0A3.%20GET%20%2F%20%E2%80%94%20protected%20by%20HTTP%20basic%20auth%20with%20ADMIN_PASSWORD.%20Three%20things%20on%20one%20page%3A%0A%20%20%20a.%20%22Yesterday%20and%20today%22%3A%20a%20list%20of%20stock-outs%20since%20the%20start%20of%20yesterday%20in%20TIMEZONE%2C%20newest%20first%2C%20showing%20time%2C%20item%2C%20reason%20and%20source%20in%20plain%20words%20\(%22Snoozed%20by%20staff%20until%2018%3A00%22%2C%20%22Sold%20out%20through%20inventory%20after%20an%20order%22%2C%20%22Switched%20off%20from%20Zonal%22\).%0A%20%20%20b.%20%22Most%20sold%20out%2C%20last%2030%20days%22%3A%20items%20ranked%20by%20number%20of%20stock-outs%2C%20with%20the%20count%20and%20the%20most%20common%20hour%20of%20day%20it%20happens.%0A%20%20%20c.%20Filters%20for%20venue%20\(if%20I%20have%20more%20than%20one\)%2C%20reason%20and%20a%20date%20range%2C%20and%20a%20Download%20CSV%20button%20that%20exports%20whatever%20is%20filtered%20with%20the%20columns%20from%20point%202.%0A4.%20A%20daily%20digest%20posted%20to%20Slack%20via%20SLACK_WEBHOOK_URL%20at%20DIGEST_TIME%20\(HH%3AMM%20in%20TIMEZONE%2C%20default%2007%3A30\).%20Content%2C%20in%20Slack%20mrkdwn%3A%0A%20%20%20*Sold%20out%20yesterday%20%E2%80%94%20%3Cvenue%20name%3E%2C%20%3Cdate%3E*%0A%20%20%20One%20line%20per%20item%2C%20in%20time%20order%3A%20%2214%3A20%20%20Margherita%20Pizza%20%E2%80%94%20sold%20out%20\(inventory\)%22%20or%20%2218%3A05%20%20Sea%20Bass%20%E2%80%94%20snoozed%20by%20staff%20until%2021%3A00%22.%20Group%20by%20venue%20if%20there%20is%20more%20than%20one.%0A%20%20%20Then%20a%20blank%20line%20and%20%22*Most%20sold%20out%20this%20month*%22%20followed%20by%20the%20top%20five%20items%20with%20counts.%0A%20%20%20If%20nothing%20sold%20out%20yesterday%2C%20post%20%22Nothing%20sold%20out%20yesterday.%22%20%E2%80%94%20still%20post%2C%20so%20I%20know%20the%20app%20is%20alive.%0A%20%20%20Post%20the%20digest%20once%20per%20day%20even%20if%20the%20app%20restarts%3A%20record%20the%20date%20of%20the%20last%20digest%20sent%20and%20skip%20if%20it%20has%20already%20been%20sent%20for%20that%20date.%0A5.%20A%20%22Send%20digest%20now%22%20button%20on%20the%20page%20for%20testing%2C%20which%20posts%20the%20digest%20for%20yesterday%20regardless%20of%20whether%20it%20was%20already%20sent.%0A6.%20GET%20%2Fhealth%20that%20returns%20200%20and%20%7B%20%22ok%22%3A%20true%20%7D%20and%20nothing%20else.%0A%0AUse%20TIMEZONE%20for%20every%20day%20boundary%20and%20displayed%20time.%20Do%20not%20guess%20a%20default%3A%20if%20TIMEZONE%20is%20unset%2C%20refuse%20to%20start%20and%20log%20a%20clear%20message.%0A%0ADEFINITION%20OF%20DONE%0A%0A-%20%5B%20%5D%20A%20signed%20item.out_of_stock%20event%20appears%20in%20the%20log%20within%20a%20second%20and%20the%20endpoint%20returned%20200.%0A-%20%5B%20%5D%20The%20same%20event%20delivered%20twice%20creates%20one%20row.%0A-%20%5B%20%5D%20A%20bad%20signature%20returns%20400%20and%20logs%20nothing.%0A-%20%5B%20%5D%20The%20example%20payload%20above%20shows%20as%20%22Margherita%20Pizza%20%E2%80%94%20snoozed%20by%20staff%20until%2018%3A00%22.%0A-%20%5B%20%5D%20The%20digest%20posts%20at%20DIGEST_TIME%20and%20not%20again%20that%20day%2C%20including%20after%20a%20restart.%0A-%20%5B%20%5D%20%22Send%20digest%20now%22%20posts%20to%20Slack%20immediately.%0A-%20%5B%20%5D%20The%20CSV%20download%20opens%20in%20a%20spreadsheet%20with%20one%20row%20per%20event%20and%20the%20columns%20listed.%0A-%20%5B%20%5D%20Restarting%20the%20app%20loses%20nothing.%0A%0AWHAT%20TO%20GIVE%20ME%20WHEN%20YOU%20ARE%20DONE%0A%0A1.%20The%20public%20webhook%20URL%20\(%E2%80%A6%2Fwebhooks%2Fstorekit\)%20and%20the%20page%20URL.%0A2.%20The%20environment%20variables%20to%20set%20\(STOREKIT_WEBHOOK_SECRET%2C%20ADMIN_PASSWORD%2C%20SLACK_WEBHOOK_URL%2C%20TIMEZONE%2C%20DIGEST_TIME\)%20and%20where%20to%20set%20them%20on%20this%20platform.%0A3.%20Confirmation%20that%20the%20app%20stays%20up%2024%20hours%20a%20day%20and%20that%20the%20scheduled%20job%20runs%20when%20nobody%20has%20the%20page%20open.%0A)

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.

> **Volledige prompt (klik om uit te klappen)**
>
> ```text theme={null}
> I want a small web app that keeps a log of every menu item that goes out of stock at my restaurant, and sends a short digest to Slack every morning. storekit tells the app about stock-outs by webhook. The app must never lose an event, never count the same event twice, and never make storekit wait.
>
> Build it with a database so the log survives restarts, an always-on public HTTPS URL, and a scheduled job for the digest.
>
> ```
>
> ```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 EVENT THIS APP USES: item.out_of_stock
>
> Ignore the order example above; this app only cares about item.out_of_stock, which looks like this:
>
> {
>   "event": "item.out_of_stock",
>   "data": {
>     "venue": { "id": 1234, "name": "My Restaurant" },
>     "item": { "id": 5678, "name": "Margherita Pizza", "plu": "PLU-001", "posId": "pos_item_42", "sku": "SKU-MARG-001" },
>     "reason": "snoozed",
>     "source": "manual",
>     "details": { "snoozeEnd": "2024-01-15T18:00:00Z" }
>   }
> }
>
> - reason is one of: snoozed (temporarily hidden by staff), inventory_depleted (sold out through inventory counts), disabled (switched off).
> - source is one of: manual (someone in the dashboard), order (a customer order used the last one), deliverect, lightspeed, zonal, pos_sync (pushed from a till or integration).
> - details.snoozeEnd is only present for reason snoozed and can be null, meaning snoozed indefinitely.
> - plu, posId and sku can be null.
> - There is no "back in stock" event. The app records when things went out; it cannot know when they came back.
>
> 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. Ignore any svix-id already saved. Handle item.out_of_stock; save and acknowledge any other event type but do nothing with it.
> 2. A log table with: received time (store UTC, display in TIMEZONE), venue name, item name, item id, plu, sku, reason, source, snoozeEnd. Record the event's time as the time the webhook arrived.
> 3. GET / — protected by HTTP basic auth with ADMIN_PASSWORD. Three things on one page:
>    a. "Yesterday and today": a list of stock-outs since the start of yesterday in TIMEZONE, newest first, showing time, item, reason and source in plain words ("Snoozed by staff until 18:00", "Sold out through inventory after an order", "Switched off from Zonal").
>    b. "Most sold out, last 30 days": items ranked by number of stock-outs, with the count and the most common hour of day it happens.
>    c. Filters for venue (if I have more than one), reason and a date range, and a Download CSV button that exports whatever is filtered with the columns from point 2.
> 4. A daily digest posted to Slack via SLACK_WEBHOOK_URL at DIGEST_TIME (HH:MM in TIMEZONE, default 07:30). Content, in Slack mrkdwn:
>    *Sold out yesterday — <venue name>, <date>*
>    One line per item, in time order: "14:20  Margherita Pizza — sold out (inventory)" or "18:05  Sea Bass — snoozed by staff until 21:00". Group by venue if there is more than one.
>    Then a blank line and "*Most sold out this month*" followed by the top five items with counts.
>    If nothing sold out yesterday, post "Nothing sold out yesterday." — still post, so I know the app is alive.
>    Post the digest once per day even if the app restarts: record the date of the last digest sent and skip if it has already been sent for that date.
> 5. A "Send digest now" button on the page for testing, which posts the digest for yesterday regardless of whether it was already sent.
> 6. GET /health that returns 200 and { "ok": true } and nothing else.
>
> Use TIMEZONE for every day boundary and displayed time. Do not guess a default: if TIMEZONE is unset, refuse to start and log a clear message.
>
> DEFINITION OF DONE
>
> - [ ] A signed item.out_of_stock event appears in the log within a second and the endpoint returned 200.
> - [ ] The same event delivered twice creates one row.
> - [ ] A bad signature returns 400 and logs nothing.
> - [ ] The example payload above shows as "Margherita Pizza — snoozed by staff until 18:00".
> - [ ] The digest posts at DIGEST_TIME and not again that day, including after a restart.
> - [ ] "Send digest now" posts to Slack immediately.
> - [ ] The CSV download opens in a spreadsheet with one row per event and the columns listed.
> - [ ] Restarting the app loses nothing.
>
> WHAT TO GIVE ME WHEN YOU ARE DONE
>
> 1. The public webhook URL (…/webhooks/storekit) and the page URL.
> 2. The environment variables to set (STOREKIT_WEBHOOK_SECRET, ADMIN_PASSWORD, SLACK_WEBHOOK_URL, TIMEZONE, DIGEST_TIME) and where to set them on this platform.
> 3. Confirmation that the app stays up 24 hours a day and that the scheduled job runs when nobody has the page open.
> ```

Open de app, druk op "Send digest now" en controleer dat Slack "Nothing sold out yesterday." toont voordat je storekit aansluit.

## Stap 2: sluit storekit aan

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

Vink voor dit endpoint alleen `item.out_of_stock` aan.

## Stap 3: test met een echte uitverkoop

Snooze een item in de menubuilder (zie [Producten snoozen](/docs/nl/guides/menu/availability-snoozing#producten-snoozen)). Binnen een paar seconden verschijnt een rij in de app met reden "snoozed" en source "manual". Un-snooze het item daarna — de app registreert dit niet, wat de bedoeling is.

## Ideeën

* **Wekelijkse inkoop-e-mail**: vraag de builder om een maandag-e-mail toe te voegen (via een provider zoals Resend of Postmark) met de 30-dagentabel als CSV bijgevoegd.
* **Preplijst**: markeer items die drie keer in een week vóór 20:00 uitverkocht raken als "onder-geprepareerd" en toon ze apart.
* **Kruiscontrole met de kassa**: filter op `source` om te zien hoe vaak je POS items verbergt waarvan je dacht dat ze in de verkoop waren.

## Wat dit niet doet

* **Het kan je niet vertellen wanneer een item terugkwam**, omdat er geen "terug op voorraad"-event is. Lees het log als "raakte op op", niet als "was op gedurende".
* **Het wijzigt de beschikbaarheid niet.** Un-snoozen en bijvullen gebeurt zoals eerst in het dashboard of je kassa.
* **Events starten vanaf het moment dat je het endpoint verbindt.** Er is geen geschiedenis van daarvóór; de 30-dagentabel vult zich in de eerste maand.
* **Het is jouw service.** storekit-support kan bevestigen dat een `item.out_of_stock`-event je URL heeft bereikt en de responscode; het log en de digest zijn van jou.

## Gerelateerd

> **[item.out\_of\_stock-payload](/docs/nl/developers/webhooks/webhook-events#item-out-of-stock)**
>
> Elke reason- en source-waarde die het event kan bevatten.

> **[Een prompt schrijven die werkt](/docs/nl/guides/build/prompting-guide)**
>
> De structuur achter deze prompt, en wat te zeggen als de builder het verkeerd doet.

> **[Order-alerts naar Slack of je telefoon](/docs/nl/guides/build/recipes/order-alerts)**
>
> Hetzelfde patroon voor bestellingen in plaats van voorraad.

> **[Beschikbaarheid en snoozen](/docs/nl/guides/menu/availability-snoozing)**
>
> Snoozen, voorraad en het ingebouwde snooze-rapport.


## Related topics

- [Bouw je eigen tools op storekit](/docs/nl/guides/build/overview.md)
- [Audit log](/docs/nl/privacy-security/audit-log.md)
- [Geneste modifiers: setup, POS-ondersteuning en diepte](/docs/nl/guides/menu/nested-modifiers.md)
- [Beschikbaarheid en snoozing](/docs/nl/guides/menu/availability-snoozing.md)
- [Foodtrucks en pop-ups](/docs/nl/guides/use-cases/food-trucks.md)


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