Moneybird logo
Webhooks

Subscribing to Payment Updates

Keep your store, order management, or CRM in sync the moment an invoice is paid by subscribing to Moneybird webhook events.

Overview

Webhooks send your server a POST request when something changes in your administration. This page is a practical example of how to subscribe to webhook events and covers a frequently used scenario. To react to payments, subscribe to the specific invoice-paid events and update your system when they arrive. While there are many more events you can subscribe to, this page is an easy guide for subscribing to payment updates.

Useful background:

Prerequisites

  • You have an access token and your administration ID. See Getting started and Authentication.
  • You have a public HTTPS endpoint that returns HTTP 200 OK for deliveries.

To know when an invoice is fully paid:

  • sales_invoice_state_changed_to_paid (for regular sales invoices)
  • external_sales_invoice_state_changed_to_paid (for external sales invoices)

Optionally, if you want to react to partial payments or reversals as well:

  • payment_registered (a payment was added)
  • payment_destroyed (a payment was removed)

Alternatively, you can subscribe to the event groups for state changes and filter in your code:

  • sales_invoice_state_changed
  • external_sales_invoice_state_changed

Step-by-step

1. Create a webhook for payment updates

Register a webhook and subscribe to the paid events so your endpoint is called immediately when an invoice becomes paid.

TerminalCode
curl -X POST "https://moneybird.com/api/v2/{ADMINISTRATION_ID}/webhooks.json" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer {ACCESS_TOKEN}" \ -d '{ "url": "https://example.com/webhooks/moneybird", "enabled_events": [ "sales_invoice_state_changed_to_paid", "external_sales_invoice_state_changed_to_paid" ] }'

The response includes a secret field — this is the signing secret used to verify the Moneybird-Signature header on incoming deliveries, and it is only returned once. Store it in your secret manager immediately. See Verifying signatures. The response also includes a token, which you can optionally compare to webhook_token in incoming payloads as a secondary check.

Alternative: subscribe to event groups

If you prefer to receive all state changes (paid, late, open, etc.) and filter client-side:

TerminalCode
curl -X POST "https://moneybird.com/api/v2/{ADMINISTRATION_ID}/webhooks.json" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer {ACCESS_TOKEN}" \ -d '{ "url": "https://example.com/webhooks/moneybird", "enabled_events": [ "sales_invoice_state_changed", "external_sales_invoice_state_changed" ] }'

List existing webhooks (useful for retrieving the stored token or debugging delivery results):

TerminalCode
curl -X GET "https://moneybird.com/api/v2/{ADMINISTRATION_ID}/webhooks.json" \ -H "Authorization: Bearer {ACCESS_TOKEN}"

2. Handle incoming webhook deliveries

Your endpoint will receive a JSON payload. At minimum:

  • Always return HTTP 200 OK quickly.
  • Use the Idempotency-Key header to avoid double-processing.
  • Verify the Moneybird-Signature header against your stored signing secret — see Verifying signatures. This is the recommended authenticity check.
  • Optionally, also compare the webhook_token in the payload against the token you stored at registration time.
  • Check action and proceed only for the payment-related events you care about (e.g., sales_invoice_state_changed_to_paid).

See the full example body in Webhooks: Payload. Key fields:

  • action: the event name that triggered the delivery
  • entity_type: SalesInvoice or ExternalSalesInvoice
  • entity_id: the resource ID in Moneybird

3. Update your system

For a reliable workflow, fetch the current invoice state before updating your order:

TerminalCode
# For SalesInvoice curl -X GET "https://moneybird.com/api/v2/{ADMINISTRATION_ID}/sales_invoices/{SALES_INVOICE_ID}.json" \ -H "Authorization: Bearer {ACCESS_TOKEN}" # For ExternalSalesInvoice curl -X GET "https://moneybird.com/api/v2/{ADMINISTRATION_ID}/external_sales_invoices/{EXTERNAL_SALES_INVOICE_ID}.json" \ -H "Authorization: Bearer {ACCESS_TOKEN}"

If the state is paid, mark the corresponding order as paid in your system. If you subscribed to payment_registered, you can also reflect partial payments.

4. Monitor and troubleshoot

  • On registration, Moneybird calls your URL and expects HTTP 200. If it fails, delivery will be retried with backoff.
  • Use the Webhooks API to inspect last_http_status and last_http_body for each webhook.
  • If you need to change subscriptions, delete and recreate the webhook with updated enabled_events.

Next steps

Last modified on