Information in a Moneybird account is constantly changing. If you want to perform actions based on these changes, webhooks help you to achieve this. Instead of querying the API at a certain interval, Moneybird will notify you about changes to information in the bookkeeping.


Webhooks are useful in a broad range of situations. When the state of a sales invoice changes, Moneybird will perform an HTTP request to the URL you provide. Based on the payload of the request, you can determine which action you need to perform.

How it works:

  • You need a URL that Moneybird can call to deliver the payload. The Moneybird servers must be able to access this URL.
  • You can add HTTP basic authentication or other token authentication in the URL, as long as the URL stays valid.
  • Your URL always needs to respond with a 200 HTTP status. Upon registration this is checked.
  • When your URL responds with another HTTP status code, Moneybird will retry to deliver the push 10 times. The time interval between retries is gradually extended.
  • After each push, Moneybird will store the last HTTP status code and HTTP body. Using the webhooks API, you can retrieve this information for debugging purposes.

You can register as many webhooks as required in an administration. Registration is done by sending a POST request to the webhooks API.


The URL in a webhook will be called by using a `POST` HTTP request. The HTTP body contains a JSON payload with the following structure:

  "administration_id": "116015326147118082",
  "webhook_id": "116010948233266179",
  "entity_type": "SalesInvoice",
  "entity_id": "116015245643744263",
  "state": "late",
  "entity": {
    "id": "116015245643744263",
    "contact_id": "116015245567198212",
    "contact": {
      "id": "116015245567198212",
      "company_name": "Foobar Holding B.V.",
      "firstname": "",
      "lastname": "",
      "attention": "",
      "address1": "Hoofdstraat 12",
      "address2": "",
      "zipcode": "1234AB",
      "city": "Amsterdam",
      "country": "NL",
      "email": "",
      "phone": "",
      "send_method": "email",
      "customer_id": "1",
      "tax_number": "",
      "chamber_of_commerce": "",
      "bank_account": "",
      "send_invoices_to_attention": "",
      "send_invoices_to_email": "",
      "send_estimates_to_attention": "",
      "send_estimates_to_email": "",
      "sepa_active": false,
      "sepa_iban": "",
      "sepa_bic": "",
      "sepa_mandate_id": "",
      "sepa_mandate_date": null,
      "created_at": "2015-02-25T10:39:41.615Z",
      "updated_at": "2015-02-25T10:39:41.615Z",
      "notes": [

      "custom_fields": [

    "invoice_id": null,
    "workflow_id": "116015053116802148",
    "document_style_id": "116015053175522406",
    "state": "late",
    "invoice_date": null,
    "payment_conditions": "We verzoeken u vriendelijk het bovenstaande bedrag van {document.total_price} voor {document.due_date} te voldoen op onze bankrekening onder vermelding van het factuurnummer {document.invoice_id}. Voor vragen kunt u contact opnemen per e-mail.",
    "reference": "Project X",
    "language": "nl",
    "currency": "EUR",
    "discount": "0.0",
    "paid_at": null,
    "sent_at": null,
    "created_at": "2015-02-25T10:39:41.685Z",
    "updated_at": "2015-02-25T10:39:41.685Z",
    "details": [
        "id": "116015245648987144",
        "tax_rate_id": "116015052994118749",
        "ledger_account_id": "116015052938544219",
        "amount": "1 x",
        "description": "Project X",
        "price": "300.0",
        "row_order": 1,
        "total_price_excl_tax_with_discount": "300.0",
        "total_price_excl_tax_with_discount_base": "300.0",
        "tax_report_reference": [
        "created_at": "2015-02-25T10:39:41.693Z",
        "updated_at": "2015-02-25T10:39:41.693Z"
    "payments": [

    "custom_fields": [

    "notes": [

    "attachments": [


The entity attribute contains a representation of the entity equal to the JSON representation you get when requesting the entity using the API. The state attribute contains the new state of the entity that triggered the push. Notice that the state in the push and the state in the entity can differ. The state of the entity could have changed in the meantime and always contains the current state in the database.