Wiring an Accounting System into a Payment Webhook Without Losing Money
On Pikkuna , a Stripe webhook doesn’t do the order-processing work itself. The moment payment confirms, it enqueues the order into a BullMQ (Redis-backed) job queue. A worker picks the job up and runs through it: create a CRM deal, write a backup record, book a shipment, log the accounting entry, generate a PDF invoice, email it, and fire a couple of analytics events (left out of the snippet below for scope, not because they don’t matter). The steps run sequentially, one after another inside the same worker function. The accounting call is one of them. It goes to Netvisor , the Finnish bookkeeping platform this business’s accountant works from: // src/app/api/stripe-webhook/route.ts export async function POST ( req : Request ) { const event = stripe . webhooks . constructEvent ( body , sig , secret ); if ( event . type === " checkout.session.completed " ) { const session = event . data . object ; // Enqueue for sequential processing — the worker handles // Zoho, Airtable, PostNord, Netvisor, PDF, and email in order await orderQueue . add ( " process-order " , { sessionId : session . id }); } return new Response ( " Queued " , { status : 200 }); } // workers/order-processor.ts const worker = new Worker ( " orders " , async ( job ) => { const { sessionId } = job . data ; const session = await fetchSession ( sessionId ); await createZohoDeal ( session ); // CRM await createAirtableRecord ( session ); // Backup DB await createPostNordShipment ( session ); // Shipping label await sendToNetvisor ( session ); // Accounting const invoice = await generateInvoicePDF ( session ); await sendEmailWithInvoice ( session , invoice ); }); That’s the real shape – the webhook half published verbatim in the Pikkuna case study , the worker steps reconstructed from its description – simplified for this article’s scope. What it doesn’t show is what sendToNetvisor has to guarantee to be safe to call from inside a job that BullMQ will retry automatically on failure, with backoff, for howeve