# Affiliate webhook payload

> The JSON BCL posts to your webhook URL when an affiliate joins your programme or a referral is approved, field by field.
>
> Source: https://docs.bcl.my/webhook-affiliate/

Affiliate webhooks tell your own system when someone joins your affiliate programme or when a referral is approved. BCL sends an HTTP `POST` with a JSON body to one URL you set for the whole programme. This page lists every field.

For the full BCL API, see the [API reference](https://bcl.my/docs/api).

## Set your webhook URL

Affiliate webhooks are set once for your programme, not per form:

1. Go to **Affiliate** > **Settings**.
2. Open the **Webhook Settings** tab.
3. Turn on **Enable Webhook**.
4. Enter your **Webhook URL**.
5. Tick the events you want: **Affiliate Joined**, **Referral Approved** or **Payout Request**.
6. Click **Save Webhook Settings**.

> **Caution**
> **Payout Request** appears in the list, but the current version of BCL does not send it. Do not build a process that depends on it yet.

## Events

The body is a flat JSON object with no `data` wrapper. The `event` key tells you which event it is:

| `event` | When BCL sends it |
| --- | --- |
| `affiliate_joined` | Someone joins your affiliate programme, including when you still need to approve them. |
| `referral_approved` | A referral is approved and its commission confirmed. |
| `payout_request` | Listed, but not sent at the moment. |

Every payload has `event`, `team_id`, `team_name`, an `affiliate` object and a `timestamp`.

## Affiliate joined

This is an `affiliate_joined` request. The values are made up.

```json
{
  "event": "affiliate_joined",
  "team_id": "9ce445a9-21f4-4e2a-b6fa-226dbb2a14f3",
  "team_name": "Contoh Trading",
  "affiliate": {
    "id": 12,
    "name": "Siti binti Ahmad",
    "email": "siti@example.com",
    "phone": "+60198765432"
  },
  "timestamp": "2026-09-27 12:46:53 +08"
}
```

The fields mean:

| Field | Type | Meaning |
| --- | --- | --- |
| `event` | string | `affiliate_joined`. |
| `team_id` | string | Your BCL account ID. |
| `team_name` | string | Your business name in BCL. |
| `affiliate.id` | number | The affiliate's ID. Matches `affiliate_id` in the payment form webhook. |
| `affiliate.name`, `affiliate.email`, `affiliate.phone` | string | The affiliate's details. |
| `timestamp` | string | When BCL sent it, `YYYY-MM-DD HH:MM:SS +08` (Malaysia time). |

## Referral approved

A `referral_approved` request adds a `referral` object:

```json
{
  "event": "referral_approved",
  "team_id": "9ce445a9-21f4-4e2a-b6fa-226dbb2a14f3",
  "team_name": "Contoh Trading",
  "affiliate": {
    "id": 12,
    "name": "Siti binti Ahmad",
    "email": "siti@example.com",
    "phone": "+60198765432"
  },
  "referral": {
    "id": 82,
    "form_title": "Online Cooking Class",
    "transaction_id": "01jnszhdng1z4mxqwsfqd27k5w",
    "order_number": "LINK-05912",
    "amount": "100.00",
    "commission_amount": "10.00",
    "status": "approved",
    "referral_source": "direct",
    "ip_address": "203.0.113.10",
    "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
  },
  "timestamp": "2026-09-27 12:18:27 +08"
}
```

The `referral` fields mean:

| Field | Type | Meaning |
| --- | --- | --- |
| `id` | number | Referral ID. Matches `affiliate_data.referral_id` in the payment form webhook. |
| `form_title` | string or null | Title of the payment form the sale came from. Null if the referral is not linked to a payment form. |
| `transaction_id` | string | Internal ID of the sale. |
| `order_number` | string | BCL order number of the sale. |
| `amount` | string | Sale amount the commission is based on. |
| `commission_amount` | string | Commission earned. |
| `status` | string | Referral status, `approved`. |
| `referral_source` | string | How the buyer arrived, for example `direct`. |
| `ip_address`, `user_agent` | string | The buyer's IP address and browser when the referral was recorded. |

## Payout request

For reference, the `payout_request` payload that BCL has built but does not send yet adds a `payout_request` object with `id`, `total_amount`, `status`, `requested_at`, `referral_count` and a `referrals` list. Each referral has `id`, `order_number`, `commission_amount`, `status` and `transaction_id`.

## Changes from the old sample

The payload shapes match the old sample. The difference is that BCL does not currently send `payout_request`, even when it is ticked.

## Check that a webhook is genuine

BCL does not sign webhooks. There is no signature header or shared secret. To stay safe, use a hard-to-guess URL, confirm the sale through the [BCL API](https://bcl.my/docs/api) before paying commission, and make your handler safe to run twice.

BCL sends each event once. Any 2xx response counts as delivered. Every attempt is listed under **Tools** > **Webhook Logs**, where you can **Resend** it.

## Common issues

### Can I send affiliate webhooks to more than one URL?

No. The affiliate webhook takes one Webhook URL for the whole programme. If several systems need the data, point it at one endpoint that forwards it.

### How do I find which sale a referral_approved webhook belongs to?

Use referral.order_number. It is the BCL order number, the same value as record_id in the payment form webhook (/webhook-payment-form/).

### My endpoint was down when an affiliate joined. Can I get the webhook again?

Yes. Go to Tools > Webhook Logs, find the failed row and click Resend in its menu.
