Outbound Webhooks

Outbound webhooks allow your agency to receive real-time notifications whenever key events occur inside your DashboardFox account — such as a new workspace being created, a trial expiring, or a subscription payment failing. Instead of polling the platform for changes, your external systems (Pabbly, Zapier, Make, or your own application) are notified automatically the moment something happens.

Each webhook sends an HTTP POST request containing a JSON payload to a URL you configure. You can set up as many endpoints as you need, each with its own URL, event subscriptions, and optional security signature.


How It Works

  1. You configure an endpoint URL and choose which events to subscribe to.

  2. When a subscribed event occurs, DashboardFox sends an HTTP POST to your URL within seconds.

  3. Your receiving application processes the payload and takes action — creating a record, sending an email, triggering a workflow, etc.

  4. DashboardFox logs every delivery attempt. If your endpoint returns an error, it will retry automatically (see Retry Behaviour below).


Finding the Webhooks Settings

Webhooks are managed from your Agency settings panel:

  1. Log in as an Agency Owner.

  2. Click your agency name in the top navigation to open Agency Settings.

  3. Select the Webhooks tab.

Note: Only Agency Owners can create, edit, or delete webhook endpoints. Billing Admins and Members cannot access this tab.


Creating a Webhook Endpoint

  1. Click Add in the top-right corner of the endpoint list.

  2. Fill in the Name field — this is just a label for your reference (e.g. "Pabbly — New Workspace").

  3. Enter your Endpoint URL. This must be an HTTPS address. HTTP endpoints are not accepted.

  4. Optionally enter a Signing Secret (see Signature Verification below). If provided, you will only be shown this value once — copy it immediately.

  5. Under Events to Subscribe, check each event type you want this endpoint to receive.

  6. Click Create. Your new endpoint will appear in the list on the left.

Tip: You can create multiple endpoints — for example, one pointed at Pabbly for workspace events and another pointed at your own API for billing events.


Editing an Endpoint

Click any endpoint in the left panel to open its settings on the right. You can update the name, URL, and event subscriptions at any time, then click Save.

Changing the signing secret: The secret cannot be edited directly after creation. Click Regenerate to generate a new one. The new secret is shown once — update your receiving application before navigating away.


Enabling and Disabling an Endpoint

Each endpoint has a toggle switch in the endpoint list. Flipping it off pauses all deliveries to that endpoint without deleting it. Toggle it back on at any time to resume.


Deleting an Endpoint

Select the endpoint, then click Delete in the top-right of the editor panel. You will be asked to confirm. Deletion is permanent and will remove all delivery history for that endpoint.


Testing an Endpoint

With an endpoint selected, click the Test button. DashboardFox will send a sample payload for each of the endpoint's subscribed events, with the "test": true flag set in the envelope. The results are shown immediately and are also visible in the Delivery Log below the editor.

Tip: Use the Test button to verify your receiving application is reachable and parsing the payload correctly before going live.


Delivery Log

The delivery log shows the last 10 attempts for the selected endpoint. Each row displays:

  • Event type — which event triggered the delivery

  • HTTP status code — the response returned by your endpoint

  • Duration — how long your endpoint took to respond

  • Timestamp — when the attempt was made

  • Attempt number — 1 for the initial delivery, 2–4 for retries

Click any row to expand it and see the full payload that was sent and the response body your endpoint returned.


Retry Behaviour

If your endpoint returns a non-2xx status code or times out, DashboardFox will retry the delivery automatically:

Attempt

Delay After Previous Attempt

1 (initial)

Immediate

2

30 seconds

3

5 minutes

4

1 hour

After 4 attempts with no success, the delivery is marked as failed. No further retries will occur. Each attempt is logged individually in the Delivery Log.

Note: Your endpoint must respond within 10 seconds. Responses that take longer are treated as a timeout and counted as a failed attempt.


Signature Verification (Optional but Recommended)

If you configure a signing secret, every delivery will include two additional HTTP headers:

Header

Description

X-Webhook-Signature

