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

# Auszahlungs-Abgleichsblatt

> Verfolgen Sie jede storekit-Auszahlung in einem Ledger nach svix-id, mit Abgleichs-Häkchen und CSV-Export, gespeist vom payments.payout.created-Webhook.

Jede Auszahlung, die storekit an Ihre Bank sendet, wird im Moment ihrer Erstellung zu einer Zeile in Ihrem eigenen Ledger: Betrag, Währung, welches Bankkonto und wann sie zu erwarten ist. Haken Sie jede Zeile ab, sobald sie auf Ihrem Kontoauszug erscheint, und laden Sie den Monat als CSV für Ihren Buchhalter herunter.

> [!TIP]
>
> Das Dashboard listet Auszahlungen unter **Analytics** → **Accounting** → **Payouts** (siehe [Wie Auszahlungen funktionieren](/docs/de/payouts/overview)). Bauen Sie dieses Rezept, wenn Sie Ihren eigenen Abgleichsstatus (abgehakt, Notizen, erwartet-vs.-eingegangen), einen für Ihre Buchhaltungssoftware zugeschnittenen Export oder einen Slack-Hinweis wollen, wenn eine Auszahlung fällig ist.

## So funktioniert es

1. storekit sendet `payments.payout.created` an Ihre App, wenn eine Auszahlung erstellt wird.
2. Ihre App fügt pro Auszahlung eine Zeile mit dem Gesamtbetrag je Währung, den letzten vier Ziffern des Bankkontos und dem geschätzten Ankunftsdatum hinzu.
3. Sie haken Zeilen gegen Ihren Kontoauszug ab; alles nach dem Ankunftsdatum, das noch nicht abgehakt ist, wird hervorgehoben.

## Was Sie brauchen

