Webhooks

Webhooks

Set up webhooks to receive real-time notifications when events occur in your Phasio account

Webhooks allow you to receive automated HTTP notifications when specific events happen in your Phasio account. When an event is triggered, Phasio sends an encrypted POST request to the URL you provide, letting you integrate with external systems such as ERPs, CRMs, or custom automation.

Setting up a webhook

  1. Navigate to Developers from the main sidebar.
  2. Click
  3. Select a Trigger — the event type that should fire the webhook.
  4. Enter the URL of the endpoint that should receive the notification. The URL must use https:// and point to a valid, publicly-reachable domain. Private, loopback, and link-local addresses are rejected.
  5. Click Add to save the webhook.

Once created, Phasio generates a unique secret for the webhook — a Base64 URL-safe encoded AES-256 encryption key. This secret is used to both encrypt the webhook payload and sign the request so your endpoint can verify authenticity and decrypt the data.

Copying the secret

  1. In the webhooks table, open the actions menu (⋯) for the webhook.
  2. Click Copy Secret to copy the secret to your clipboard.

Important: Treat the secret like a password. Store it securely and never expose it in client-side code or public repositories.

Available event types

Each webhook is configured for a single event type. The following events are available:

Event TypeTriggerDescription
Order CreatedORDERFires when a new order is created or committed.
Order UpdatedORDER_UPDATEDFires when an order's details, status, payment status, or Kanban column changes.
Quote ConvertedQUOTE_CONVERTEDFires when a quote is accepted or paid, converting it into a confirmed order.
Customer Organisation CreatedCUSTOMER_ORGANISATION_CREATEDFires when a new customer organisation is created.
Customer Organisation UpdatedCUSTOMER_ORGANISATION_UPDATEDFires when a customer organisation's details are modified.
Part Specification CreatedSPECIFICATION_CREATEDFires when a new part specification is created.

See the individual event type pages for detailed payload schemas and trigger conditions.

Request format

When a webhook fires, Phasio sends an HTTP POST request to your endpoint with the following structure:

Headers

HeaderDescription
Content-Typeapplication/json
X-Phasio-SignatureHex-encoded HMAC-SHA256 signature of the encrypted payload string, computed using the UTF-8 bytes of your secret as the HMAC key.

Body

{
  "payload": "<Base64-encoded encrypted string>"
}

The payload value is the JSON event data encrypted with AES-256-GCM, then Base64 URL-safe encoded. Your secret (a Base64 URL-safe encoded AES-256 key) is required to both verify the signature and decrypt the payload.

Delivery behaviour

  • Webhooks are delivered asynchronously — Phasio does not wait for your endpoint to respond before continuing processing.
  • Requests have a 5-second timeout. If your endpoint does not respond within 5 seconds, the delivery is considered failed.
  • Failed deliveries are not retried. Ensure your endpoint is reliable and responds quickly.

Verifying and decrypting the payload

To read the event data, your endpoint must:

  1. Verify the signature — compute HMAC-SHA256 over the raw payload string, using the UTF-8 bytes of your secret as the HMAC key. Compare the hex-encoded result to the X-Phasio-Signature header. Reject the request if they don't match.
  2. Decrypt the payload — Base64 URL-safe decode the payload string to get the raw bytes. The first 12 bytes are the initialization vector (IV), followed by the AES-256-GCM ciphertext and authentication tag (128-bit). Decrypt using the Base64-decoded secret as the AES key.

Note the distinction: the HMAC key is the secret string's raw UTF-8 bytes, while the AES key is the Base64-decoded bytes of the secret.

Example (Node.js)

import { createDecipheriv, createHmac, timingSafeEqual } from 'node:crypto'

function verify(payload, signature, secret) {
  const expected = createHmac('sha256', secret).update(payload).digest()
  return timingSafeEqual(expected, Buffer.from(signature, 'hex'))
}

function decrypt(payload, secret) {
  const key = Buffer.from(secret, 'base64url')
  const data = Buffer.from(payload, 'base64url')

  const decipher = createDecipheriv('aes-256-gcm', key, data.subarray(0, 12))
  decipher.setAuthTag(data.subarray(-16))

  return Buffer.concat([
    decipher.update(data.subarray(12, -16)),
    decipher.final(),
  ]).toString()
}

Usage in a request handler:

const { payload } = req.body
const signature = req.headers['x-phasio-signature']

if (!verify(payload, signature, process.env.WEBHOOK_SECRET)) {
  return res.status(401).end()
}

const event = JSON.parse(decrypt(payload, process.env.WEBHOOK_SECRET))

Deleting a webhook

  1. In the webhooks table, open the actions menu (⋯) for the webhook.
  2. Click Delete to remove the webhook. Phasio will stop sending requests to that endpoint immediately.

Last updated on