Webhooks send HTTP POST requests to your server when events occur, so you don’t need to poll the API for changes.
const webhook = await sdk.webhooks.create ({
url: "https://example.com/webhooks" ,
events: ["invoice.created" , "invoice.paid" , "payment.received" ],
description: "Invoice notifications" ,
});
console.log ("Webhook secret:" , webhook.secret );
Subscribe to specific events or listen to all events for a category.
Event Trigger invoice.createdInvoice created invoice.updatedInvoice updated invoice.sentInvoice sent to customer invoice.paidInvoice fully paid invoice.overdueInvoice past due date invoice.cancelledInvoice cancelled invoice.deletedInvoice soft-deleted invoice.restoredInvoice restored from deletion invoice.voidedInvoice voided invoice.finalizedInvoice finalized (locked)
Event Trigger customer.createdCustomer created customer.updatedCustomer updated customer.deletedCustomer soft-deleted customer.restoredCustomer restored customer.permanently_deletedCustomer permanently removed
Event Trigger payment.receivedPayment received payment.failedPayment failed payment.deletedPayment soft-deleted payment.restoredPayment restored payment.permanently_deletedPayment permanently removed
Event Trigger estimate.createdEstimate created estimate.sentEstimate sent estimate.acceptedEstimate accepted by customer estimate.rejectedEstimate rejected estimate.deletedEstimate soft-deleted estimate.restoredEstimate restored
Event Trigger credit_note.createdCredit note created credit_note.issuedCredit note issued credit_note.voidedCredit note voided credit_note.deletedCredit note soft-deleted credit_note.restoredCredit note restored
Event Trigger advance_invoice.createdAdvance invoice created advance_invoice.paidAdvance invoice paid advance_invoice.appliedAdvance applied to final invoice advance_invoice.voidedAdvance invoice voided advance_invoice.deletedAdvance invoice soft-deleted advance_invoice.restoredAdvance invoice restored
Event Trigger recurring_invoice.createdSchedule created recurring_invoice.updatedSchedule updated recurring_invoice.deletedSchedule soft-deleted recurring_invoice.restoredSchedule restored recurring_invoice.permanently_deletedSchedule permanently removed recurring_invoice.pausedSchedule paused recurring_invoice.resumedSchedule resumed recurring_invoice.invoice_generatedInvoice generated from schedule recurring_invoice.generation_failedInvoice generation failed recurring_invoice.completedAll invoices generated
Event Trigger item.createdItem created item.deletedItem soft-deleted item.restoredItem restored item.permanently_deletedItem permanently removed tax.createdTax created tax.updatedTax updated tax.deletedTax soft-deleted tax.restoredTax restored tax.permanently_deletedTax permanently removed
Event Trigger order.createdOrder created order.updatedOrder updated order.deletedOrder soft-deleted order.restoredOrder restored order.permanently_deletedOrder permanently removed order.processedOrder processed order.cancelledOrder cancelled order.failedOrder processing failed order_integration.createdOrder integration created order_integration.updatedOrder integration updated order_integration.deletedOrder integration deleted delivery_note.createdDelivery note created delivery_note.sentDelivery note sent delivery_note.cancelledDelivery note cancelled delivery_note.voidedDelivery note voided delivery_note.deletedDelivery note soft-deleted delivery_note.restoredDelivery note restored
Event Trigger e_invoicing.submission.createdE-invoice submitted e_invoicing.submission.deliveredE-invoice delivered e_invoicing.submission.failedE-invoice delivery failed e_invoicing.supplier.onboardedSupplier onboarded for e-invoicing e_invoicing.supplier.rejectedSupplier onboarding rejected stripe_app.connectedStripe app connected stripe_app.disconnectedStripe app disconnected stripe_app.settings_updatedStripe app settings changed
Every webhook delivery sends a JSON payload:
"timestamp" : " 2024-01-15T10:30:00.000Z "
The data field contains the full resource object at the time of the event.
Header Description X-Webhook-SignatureHMAC-SHA256 signature (sha256=<hex>) X-Webhook-TimestampUnix timestamp (seconds) X-Webhook-EventEvent type X-Webhook-DeliveryUnique delivery ID X-Webhook-IdWebhook ID Content-Typeapplication/json
Every delivery is signed with your webhook secret using HMAC-SHA256. Always verify signatures to ensure requests are from Space Invoices.
import crypto from "node:crypto" ;
function verifyWebhookSignature (
secret: string,
payload: string,
signatureHeader: string,
): boolean {
const expected = crypto
.createHmac ("sha256" , secret)
.update (payload)
.digest ("hex" );
return signatureHeader === `sha256=${expected}` ;
}
const rawBody = await request.text ();
const signature = request.headers.get ("X-Webhook-Signature" )!;
if (!verifyWebhookSignature ("your_webhook_secret" , rawBody, signature)) {
throw new Error ("Invalid webhook signature" );
}
Process events asynchronously and respond quickly with a 2xx status.
app.post ("/webhooks" , async (req, res) => {
const { event, data, timestamp } = req.body ;
switch (event) {
case "invoice.paid" :
await fulfillOrder (data.id );
break;
case "invoice.overdue" :
await sendReminder (data.id );
break;
case "customer.created" :
await syncToExternalCRM (data);
break;
}
res.status (200 ).json ({ received: true });
});
Failed deliveries (non-2xx response or timeout) are retried up to 5 times with increasing delays:
Attempt Delay 1 1 minute 2 5 minutes 3 30 minutes 4 2 hours 5 24 hours
Deliveries that return 410 Gone are not retried and the webhook is automatically deactivated.
The delivery timeout is 10 seconds — your endpoint must respond within this window.
Respond 2xx quickly — Do heavy processing asynchronously after acknowledging the webhook
Verify signatures — Always validate X-Webhook-Signature before processing
Handle duplicates — Use the X-Webhook-Delivery header as an idempotency key in case of retries
Monitor deliveries — Check webhook delivery logs in the dashboard for failures
Use specific events — Subscribe only to events you need rather than all events
Secure your endpoint — Use HTTPS and restrict access to Space Invoices IP ranges if possible