* Webhooks in Ihrem storekit-Plan aktiviert (**Settings** → **Developers**).
* Ein [Replit](https://replit.com)-Konto – das Ledger braucht eine Datenbank und eine URL, die verfügbar bleibt.
* Optional: eine Slack-Incoming-Webhook-URL für eine wöchentliche „noch nicht abgeglichen"-Erinnerung.

## Schritt 1: Die App bauen

Fügen Sie den gesamten Block in einer einzigen Nachricht in den Builder ein.

[![Open in Replit](https://replit.com/badge?caption=Open%20in%20Replit)](https://replit.com/?stack=Build\&prompt=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-VCHtaurlZpSS4S02QHJeC8DBEuJ0TziRYCaD-RYuDlEYLuWCvFcZki0ykDKL4pg471wLHgp8rBkEamWTAZSnc6AOS4MssJLYhWzHTrQy+UAFAYGSCJSa0YhnIEQAAbQALqJA1QwmUMSQAqqRjAgIDEc6jXiiIRKxoHUyDcfSeYaVoRWHtY6ogMB6QKGQDE4QBZijCB3uATlSB37unKV+C4TIaLzHdIsOSClYZ8USGpcosg0AiAKhOM44EzggGgihAiUFLLpuUpm1S2Fi3QQqgRItJaS1QVKuW6Y1N8hWAdqpAAzHWlt0FbDyXLRyB2lxa32Hra2t4bQCIwClBsGd0EanoAIpsqOK6oIZiwBurZ06h24WZW0tgG6ACc57D0ttwl0uwvT+loAIpXbdpzznlpBUSwdN7-7MGpbShY5bI6qSVoiFWDtETOyaA7FWY4lZOzHGrAAWt+1tpRoDdCfQhKC9NLioegrrf1gahAEQtXU7dVa+AchgEBlWIGwMQagzBscfbYPIfw8e0FSCAMkFo-R8DkGnbQYdohtjKsUPXtbRqxA5bSQtiEuoGJGAONeq1IlJtK7W3B1UG6wD2HdwiHoFAfDraPQ6fdR+kQvHJM3oCGFctBlDNQAAAK0STTwJ1yATMEbqN0ctABqJWSte19vgwANgAOwAA5z3eagqgROcN7TUiYgkBdS6V2kRs220gOqCK6s04RQrUmLPYY1rGfgUh8ABjXHgAAXnViA3nW3TNgLp3jZWKtVcVM1gj+B1gEV7VuodR76rBmVINmzR73QKFI6q8jI2f0DGALwObGAps3oDDRUkcQN0vsW1JgJa2FsHfixMu6s18vFZbZBKCbC9PQQTYuhApQ2C6Gwn1-W7Xy3UikCCazn2BsIWdpXaCY3YATeBzhGbx3ofLdWwhMjOEts7dIHtsi139WFdIiu-V2WUodaK4tttCOQAhaVhtu7pXoJa2qv6QM304KU8QGgBQ-By0mERGCAMQYmeFaggVMl6oNMHegqoDQcMHblpCyAcrNYPm9aguLtgMBa3YcVz4GAshy3klNksRXutVApdHdh2mDsORk45ByDX96kHluJMKG3G1oCyG+2V0wNVYi87gOSGAq2NtofqHJUIcQZMIVux6DMc8TcgCdg7RIWyIsU+grm4G2gFAx7A4kXt0WMeLZx0OrL27CUDRJULsJIuRtK8XSrqX2HwsgFpBASwHJehxeV3DNX0FWmR-LnFzX2vsO6-0PrynhuYDG8J1BJkDsQBhY5PSfvtvB-QQd3F6TsP+e2GmCH0gYfCIp5ltHwnceE-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-VGG6B6DWPSQqXbI8DAFRPkusIAa2V-XfLIIGo-U4EeA0KwOwC2B8MfJAHMtCRCMBIEFYDwNALVS4I+dmpUHWaXX3YwJaMsFQzYtVvSmQPvYfd7VPU8ckVSE7M-AxKwo9DUJoHghoCSW5AhJmOTOSByNSKzLhhFazBeNRboKHOgqYBrKbDdUwCrOeqJrdfdY9c9dgMPNBAhercWbUtaA6CyPWeqXDBA7A1A6IJUiNCiYEIhB-VhFfcICJC3VDMY18I1fWGmN0B7FoLQAkJkhUsghIE+ATA9FHXeGSXY1SGFizWzc5NNEbWUCLHABoCVa7eVdGLdg0OlqlGRInTNS2BUroOpdckyK0hLWKMAIeLSK0iANcs9RcFOLqiAPqrQTkKIcmkAbvW7ZIaNA5JNNfd7XbasFDBTiBmKVlWkVuI8MA-AmA5gJxSCXRhcVVOs5s9QoqmQAJCXoieZKsAnZRvGTfRWViV85yDGDMPtGwiVTnXDACK7ZlUVVMHJBrSM+vZCxs6gliw6I+DkAHG8GMh4imv0ARaNHOXFbMLBS4PMQhbxX+XACqsRsIPqeGlBNsdFsxVrn4IDYiPucIEGZ87i7SgAi2H7dE+FCNeYpVRHTVQFbCwCECL0Nabnfs9GFovThCKK98zkAo6IIvOYl-PKEYm+CrvczuNgzJay0GoRSAFCxbo2UdSdeMmXRI1wDo39fwLXdCPXPPWTDUy3ZVu3RAU-BcJpdpbQbSCAH4cAFQbLhQZpdQSAAAJo8ichChLMrNnAmXUJYBogYhWADi4EkgUh6iABkBBZYOCgXAdoF+Y3N8HwC6eW5SBtc0Ns1ANjEsITZUyrYYM4HY3qEFVTKFZY8zKzOzJzGzY4KLeLZLdLbLfLaSNco4HdQ9U9fSEyFfZo0sLGQSKY+Y2FYzJO9TBeI2xGoicWY2BkFIIECiOPfkjAL6MgEzckCllAMHCRawgIne2lO0LENXUAiBoBMDdac8DnGcEAA\&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%20private%20web%20app%20that%20keeps%20a%20ledger%20of%20the%20payouts%20storekit%20sends%20to%20my%20bank%20account%2C%20so%20I%20can%20reconcile%20them%20against%20my%20bank%20statement.%20storekit%20tells%20the%20app%20about%20each%20payout%20by%20webhook.%20The%20app%20must%20never%20lose%20a%20payout%2C%20never%20record%20the%20same%20one%20twice%2C%20and%20never%20make%20storekit%20wait.%0A%0ABuild%20it%20with%20a%20database%20so%20the%20ledger%20survives%20restarts%20and%20an%20always-on%20public%20HTTPS%20URL.%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%20payments.payout.created%0A%0AIgnore%20the%20order%20example%20above%3B%20this%20app%20only%20cares%20about%20payments.payout.created%2C%20which%20looks%20like%20this%3A%0A%0A%7B%0A%20%20%22event%22%3A%20%22payments.payout.created%22%2C%0A%20%20%22data%22%3A%20%7B%0A%20%20%20%20%22amounts%22%3A%20%5B%0A%20%20%20%20%20%20%7B%20%22currency%22%3A%20%22GBP%22%2C%20%22value%22%3A%20%223210.50%22%20%7D%2C%0A%20%20%20%20%20%20%7B%20%22currency%22%3A%20%22GBP%22%2C%20%22value%22%3A%20%221030.00%22%20%7D%0A%20%20%20%20%5D%2C%0A%20%20%20%20%22bankAccount%22%3A%20%7B%0A%20%20%20%20%20%20%22id%22%3A%20%22db97e205-105c-42ff-8460-d06c25cb6830%22%2C%0A%20%20%20%20%20%20%22IBAN%22%3A%20%22GB15HBUK40127612345678%22%2C%0A%20%20%20%20%20%20%22accountNumber%22%3A%20%220001234%22%2C%0A%20%20%20%20%20%20%22branchCode%22%3A%20%22001234%22%2C%0A%20%20%20%20%20%20%22currency%22%3A%20%22GBP%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22estimatedArrivalDate%22%3A%20%221%2F2024%22%0A%20%20%7D%0A%7D%0A%0AImportant%20differences%20from%20the%20order%20events%3A%0A-%20Money%20here%20is%20NOT%20in%20minor%20units.%20Each%20value%20is%20a%20decimal%20string%20in%20major%20units%3A%20%223210.50%22%20means%203%2C210.50.%20Parse%20it%20as%20a%20decimal%2C%20never%20as%20a%20float%20you%20then%20round%20%E2%80%94%20use%20a%20decimal%20library%20or%20store%20it%20as%20a%20string%20and%20sum%20with%20integer%20pence.%0A-%20amounts%20is%20a%20list.%20Sum%20the%20values%20per%20currency%3B%20a%20payout%20usually%20has%20one%20currency%20but%20do%20not%20assume%20it.%20Show%20each%20currency%20total%20on%20the%20row.%0A-%20The%20payload%20has%20no%20payout%20id%20and%20no%20store%20name.%20Use%20the%20svix-id%20header%20as%20the%20unique%20key%20for%20the%20row.%0A-%20bankAccount%20contains%20full%20bank%20details.%20Store%20only%20the%20last%20four%20characters%20of%20accountNumber%20\(or%20of%20IBAN%20if%20accountNumber%20is%20missing\)%20and%20the%20bankAccount.id.%20Do%20not%20store%20or%20display%20the%20full%20IBAN%20or%20account%20number%20anywhere%2C%20including%20logs.%0A-%20estimatedArrivalDate%20is%20a%20%22month%2Fyear%22%20string%20such%20as%20%221%2F2024%22%2C%20or%20an%20empty%20string%20when%20unknown.%20Show%20it%20as%20text%3B%20do%20not%20parse%20it%20as%20a%20date.%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%20row%20and%20return%20200%20immediately.%20Ignore%20any%20svix-id%20already%20saved.%20Handle%20payments.payout.created%3B%20save%20and%20acknowledge%20any%20other%20event%20type%20but%20do%20nothing%20with%20it.%0A2.%20A%20ledger%20table%20with%3A%20received%20time%20\(UTC%2C%20display%20in%20TIMEZONE\)%2C%20amounts%20per%20currency%2C%20bank%20account%20last%20four%2C%20bank%20account%20id%2C%20estimated%20arrival%20date%2C%20reconciled%20\(yes%2Fno\)%2C%20reconciled%20on%2C%20statement%20reference%20\(free%20text\)%2C%20notes%20\(free%20text\).%0A3.%20GET%20%2F%20%E2%80%94%20protected%20by%20HTTP%20basic%20auth%20with%20ADMIN_PASSWORD.%20A%20table%20of%20payouts%20newest%20first%20with%20a%20month%20filter%20\(default%3A%20current%20month\)%2C%20showing%20the%20columns%20above.%20Each%20row%20has%20a%20Reconciled%20tick-box%20and%20editable%20statement%20reference%20and%20notes%20fields%20that%20save%20without%20a%20page%20reload.%20Rows%20received%20more%20than%207%20days%20ago%20and%20not%20reconciled%20are%20highlighted%20amber.%20Above%20the%20table%3A%20total%20paid%20out%20this%20month%20per%20currency%2C%20total%20reconciled%2C%20total%20outstanding.%0A4.%20Download%20CSV%20for%20the%20filtered%20month%2C%20one%20row%20per%20payout%2C%20columns%3A%20received_date%2C%20currency%2C%20amount%2C%20bank_last4%2C%20estimated_arrival%2C%20reconciled%2C%20reconciled_on%2C%20statement_reference%2C%20notes.%20Amounts%20as%20plain%20decimals%20with%20two%20places%20and%20no%20currency%20symbol%20so%20bookkeeping%20software%20imports%20them%20cleanly.%20If%20a%20payout%20has%20more%20than%20one%20currency%2C%20write%20one%20CSV%20row%20per%20currency.%0A5.%20Optional%20weekly%20reminder%3A%20if%20SLACK_WEBHOOK_URL%20is%20set%2C%20every%20Monday%20at%2009%3A00%20in%20TIMEZONE%20post%20%22N%20payouts%20totalling%20X%20not%20yet%20reconciled%2C%20oldest%20from%20%3Cdate%3E%22%2C%20or%20nothing%20if%20there%20are%20none.%20Skip%20entirely%20if%20the%20variable%20is%20unset.%0A6.%20GET%20%2Fhealth%20that%20returns%20200%20and%20%7B%20%22ok%22%3A%20true%20%7D%20and%20nothing%20else.%0A%0ADEFINITION%20OF%20DONE%0A%0A-%20%5B%20%5D%20The%20example%20payload%20above%20creates%20one%20row%20showing%204%2C240.50%20GBP%20with%20estimated%20arrival%20%221%2F2024%22.%0A-%20%5B%20%5D%20The%20same%20event%20delivered%20twice%20creates%20one%20row.%0A-%20%5B%20%5D%20A%20bad%20signature%20returns%20400%20and%20records%20nothing.%0A-%20%5B%20%5D%20Nothing%20in%20the%20database%2C%20page%20or%20logs%20contains%20the%20full%20IBAN%20or%20account%20number%20%E2%80%94%20only%20%225678%22%20style%20last-four%20values.%0A-%20%5B%20%5D%20Ticking%20Reconciled%20saves%20immediately%20and%20survives%20a%20reload%20and%20a%20restart.%0A-%20%5B%20%5D%20The%20CSV%20opens%20in%20a%20spreadsheet%20with%20amounts%20as%20numbers.%0A-%20%5B%20%5D%20A%20payout%20received%20more%20than%20a%20week%20ago%20and%20not%20reconciled%20is%20highlighted.%0A%0AWHAT%20TO%20GIVE%20ME%20WHEN%20YOU%20ARE%20DONE%0A%0A1.%20The%20public%20webhook%20URL%20\(%E2%80%A6%2Fwebhooks%2Fstorekit\)%20and%20the%20ledger%20URL.%0A2.%20The%20environment%20variables%20to%20set%20\(STOREKIT_WEBHOOK_SECRET%2C%20ADMIN_PASSWORD%2C%20TIMEZONE%2C%20optionally%20SLACK_WEBHOOK_URL\)%20and%20where%20to%20set%20them%20on%20this%20platform.%0A3.%20Confirmation%20that%20the%20app%20stays%20up%2024%20hours%20a%20day.%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.

> **Vollständiger Prompt (zum Ausklappen klicken)**
>
> ```text theme={null}
> I want a small private web app that keeps a ledger of the payouts storekit sends to my bank account, so I can reconcile them against my bank statement. storekit tells the app about each payout by webhook. The app must never lose a payout, never record the same one twice, and never make storekit wait.
>
> Build it with a database so the ledger survives restarts and an always-on public HTTPS URL.
>
> ```
>
> ```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: payments.payout.created
>
> Ignore the order example above; this app only cares about payments.payout.created, which looks like this:
>
> {
>   "event": "payments.payout.created",
>   "data": {
>     "amounts": [
>       { "currency": "GBP", "value": "3210.50" },
>       { "currency": "GBP", "value": "1030.00" }
>     ],
>     "bankAccount": {
>       "id": "db97e205-105c-42ff-8460-d06c25cb6830",
>       "IBAN": "GB15HBUK40127612345678",
>       "accountNumber": "0001234",
>       "branchCode": "001234",
>       "currency": "GBP"
>     },
>     "estimatedArrivalDate": "1/2024"
>   }
> }
>
> Important differences from the order events:
> - Money here is NOT in minor units. Each value is a decimal string in major units: "3210.50" means 3,210.50. Parse it as a decimal, never as a float you then round — use a decimal library or store it as a string and sum with integer pence.
> - amounts is a list. Sum the values per currency; a payout usually has one currency but do not assume it. Show each currency total on the row.
> - The payload has no payout id and no store name. Use the svix-id header as the unique key for the row.
> - bankAccount contains full bank details. Store only the last four characters of accountNumber (or of IBAN if accountNumber is missing) and the bankAccount.id. Do not store or display the full IBAN or account number anywhere, including logs.
> - estimatedArrivalDate is a "month/year" string such as "1/2024", or an empty string when unknown. Show it as text; do not parse it as a date.
>
> 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 row and return 200 immediately. Ignore any svix-id already saved. Handle payments.payout.created; save and acknowledge any other event type but do nothing with it.
> 2. A ledger table with: received time (UTC, display in TIMEZONE), amounts per currency, bank account last four, bank account id, estimated arrival date, reconciled (yes/no), reconciled on, statement reference (free text), notes (free text).
> 3. GET / — protected by HTTP basic auth with ADMIN_PASSWORD. A table of payouts newest first with a month filter (default: current month), showing the columns above. Each row has a Reconciled tick-box and editable statement reference and notes fields that save without a page reload. Rows received more than 7 days ago and not reconciled are highlighted amber. Above the table: total paid out this month per currency, total reconciled, total outstanding.
> 4. Download CSV for the filtered month, one row per payout, columns: received_date, currency, amount, bank_last4, estimated_arrival, reconciled, reconciled_on, statement_reference, notes. Amounts as plain decimals with two places and no currency symbol so bookkeeping software imports them cleanly. If a payout has more than one currency, write one CSV row per currency.
> 5. Optional weekly reminder: if SLACK_WEBHOOK_URL is set, every Monday at 09:00 in TIMEZONE post "N payouts totalling X not yet reconciled, oldest from <date>", or nothing if there are none. Skip entirely if the variable is unset.
> 6. GET /health that returns 200 and { "ok": true } and nothing else.
>
> DEFINITION OF DONE
>
> - [ ] The example payload above creates one row showing 4,240.50 GBP with estimated arrival "1/2024".
> - [ ] The same event delivered twice creates one row.
> - [ ] A bad signature returns 400 and records nothing.
> - [ ] Nothing in the database, page or logs contains the full IBAN or account number — only "5678" style last-four values.
> - [ ] Ticking Reconciled saves immediately and survives a reload and a restart.
> - [ ] The CSV opens in a spreadsheet with amounts as numbers.
> - [ ] A payout received more than a week ago and not reconciled is highlighted.
>
> WHAT TO GIVE ME WHEN YOU ARE DONE
>
> 1. The public webhook URL (…/webhooks/storekit) and the ledger URL.
> 2. The environment variables to set (STOREKIT_WEBHOOK_SECRET, ADMIN_PASSWORD, TIMEZONE, optionally SLACK_WEBHOOK_URL) and where to set them on this platform.
> 3. Confirmation that the app stays up 24 hours a day.
> ```

## 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 nur `payments.payout.created` an. Nutzen Sie die Test-Option des Portals mit diesem Event-Typ, um Ihre erste Zeile zu erstellen.

## Schritt 3: Abgleichen

Sobald die nächste echte Auszahlung eintrifft, vergleichen Sie die Zeile mit **Analytics** → **Accounting** → **Payouts** im Dashboard und mit Ihrem Kontoauszug und haken Sie sie dann ab. Auszahlungen folgen Ihrem [Auszahlungsplan](/docs/de/payouts/payout-schedule), sodass die erste echte Zeile ein paar Tage dauern kann.

## Ideen

* **Automatisch an Ihren Buchhalter senden**: Bitten Sie den Builder, die CSV des Monats am 1. per E-Mail über einen Anbieter wie Resend oder Postmark zu versenden.
* **Nach Betrag matchen**: Fügen Sie eine Kontoauszug-CSV ein und lassen Sie die App Übereinstimmungen nach Betrag und Datum vorschlagen.
* **Mehrere Stores**: Betreiben Sie einen Endpoint pro storekit-Konto und fügen Sie ein „store"-Label aus einer Umgebungsvariable hinzu, damit das Ledger zusammengeführt werden kann.

## Was dieses Rezept nicht tut

* **Es erklärt nicht, was in einer Auszahlung steckt.** Das Event enthält die Summen, nicht die dahinterliegenden Bestellungen, Gebühren oder Rückerstattungen; nutzen Sie dafür den [Gebührenbericht](/docs/de/guides/reports/fee-report) und den [Transaktionsbericht](/docs/de/guides/reports/transactions-report).
* **Es startet ab dem Tag, an dem Sie es verbinden.** Frühere Auszahlungen finden Sie im Dashboard, nicht im Event-Stream.
* **Es ist kein Zahlungsnachweis.** Das Event sagt, dass eine Auszahlung erstellt wurde; ob und wann sie ankommt, liegt zwischen dem Payment-Anbieter und Ihrer Bank.
* **Es ist Ihr Service.** Der storekit-Support kann bestätigen, dass das Event Ihre URL erreicht hat und mit welchem Antwortcode; das Ledger und der Export gehören Ihnen.

## Verwandt

> **[payments.payout.created-Payload](/docs/de/developers/webhooks/webhook-events#payments-payout-created)**
>
> Der vollständige Payload, einschließlich der Felder, die dieses Rezept bewusst nicht speichert.

> **[Wie Auszahlungen funktionieren](/docs/de/payouts/overview)**
>
> Timing, Gebühren und wo Auszahlungen im Dashboard erscheinen.

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

> **[Gebührenbericht](/docs/de/guides/reports/fee-report)**
>
> Was vor der Auszahlung abgezogen wurde.


## Related topics

- [Rückerstattungen und Auszahlungen](/docs/de/guides/payments/refunds-payouts.md)
- [storekit-Auszahlungen: Zeitpunkt, Gebühren, Verifizierung](/docs/de/payouts/overview.md)
- [Auszahlungsplan](/docs/de/payouts/payout-schedule.md)
- [Gebührenbericht und Tageszusammenfassung](/docs/de/guides/reports/fee-report.md)
- [storekit-Auszahlungsbankkonto einrichten und ändern](/docs/de/payouts/bank-accounts.md)


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