> ## Documentation Index
> Fetch the complete documentation index at: https://funnelfox.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Subscription engine webhook events

> Handle subscription engine webhook events in FunnelFox. Event types, payload schemas, and integration examples for billing.

## How Webhooks work

When an event occurs in FunnelFox Billing, FunnelFox Billing sends an HTTP POST request to your configured endpoint with a JSON payload containing event details. The same event is also recorded and displayed in the Support Tool for visibility and troubleshooting.

There are two webhook event flows in FunnelFox Billing:

**Events triggered by customer actions**

```mermaid theme={null}
sequenceDiagram
autonumber
participant User
participant FunnelFoxBilling as FunnelFox Billing
participant SupportTool as Support Tool
participant YourServer as Your Server

User->>FunnelFoxBilling: Purchases subscription
FunnelFoxBilling->>YourServer: POST webhook event
YourServer->>YourServer: Process event
YourServer-->>FunnelFoxBilling: 200 OK
FunnelFoxBilling->>SupportTool: Display event in Support Tool
```

**Events triggered by your team in the Support Tool**

```mermaid theme={null}
sequenceDiagram
autonumber
participant SupportTool as Support Tool
participant FunnelFoxBilling as FunnelFox Billing
participant YourServer as Your Server

SupportTool->>FunnelFoxBilling: Refund subscription
FunnelFoxBilling->>YourServer: POST webhook event
YourServer->>YourServer: Process event
YourServer-->>FunnelFoxBilling: 200 OK
FunnelFoxBilling->>SupportTool: Display event in Support Tool
```

## Get started

