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

# Foglio di riconciliazione dei payout

> Traccia ogni payout storekit in un registro indicizzato per svix-id, con casella di conciliazione ed esportazione CSV, dal webhook payments.payout.created.

Ogni payout che storekit invia alla tua banca diventa una riga nel tuo registro nel momento in cui viene creato: importo, valuta, quale conto bancario e quando aspettartelo. Spunta ogni riga man mano che appare sul tuo estratto conto e scarica il mese come CSV per il tuo commercialista.

> [!TIP]
>
> La dashboard elenca i payout sotto **Analytics** → **Accounting** → **Payouts** (vedi [Come funzionano i payout](/docs/it/payouts/overview)). Costruisci questa recipe quando vuoi il tuo stato di riconciliazione (spuntato, note, atteso vs arrivato), un'esportazione formattata per il tuo software di contabilità o un promemoria Slack quando un payout è atteso.

## Come funziona

1. storekit invia `payments.payout.created` alla tua app quando viene creato un payout.
2. La tua app aggiunge una riga per payout con il totale per valuta, le ultime quattro cifre del conto bancario e la data stimata di arrivo.
3. Tu spunti le righe rispetto al tuo estratto conto; qualsiasi payout oltre la data di arrivo e ancora non spuntato viene evidenziato.

## Cosa ti serve

* I webhook abilitati sul tuo piano storekit (**Settings** → **Developers**).
* Un account [Replit](https://replit.com) — il registro ha bisogno di un database e di un URL che resti attivo.
* Opzionale: un URL di incoming webhook Slack per un promemoria settimanale "ancora non riconciliato".

## Step 1: costruisci l'app

Incolla nel builder l'intero blocco in un unico messaggio.

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

> **Prompt completo (clicca per espandere)**
>
> ```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.
> ```

## Step 2: collega storekit

**1. Open the webhooks portal**

In the dashboard sidebar, go to **Settings** → **Webhooks**. If your plan includes webhooks and they are not yet enabled, click **Enable Webhooks**. If the page shows **Upgrade to enable webhooks**, [contact support](/docs/getting-started/contact-support) to discuss adding webhooks to your plan.

**2. Add your app as an endpoint**

In the embedded portal, add a new endpoint, paste the webhook URL your app builder gave you, and tick only the event types the recipe needs.

**3. Copy the signing secret into your app**

Open the endpoint you just created and copy its signing secret. In your app builder, save it as the environment variable `STOREKIT_WEBHOOK_SECRET` (builders call this "secrets" or "environment variables"). Redeploy if the builder asks you to.

**4. Send a test event**

Use the portal's test option on the endpoint to send a sample event. The delivery log shows the response code from your app. A `2xx` means your app accepted it; anything else, read the response body in the log — it is usually a missing secret.

Spunta solo `payments.payout.created` per questo endpoint. Usa l'opzione di test del portale con quel tipo di evento per creare la tua prima riga.

## Step 3: riconcilia

Quando arriva il prossimo payout reale, confronta la riga con **Analytics** → **Accounting** → **Payouts** nella dashboard e con il tuo estratto conto, poi spuntala. I payout seguono la tua [pianificazione dei payout](/docs/it/payouts/payout-schedule), quindi la prima riga reale potrebbe richiedere qualche giorno.

## Idee

* **Invia automaticamente al commercialista**: chiedi al builder di inviare via email il CSV del mese il 1° tramite un provider come Resend o Postmark.
* **Match per importo**: incolla un CSV dell'estratto conto e lascia che l'app suggerisca corrispondenze per importo e data.
* **Più negozi**: esegui un endpoint per account storekit e aggiungi un'etichetta "store" da una variabile d'ambiente così che il registro possa essere unito.

## Cosa non fa

* **Non spiega cosa c'è dentro un payout.** L'evento contiene i totali, non gli ordini, le commissioni o i rimborsi che ci stanno dietro; per quello usa il [report commissioni](/docs/it/guides/reports/fee-report) e il [report transazioni](/docs/it/guides/reports/transactions-report).
* **Parte dal giorno in cui la colleghi.** I payout precedenti sono nella dashboard, non nel flusso di eventi.
* **Non è una prova di pagamento.** L'evento dice che un payout è stato creato; se e quando arriva è una questione tra il provider di pagamento e la tua banca.
* **È il tuo servizio.** Il supporto di storekit può confermare che l'evento ha raggiunto il tuo URL e il codice di risposta; il registro e l'esportazione sono tuoi.

## Correlati

> **[Payload payments.payout.created](/docs/it/developers/webhooks/webhook-events#payments-payout-created)**
>
> Il payload completo, inclusi i campi che questa recipe deliberatamente non memorizza.

> **[Come funzionano i payout](/docs/it/payouts/overview)**
>
> Tempistiche, commissioni e dove i payout appaiono nella dashboard.

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

> **[Report commissioni](/docs/it/guides/reports/fee-report)**
>
> Cosa è stato dedotto prima del payout.


## Related topics

- [Fee Report e Daily Summary](/docs/it/guides/reports/fee-report.md)
- [Calendario dei bonifici](/docs/it/payouts/payout-schedule.md)
- [Report di vendita e contabilità in storekit](/docs/it/guides/reports/overview.md)
- [Costruisci i tuoi strumenti su storekit](/docs/it/guides/build/overview.md)
- [Bonifici storekit: tempi, commissioni e verifica](/docs/it/payouts/overview.md)


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