Olympus PayDevelopers

Arubis webhooks

Arubis sends a signed HTTPS request to your endpoint when a document, contact or lead changes. Events are queued and sent in batches, so expect each one within about 15 minutes of the change.

Add an endpoint#

  1. In Arubis, open Settings, API and webhooks and choose Add endpoint.
  2. Enter an https:// URL that resolves to a public address, and choose the events to receive.
  3. Copy the signing secret. It starts with whsec_ and is shown once.

Use Send test to queue a test.ping event straight away. The endpoint list shows the last delivery, its HTTP status and recent attempts.

Events#

EventSent when
invoice.createdAn invoice was created, in Arubis or through the API
invoice.issuedAn invoice was issued and posted to the books
invoice.paidAn invoice was paid in full
invoice.voidedAn invoice was voided
quote.acceptedA customer accepted a quote
quote.declinedA customer declined a quote
bill.createdA bill was entered
bill.approvedA bill was approved
bill.paidA bill was paid in full
contact.createdA customer or supplier was added
lead.wonA lead was marked won
test.pingYou chose Send test

The request#

POST /arubis/webhooks HTTP/1.1
Content-Type: application/json
User-Agent: Arubis-Webhooks/1
X-Arubis-Event: invoice.paid
X-Arubis-Delivery: 0c9b3c4e-6a55-4d0e-8a4f-1f3f2b7d9e10
X-Arubis-Signature: t=1792040000,v1=9f2c...b71a
{
  "id": "5e1d2c3b-4a59-4f68-8e7d-6c5b4a392817",
  "type": "invoice.paid",
  "created_at": "2026-10-15T09:12:44.103Z",
  "org_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "data": {
    "id": "7a0c5c1e-2f61-4c0e-a1f0-0d5c9d1b2e33",
    "kind": "invoice",
    "number": "INV-0042",
    "status": "paid",
    "contact_id": "3d6f8f8a-0b8e-4f5e-9c2b-6c7a0e0d41aa",
    "date": "2026-10-01",
    "due_date": "2026-10-31",
    "currency": "BWP",
    "subtotal": 900.00,
    "tax_total": 126.00,
    "total": 1026.00,
    "amount_paid": 1026.00,
    "reference": "Order 1001"
  }
}

Document events carry the fields shown above. contact.created carries id, name, email, is_customer, is_supplier and currency. lead.won carries id, name, company, value, currency, contact_id and quote_id.

The payload is a summary. Fetch the full record from the API when you need the lines.

Verify the signature#

X-Arubis-Signature holds a Unix timestamp t and v1, the hex HMAC-SHA256 of <t>.<raw body> keyed with your signing secret.

  1. Read the raw request body before parsing it.
  2. Compute the HMAC over t + "." + body and compare it to v1 in constant time.
  3. Reject the request if t is more than five minutes from your clock.

import crypto from 'node:crypto'

export function verifyArubis(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')))
  const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex')
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300
  return fresh && expected.length === parts.v1.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
}

Respond, retries and duplicates#

  • Answer with any 2xx within 5 seconds. Do the work afterwards, for example on a queue.
  • Any other answer, or no answer, is a failure. Arubis retries with growing gaps, up to 8 attempts, then marks the delivery failed.
  • After 20 failures in a row the endpoint is switched off. Switch it back on in Settings once it is fixed.
  • A delivery can arrive more than once. Use X-Arubis-Delivery or the payload id to skip ones you have already handled.
  • Events can arrive out of order. Compare created_at, or fetch the record, before acting.