<Steps>
  <Step title="Add your webhook URL">
    Go to **Settings** of your FunnelFox Billing dashboard and paste your endpoint into **Webhook url**.

    Click **Submit**.

    <Tip>You can include query parameters in the URL for example, to pass an environment.</Tip>

    <Frame>
      <img src="https://mintcdn.com/funnelfox/--3YwQ0xf8y3cVkV/assets/webhook-url.png?fit=max&auto=format&n=--3YwQ0xf8y3cVkV&q=85&s=b1b34e6a7d159744331b54e3b397374c" width="1621" height="686" data-path="assets/webhook-url.png" />
    </Frame>
  </Step>

  <Step title="(Optional) Turn on signatures">
    Add a secret in **Webhook signing\_secret** to enable signature verification.

    Learn about [verification](/develop/webhooks-billing#verification).

    <Frame>
      <img src="https://mintcdn.com/funnelfox/--3YwQ0xf8y3cVkV/assets/webhook-signature.png?fit=max&auto=format&n=--3YwQ0xf8y3cVkV&q=85&s=b302dd787e274326fac80a52f41de263" width="1621" height="686" data-path="assets/webhook-signature.png" />
    </Frame>
  </Step>

  <Step title="Handle events">
    Parse the JSON payload and return a **2xx** response (for example `200`) to acknowledge it.
  </Step>

  <Step title="Deduplicate deliveries">
    Webhooks may be retried. Use `event_timestamp` from the payload as a unique key to detect and ignore duplicate events.
  </Step>

  <Step title="(Optional) Add additional URLs">
    Use additional fields, such as **Webhook url (2)**, if you want to send webhooks to multiple destinations, for example production and sandbox.

    <Frame>
      <img src="https://mintcdn.com/funnelfox/--3YwQ0xf8y3cVkV/assets/webhook-additional.png?fit=max&auto=format&n=--3YwQ0xf8y3cVkV&q=85&s=ffa264568b88b8fb11b7de0ccbe1a046" width="1619" height="433" data-path="assets/webhook-additional.png" />
    </Frame>
  </Step>
</Steps>

## Event types

FunnelFox Billing sends webhooks for these events:

<CardGroup cols={2}>
  <Card title="Order events" icon="credit-card">
    Subtypes:

    * `settled` - Payment completed successfully
    * `declined` - Payment failed or was rejected
  </Card>

  <Card title="Subscription events" icon="rotate">
    Subtypes:

    * `starting_trial` - Trial period starts
    * `convertion` - Trial converts to paid subscription
    * `renewing` - Subscription renews (regular charge)
    * `unsubscription` - User cancels subscription (auto-renewal disabled)
    * `planning_postponed_subscription` - Subscription with **UPCOMING** status scheduled to start when **delayed\_start** migration is used
    * `pausing` - Subscription paused
    * `defering` - Next charge date postponed
    * `resuming` - Paused subscription resumes
    * `recovering_autorenew` - Auto-renewal restored after failure
    * `expiration` - Subscription expired
    * `unknown` - Unknown or unclassified event
    * `start_grace` - Grace period starts after failed charge
    * `start_retry` - Retry attempts start without grace period
    * `finish_grace` - Grace period ends
    * `recovering` - Recovered from grace/retry state
  </Card>

  <Card title="One-off events" icon="badge-check">
    Subtypes:

    * `granted` - Access granted
    * `revoked` - Access revoked
  </Card>

  <Card title="Refund events" icon="rotate-left">
    `refund` - Sent when a refund is completed for an order.
  </Card>

  <Card title="User events" icon="user">
    Subtypes:

    * `update_email` - User's email address was updated
  </Card>

  <Card title="Dispute events" icon="gavel">
    Subtypes:

    * `opened` - A dispute was registered for an order
  </Card>
</CardGroup>

<Tip>
  All events include the full state of related objects (subscription, order, user) in the payload, allowing you to sync your system without additional API calls.
</Tip>

See the [FunnelFox Billing webhook reference](/api-reference/webhook-reference/order) for complete payload schemas.

## Verification

FunnelFox Billing supports webhook signature verification to ensure requests are authentic.

To enable signature verification:

1. Go to **Settings** in your FunnelFox Billing dashboard.
2. Add a secret key in the **Webhook signing\_secret** field.
3. Click **Submit**.

FunnelFox Billing will include an `ff-webhook-signature` header with each webhook request containing an HMAC SHA-256 signature of the payload.

Optionally, you can verify the signature by computing the HMAC SHA-256 hash of the raw request body using your secret key and comparing it to the received signature. For example:

```python theme={null}
import hmac
import hashlib

def verify_signature(payload: str, secret: str, received_signature: str) -> bool:
    expected_signature = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected_signature, received_signature)
```

## Retry logic

If your endpoint fails to respond with a 2xx status code (for example, server downtime or errors), FunnelFox Billing automatically retries delivery up to **6 times** with exponential backoff.

### Retry schedule

<Tip>The retry schedule is configurable per merchant.</Tip>

FunnelFox Billing uses the following retry intervals (in seconds):

```
[8, 64, 512, 4096, 32768, 262144]
```

This results in approximately:

* Attempt 1: \~8 seconds
* Attempt 2: \~1 minute
* Attempt 3: \~8.5 minutes
* Attempt 4: \~1.1 hours
* Attempt 5: \~9 hours
* Attempt 6: \~72 hours (3 days)

<Info>
  Delivery is considered successful when your endpoint returns any HTTP 2xx status code. Retries continue until success or the maximum number of attempts is reached.
</Info>

### Failed deliveries

You can view all failed webhook deliveries and their retry details in the **Webhook Events** section of any **User information** page in the Support Tool.

<Frame>
  <img src="https://mintcdn.com/funnelfox/lBIs_N0f7r5ZD3Hj/assets/webhook-fail.png?fit=max&auto=format&n=lBIs_N0f7r5ZD3Hj&q=85&s=8f9c155d4d83d166acc3d5b8a2bc55a3" alt="Failed webhook deliveries shown in Support Tool" width="1441" height="401" data-path="assets/webhook-fail.png" />
</Frame>

## Rate limits

<Callout icon="rocket" color="#e18535">Detailed documentation is coming soon!</Callout>