HMAC-SHA256 signature of the request body, prefixed with sha256=

X-Webhook-Timestamp

Unix timestamp (milliseconds) when the request was sent

How to verify the signature

To confirm a delivery is genuinely from DashboardFox and has not been tampered with:

  1. Read the raw request body as a string (before any JSON parsing).

  2. Compute HMAC-SHA256 of the body string using your signing secret.

  3. Compare the result (prefixed with sha256=) against the value in X-Webhook-Signature.

  4. Optionally, check that X-Webhook-Timestamp is within an acceptable window (e.g. 5 minutes) to protect against replay attacks.

Example — Node.js

const crypto = require('crypto');
 
function verifyWebhook(rawBody, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody) // raw string, not parsed JSON
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}

Example — PHP

function verifyWebhook(string $rawBody, string $signature, string $secret): bool {
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
return hash_equals($expected, $signature);
}

Payload Envelope

Every event — regardless of type — uses the same outer envelope:

{
"event": "workspace.created",
"fired_at": "2026-02-24T17:00:00Z",
"test": false,
"agency_id": "agency-abc123",
"data": {
...event-specific fields...
}
}

Field

Type

Description

event

string

The event slug that triggered this delivery

fired_at

string

ISO 8601 UTC timestamp of when the event fired

test

boolean

true only when sent via the Test button — ignore for production logic

agency_id

string

Your agency identifier

data

object

Event-specific payload — see reference below


Event Reference

workspace.created

Fired when a new workspace is created under your agency.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"owner_email": "jane@acme.com",
"tier_name": "professional",
"agency_id": "agency-abc123"
}

workspace.deleted

Fired when a workspace is permanently deleted.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"owner_email": "jane@acme.com",
"tier_name": "professional",
"agency_id": "agency-abc123"
}

workspace.suspended

Fired when a workspace is suspended — typically due to a payment issue.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"owner_email": "jane@acme.com",
"tier_name": "professional",
"agency_id": "agency-abc123"
}

workspace.reactivated

Fired when a suspended workspace is reactivated.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"owner_email": "jane@acme.com",
"tier_name": "professional",
"agency_id": "agency-abc123"
}

workspace.transfer_completed

Fired when an ownership transfer of a workspace is accepted and completed.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"from_email": "old-owner@acme.com",
"to_email": "new-owner@acme.com",
"agency_id": "agency-abc123"
}

workspace.trial_started

Fired when a new workspace enters its trial period.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"owner_email": "jane@acme.com",
"trial_ends_at": "2026-03-17T00:00:00Z",
"agency_id": "agency-abc123"
}

workspace.trial_expiring

Fired when a trial is 3 days away from expiring. Useful for sending reminder emails or prompting upgrade flows. This event fires once per workspace per day while the 3-day window applies.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"owner_email": "jane@acme.com",
"trial_ends_at": "2026-03-17T00:00:00Z",
"agency_id": "agency-abc123"
}

workspace.trial_expired

Fired when a trial period ends and the workspace has not been converted to a paid subscription.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"owner_email": "jane@acme.com",
"trial_ends_at": "2026-03-17T00:00:00Z",
"agency_id": "agency-abc123"
}

subscription.upgraded

Fired when a workspace moves to a higher subscription tier.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"owner_email": "jane@acme.com",
"old_tier": "Starter",
"new_tier": "Professional",
"billing_cycle": "monthly",
"agency_id": "agency-abc123"
}

subscription.downgraded

Fired when a workspace moves to a lower subscription tier.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"owner_email": "jane@acme.com",
"old_tier": "Professional",
"new_tier": "Starter",
"billing_cycle": "monthly",
"agency_id": "agency-abc123"
}

subscription.cancelled

Fired when a subscription is cancelled. The workspace will continue to function until the end of the current billing period.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"owner_email": "jane@acme.com",
"tier_name": "professional",
"agency_id": "agency-abc123"
}

subscription.reactivated

Fired when a previously cancelled subscription is reactivated before it fully lapses.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"owner_email": "jane@acme.com",
"tier_name": "professional",
"agency_id": "agency-abc123"
}

subscription.payment_failed

Fired when a subscription payment attempt fails. The retry_count field indicates how many times payment has been attempted for this billing cycle.

"data": {
"workspace_id": 1042,
"workspace_name": "Acme Corp",
"owner_email": "jane@acme.com",
"amount": 49.00,
"currency": "USD",
"invoice_id": "INV-00892",
"retry_count": 1,
"agency_id": "agency-abc123"
}

user.registered

Fired when a new user completes registration under your agency.

"data": {
"user_id": 204,
"user_email": "jane@acme.com",
"user_name": "Jane Smith",
"agency_id": "agency-abc123"
}

user.deleted

Fired when a user exercises their right to deletion and their account is removed.

"data": {
"user_id": 204,
"user_email": "jane@acme.com",
"user_name": "Jane Smith",
"agency_id": "agency-abc123"
}

team.member_invited

Fired when an agency owner invites someone to join the agency team, or directly adds an existing user.

"data": {
"agency_id": "agency-abc123",
"agency_name": "My Agency",
"invitee_email": "colleague@acme.com",
"role": "member",
"invited_by_email": "owner@agency.com"
}

team.member_joined

Fired when an invited user accepts their invitation and joins the agency team.

"data": {
"agency_id": "agency-abc123",
"agency_name": "My Agency",
"invitee_email": "colleague@acme.com",
"role": "member",
"invited_by_email": "owner@agency.com"
}

team.member_removed

Fired when a team member is removed from the agency.

"data": {
"agency_id": "agency-abc123",
"agency_name": "My Agency",
"invitee_email": "colleague@acme.com",
"role": "member",
"invited_by_email": "owner@agency.com"
}

Event Quick Reference

Event

When it fires

workspace.created

A new workspace is created

workspace.deleted

A workspace is permanently deleted

workspace.suspended

A workspace is suspended

workspace.reactivated

A suspended workspace is reactivated

workspace.transfer_completed

A workspace ownership transfer completes

workspace.trial_started

A new workspace enters its trial period

workspace.trial_expiring

A trial is 3 days from expiring (fires daily)

workspace.trial_expired

A trial period ends without conversion

subscription.upgraded

A workspace moves to a higher tier

subscription.downgraded

A workspace moves to a lower tier

subscription.cancelled

A subscription is cancelled

subscription.reactivated

A cancelled subscription is reactivated

subscription.payment_failed

A payment attempt fails

user.registered

A new user registers

user.deleted

A user account is deleted

team.member_invited

A team member is invited or directly added

team.member_joined

An invited team member accepts their invite

team.member_removed

A team member is removed from the agency


Common Use Cases

Goal

Events to subscribe

Sync new customers to your CRM

workspace.created, user.registered

Automate trial nurture emails

workspace.trial_started, workspace.trial_expiring, workspace.trial_expired

Trigger dunning workflows

subscription.payment_failed, subscription.cancelled

Update billing records on plan changes

subscription.upgraded, subscription.downgraded, subscription.reactivated

Audit team access in your own system

team.member_invited, team.member_joined, team.member_removed

Deprovision accounts on deletion

workspace.deleted, user.deleted


Tips & Best Practices

Always respond quickly. Return a 200 status as soon as you receive the request, then process the payload asynchronously. If your handler takes longer than 10 seconds, DashboardFox will treat it as a timeout and retry.

Check the test flag. Deliveries sent via the Test button have "test": true set. Filter these out in your production logic if needed.

Use signature verification. Always configure a signing secret and verify the X-Webhook-Signature header to confirm deliveries are genuinely from DashboardFox.

Make your handler idempotent. Due to retries, your endpoint may occasionally receive the same event more than once. Design your logic to handle duplicate deliveries gracefully.

Use the delivery log for debugging. If your automation isn't triggering as expected, open the endpoint in the Webhooks tab and check the delivery log. The full request payload and your endpoint's response body are both visible there.