> For the complete documentation index, see [llms.txt](https://docs.catfee.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.catfee.io/en/getting-started/webhook.md).

# Webhook

A developer guide to webhook payloads, delegation business types, version compatibility, response requirements, retries, and configuration.

{% hint style="info" %}
The current event protocol version is `20260918`, provided in the `X-EVENT-VERSION` header. This version adds `data.business_type` to delegation notifications to identify the associated service. `data.delegation_type` is deprecated but remains available for compatibility. New integrations should use `business_type`; existing integrations can follow the migration guidance below.
{% endhint %}

#### Overview

When an event occurs on the platform, CatFee will send an HTTP `POST` request to your configured callback address (`callbackUrl`).\
You need to:

1. Receive and parse the JSON data.
2. Identify the event type via the `X-EVENT-TYPE` header.
3. Return **HTTP 200** after successful processing.
4. Otherwise, the platform will retry according to its retry policy.

***

#### Configure the Callback URL

* **Location:** Go to **User Center → API Settings**.
* **Configuration:** Fill in `callbackUrl` and check the event types you want to subscribe to.
* **Protocol:** Both **HTTP** and **HTTPS** are supported.
* **Identification:** The event type is indicated by the request header `X-EVENT-TYPE`.
* **Note:** Dynamic subscription via API is **not supported**.

***

#### Request Headers

Each webhook request includes the following HTTP headers:

| Header Name       | Description                                  |
| ----------------- | -------------------------------------------- |
| `X-EVENT-ID`      | Unique event ID (idempotency key)            |
| `X-EVENT-TYPE`    | Event type (enum `EventType`)                |
| `X-EVENT-VERSION` | Event protocol version, currently `20260918` |

***

#### Event Structure (JSON)

The request body of a webhook is **JSON**, using **snake\_case** for top-level fields:

```json
{
  "event_type": "EVENT_BALANCE",
  "event_id": "aabbccdd-1122-3344-5566-77889900",
  "data": {}
}
```

`data` contains the event-specific payload. See the examples and event data definitions below for its fields.

**Event Types (EventType)**

Currently supported types:\
`EVENT_BALANCE`, `EVENT_TRON_MATE_SUBSCRIPTION`, `EVENT_DELEGATION`, `EVENT_ADDRESS_MONITOR`\
(If you receive an unknown type, record and ignore it.)

{% hint style="warning" %}
The balance event fields have been upgraded: `balance_type` has been replaced by `action_type`, and `billing_type` has been replaced by `billing_item_type`. Receivers must update their JSON deserialization models, field validation, and message templates accordingly.
{% endhint %}

**Example: Balance Change (EVENT\_BALANCE)**

```json
{
  "event_type": "EVENT_BALANCE",
  "event_id": "aabbccdd-1122-3344-5566-77889900",
  "data": {
    "action_type": "BALANCE_ACTION_RECHARGE",
    "billing_item_type": "UNKNOWN_BILLING_ITEM_TYPE",
    "coin_type": "USDT",
    "amount_sun": 1000000,
    "balance": 500000000,
    "balance_usdt": 2000000,
    "timestamp": 1760505600,
    "remark": "transfer in"
  }
}
```

**Example: TRON Mate Subscription (EVENT\_TRON\_MATE\_SUBSCRIPTION)**

```json
{
  "event_type": "EVENT_TRON_MATE_SUBSCRIPTION",
  "event_id": "22334455-6677-8899-aabb-ccddeeff",
  "data": {
    "payment_amount_sun": 5000000,
    "payment_timestamp": 1760505600,
    "subscribe_type": "SUBSCRIBE_PRO",
    "address": "TGxxx..."
  }
}
```

**Example: Delegation Confirmation (EVENT\_DELEGATION)**

```json
{
  "event_type": "EVENT_DELEGATION",
  "event_id": "delegation-event-id",
  "data": {
    "resource_type": "ENERGY",
    "business_type": "BUSINESS_HOUR_ENERGY",
    "delegation_type": "DELEGATION_NORMAL",
    "receiver": "TReceiver",
    "payment_amount_sun": 2000000,
    "payment_timestamp": 1761021630421,
    "duration": 60,
    "quantity": 65000,
    "staked_sun": 100000000,
    "delegation_hash": "delegation-hash",
    "delegation_timestamp": 1761021630421
  }
}
```

The address and transaction hash in this example are placeholders. In delegation events, `payment_timestamp` and `delegation_timestamp` are Unix timestamps in milliseconds, and `duration` is in minutes. Use the top-level `event_id` to identify the event; there is no separate `order_id` field inside `data`.

#### Delegation Business Types and Compatibility

| Field             | Purpose                                         | Integration guidance                                                |
| ----------------- | ----------------------------------------------- | ------------------------------------------------------------------- |
| `resource_type`   | The delivered resource: `ENERGY` or `BANDWIDTH` | Use it to distinguish Energy from Bandwidth                         |
| `business_type`   | The service associated with the delegation      | Use this string enum to route events by service in new integrations |
| `delegation_type` | The legacy delegation classification            | Deprecated; retained for compatibility with existing receivers      |

Common resource-related business types are listed below. The full enum is available in the `DelegationEventData` definition. This is a shared business classification; not every business type necessarily produces delegation events.

| `business_type`                  | Service                         |
| -------------------------------- | ------------------------------- |
| `BUSINESS_HOUR_ENERGY`           | Hourly Energy                   |
| `BUSINESS_TRON_MATE`             | TRON Mate                       |
| `BUSINESS_SEAMLESS_SERVICE`      | Seamless Energy                 |
| `BUSINESS_ENERGY_SUBLET`         | Energy Subleasing               |
| `BUSINESS_FLASH_SERVICE`         | Flash Refill                    |
| `BUSINESS_REALTIME_COLLECTION`   | Sweep Assist                    |
| `BUSINESS_ONE_ORDER_ONE_PAYMENT` | Transaction Handoff             |
| `UNKNOWN_BUSINESS_TYPE`          | Unspecified or unknown business |

For existing integrations:

1. Add `business_type` to your delegation event model. Allow it to be absent for compatibility with older notifications.
2. Gradually switch service routing to `business_type`. Combine it with `resource_type` when you also need to distinguish the delivered resource.
3. Keep parsing `delegation_type` until you have migrated your handling of older notifications. The fields represent different classifications and should not be treated as a one-to-one replacement.
4. Handle missing values, `UNKNOWN_BUSINESS_TYPE`, `UNRECOGNIZED`, and future enum values through a fallback path, and record the original payload. Do not assume an unknown business is Hourly Energy or reject an entire callback merely because it contains a new field.

This version includes both classification fields, but historical notifications may not have a specific business classification.

#### Business Types in Message Templates

Delegation notification templates can use `{{business_type}}` directly, without a `data.` prefix. For example, a Telegram message template can contain:

```json
{
  "chat_id": "YOUR_CHAT_ID",
  "text": "Business: {{business_type}}; Resource: {{resource_type}}; Receiver: {{receiver}}"
}
```

`{{business_type}}` renders the enum name, such as `BUSINESS_HOUR_ENERGY`. The existing `{{delegation_type}}` variable remains available, but new templates should use the business type. In the Webhook JSON payload, the corresponding path is `data.business_type`.

Delegation test notifications also include `business_type`, with the sample value `BUSINESS_HOUR_ENERGY`, so you can check payload parsing and template rendering.

### Event Data Definitions

## The BalanceEvent object

```json
{"openapi":"3.1.0","info":{"title":"Notifier API","version":"0.1#@BUILD_ID@"},"components":{"schemas":{"BalanceEvent":{"description":"Balance change event","properties":{"event_type":{"type":"string","description":"Event type","enum":["EVENT_UNKNOWN","EVENT_BALANCE","EVENT_TRON_MATE_SUBSCRIPTION","EVENT_DELEGATION","EVENT_ADDRESS_MONITOR","EVENT_TRON_MATE_HOST","EVENT_EMAIL_MESSAGE","EVENT_TELEGRAM_MESSAGE","EVENT_INTERNAL_MESSAGE","UNRECOGNIZED"]},"event_id":{"type":"string","description":"Order ID (idempotency key)"},"data":{"$ref":"#/components/schemas/BalanceEventData"}}},"BalanceEventData":{"description":"Account balance change details","properties":{"action_type":{"type":"string","description":"Balance change action","enum":["UNKNOWN_BALANCE_ACTION_TYPE","BALANCE_ACTION_RECHARGE","BALANCE_ACTION_WITHDRAW","BALANCE_ACTION_PAYMENT","BALANCE_ACTION_REFUND","BALANCE_ACTION_ADDITIONAL_PAYMENT","UNRECOGNIZED"]},"billing_item_type":{"type":"string","description":"Billing item","enum":["UNKNOWN_BILLING_ITEM_TYPE","BILLING_ITEM_HOUR_ENERGY","BILLING_ITEM_TRON_MATE_SUBSCRIPTION","BILLING_ITEM_TRON_MATE_ENERGY","BILLING_ITEM_TRON_MATE_BANDWIDTH","BILLING_ITEM_SEAMLESS_ENERGY","BILLING_ITEM_SEAMLESS_BANDWIDTH","BILLING_ITEM_ENERGY_SUBLET","BILLING_ITEM_FLASH_ENERGY","BILLING_ITEM_FLASH_BANDWIDTH","BILLING_ITEM_REALTIME_COLLECTION_ENERGY","BILLING_ITEM_REALTIME_COLLECTION_BANDWIDTH","BILLING_ITEM_TELEGRAM_PREMIUM","BILLING_ITEM_TELEGRAM_STARS","BILLING_ITEM_ONE_ORDER_ONE_PAYMENT_ENERGY","BILLING_ITEM_ONE_ORDER_ONE_PAYMENT_BANDWIDTH","BILLING_ITEM_TRON_NODE","BILLING_ITEM_ADDRESS_MONITOR_SUBSCRIPTION","BILLING_ITEM_ADDRESS_CHECK_SUBSCRIPTION","BILLING_ITEM_SWAP","BILLING_ITEM_STAKING_VAULT_MARGIN","UNRECOGNIZED"]},"coin_type":{"type":"string","description":"Currency","enum":["USDT","TRX","ETH","BTC","BNB","BUSD"]},"amount_sun":{"type":"integer","format":"int64","description":"Amount in sun"},"balance":{"type":"integer","format":"int64","description":"TRX balance"},"balance_usdt":{"type":"integer","format":"int64","description":"USDT balance"},"timestamp":{"type":"integer","format":"int64","description":"Timestamp"},"remark":{"type":"string","description":"Remarks"}}}}}}
```

## The DelegationEvent object

```json
{"openapi":"3.1.0","info":{"title":"Notifier API","version":"0.1#@BUILD_ID@"},"components":{"schemas":{"DelegationEvent":{"properties":{"event_type":{"type":"string","description":"Event type","enum":["EVENT_UNKNOWN","EVENT_BALANCE","EVENT_TRON_MATE_SUBSCRIPTION","EVENT_DELEGATION","EVENT_ADDRESS_MONITOR","EVENT_TRON_MATE_HOST","EVENT_EMAIL_MESSAGE","EVENT_TELEGRAM_MESSAGE","EVENT_INTERNAL_MESSAGE","UNRECOGNIZED"]},"event_id":{"type":"string","description":"Order ID (idempotency key)"},"data":{"$ref":"#/components/schemas/DelegationEventData"}}},"DelegationEventData":{"description":"Delegation details","properties":{"resource_type":{"type":"string","description":"Resource type: ENERGY | BANDWIDTH","enum":["ENERGY","BANDWIDTH","UNRECOGNIZED"]},"delegation_type":{"type":"string","description":"Deprecated delegation type, retained for compatibility with existing receivers; use business_type for new integrations","deprecated":true,"enum":["DELEGATION_UNKNOWN","DELEGATION_NORMAL","DELEGATION_MATE_SLOT","DELEGATION_MATE_REPLENISH","UNRECOGNIZED"]},"business_type":{"type":"string","description":"Business type (recommended); see the BusinessType enum for supported values","enum":["UNKNOWN_BUSINESS_TYPE","BUSINESS_HOUR_ENERGY","BUSINESS_TRON_MATE","BUSINESS_SEAMLESS_SERVICE","BUSINESS_ENERGY_SUBLET","BUSINESS_FLASH_SERVICE","BUSINESS_REALTIME_COLLECTION","BUSINESS_TELEGRAM_PREMIUM","BUSINESS_ONE_ORDER_ONE_PAYMENT","BUSINESS_TRON_NODE","BUSINESS_ADDRESS_MONITOR","BUSINESS_ADDRESS_CHECK","BUSINESS_SWAP","BUSINESS_STAKING_VAULT","UNRECOGNIZED"]},"receiver":{"type":"string","description":"Recipient address"},"payment_amount_sun":{"type":"integer","format":"int64","description":"Payment amount"},"payment_timestamp":{"type":"integer","format":"int64","description":"Payment time"},"duration":{"type":"integer","format":"int32","description":"Duration (minutes)"},"quantity":{"type":"integer","format":"int32","description":"Quantity"},"staked_sun":{"type":"integer","format":"int64","description":"Staked TRX amount"},"delegation_hash":{"type":"string","description":"Delegation hash"},"delegation_timestamp":{"type":"integer","format":"int64","description":"Delegation time"}}}}}}
```

## The TronMateSubscriptionEvent object

```json
{"openapi":"3.1.0","info":{"title":"Notifier API","version":"0.1#@BUILD_ID@"},"components":{"schemas":{"TronMateSubscriptionEvent":{"description":"Tron Mate subscription event","properties":{"event_type":{"type":"string","description":"Event type","enum":["EVENT_UNKNOWN","EVENT_BALANCE","EVENT_TRON_MATE_SUBSCRIPTION","EVENT_DELEGATION","EVENT_ADDRESS_MONITOR","EVENT_TRON_MATE_HOST","EVENT_EMAIL_MESSAGE","EVENT_TELEGRAM_MESSAGE","EVENT_INTERNAL_MESSAGE","UNRECOGNIZED"]},"event_id":{"type":"string","description":"Order ID (idempotency key)"},"data":{"$ref":"#/components/schemas/TronMateSubscriptionEventData"}}},"TronMateSubscriptionEventData":{"description":"Subscription details","properties":{"payment_amount_sun":{"type":"integer","format":"int64","description":"Payment amount"},"payment_timestamp":{"type":"integer","format":"int64","description":"Payment time"},"subscribe_type":{"type":"string","description":"Subscription type (BASIC | PRO)","enum":["SUBSCRIBE_UNKNOWN","SUBSCRIBE_BASIC","SUBSCRIBE_PRO","SUBSCRIBE_FLASH","UNRECOGNIZED"]},"address":{"type":"string","description":"Address"}}}}}}
```

## The AddressMonitorEvent object

```json
{"openapi":"3.1.0","info":{"title":"Notifier API","version":"0.1#@BUILD_ID@"},"components":{"schemas":{"AddressMonitorEvent":{"description":"Address monitoring event","properties":{"event_type":{"type":"string","description":"Event type","enum":["EVENT_UNKNOWN","EVENT_BALANCE","EVENT_TRON_MATE_SUBSCRIPTION","EVENT_DELEGATION","EVENT_ADDRESS_MONITOR","EVENT_TRON_MATE_HOST","EVENT_EMAIL_MESSAGE","EVENT_TELEGRAM_MESSAGE","EVENT_INTERNAL_MESSAGE","UNRECOGNIZED"]},"event_id":{"type":"string","description":"Order ID (idempotency key)"},"data":{"$ref":"#/components/schemas/AddressMonitorEventData"}}},"AddressMonitorEventData":{"description":"Address monitoring details","properties":{"txn_hash":{"type":"string","description":"Transaction hash"},"block_id":{"type":"integer","format":"int64","description":"Block number"},"name":{"type":"string","description":"Monitored address name"},"address":{"type":"string","description":"Monitored address"},"from_address":{"type":"string","description":"Sender address"},"contract_address":{"type":"string","description":"Contract address"},"to_address":{"type":"string","description":"Recipient address"},"amount":{"type":"integer","format":"int64","description":"Transfer amount"},"decimals":{"type":"integer","format":"int32","description":"Number of decimal places for the transfer amount"},"currency":{"type":"string","description":"Currency","enum":["USDT","TRX","ETH","BTC","BNB","BUSD"]},"chain":{"type":"string","description":"Blockchain type","enum":["TRON","ETH","BTC","UNRECOGNIZED"]},"paid_at":{"type":"integer","format":"int64","description":"Payment time"}}}}}}
```

***

#### Request Format

* **Method:** `POST`
* **Content-Type:** `application/json; charset=utf-8`
* **Headers:** Must include `X-EVENT-ID`, `X-EVENT-TYPE`, `X-EVENT-VERSION`

**Example Request**

```http
POST /callback HTTP/1.1
Host: example.com
Content-Type: application/json
X-EVENT-ID: aabbccdd-1122-3344-5566-77889900
X-EVENT-TYPE: EVENT_BALANCE
X-EVENT-VERSION: 20260918

{
  "event_type": "EVENT_BALANCE",
  "event_id": "aabbccdd-1122-3344-5566-77889900",
  "data": {
    "action_type": "BALANCE_ACTION_RECHARGE",
    "billing_item_type": "UNKNOWN_BILLING_ITEM_TYPE",
    "coin_type": "USDT",
    "amount_sun": 1000000,
    "balance": 500000000,
    "balance_usdt": 2000000,
    "timestamp": 1760505600,
    "remark": "transfer in"
  }
}
```

***

#### Event Data Definitions

**The `DelegationEvent` object**

Describes Energy or Bandwidth delegation details, including `resource_type`, `business_type`, the deprecated `delegation_type`, receiver, payment, duration, quantity, staked TRX, and delegation transaction details. See the OpenAPI schema above for the complete field definitions.

**The `BalanceEvent` object**

Describes account balance changes, including recharge, transfer, dApp consumption, API billing, refund, and others.

**The `TronMateSubscriptionEvent` object**

Describes subscription information for TRON Mate, including payment amount, payment time, subscription type (`BASIC` or `PRO`), and address.

**The `AddressMonitorEvent` object**

Describes a monitored-address transfer, including the transaction and block identifiers, monitored address, sender and recipient, amount, currency, chain, and payment time.

***

#### Response Requirements

> ⚠️ **NOTICE:** Please return `success` to inform the notification server that you have successfully received and handled the event. Once the notification server receives a success response, it stops retrying.

* After successful handling, **you must return:**

```http
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

success
```

* The platform treats HTTP 200 as success; otherwise, it will retry.

***

#### Retry Mechanism

If your endpoint does not return status 200, the system retries the notification.

**Retry Schedule**

Up to **10 attempts**, with the following intervals:

```
0s / 15s / 30s / 3m / 10m / 20m / 30m / 60m / 3h / 6h
```

After 10 consecutive failures, the system stops retrying and logs the failure.

***

#### Idempotency Recommendation

* Use `X-EVENT-ID` as the idempotency key.
* If the event has already been processed, immediately return `200`.

***

#### Example Code

**Node.js (Express)**

```js
import express from 'express';
const app = express();
app.use(express.json());
const processed = new Set();

app.post('/callback', (req, res) => {
  const eventId = req.header('X-EVENT-ID');
  if (processed.has(eventId)) return res.status(200).type('text/plain').send('success');
  processed.add(eventId);

  const evt = req.body; // { event_type, data }
  // TODO: handle event

  res.status(200).type('text/plain').send('success');
});

app.listen(8080);
```

**Java (Spring Boot)**

```java
@RestController
public class WebhookController {
  private final Set<String> processed = Collections.synchronizedSet(new HashSet<>());

  @PostMapping(value = "/callback", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
  public ResponseEntity<String> handle(@RequestHeader("X-EVENT-ID") String id,
                                       @RequestBody Map<String, Object> evt) {
    synchronized (processed) {
      if (processed.contains(id)) return ResponseEntity.ok("success");
      processed.add(id);
    }

    // TODO: handle event logic

    return ResponseEntity.ok("success");
  }
}
```

**Python (FastAPI)**

```python
from fastapi import FastAPI, Request, Header, Response
app = FastAPI()
processed = set()

@app.post("/callback")
async def webhook(req: Request, x_event_id: str = Header(None)):
    if x_event_id in processed:
        return Response(content="success", media_type="text/plain")
    processed.add(x_event_id)

    evt = await req.json()
    # TODO: handle event

    return Response(content="success", media_type="text/plain")
```

***

#### FAQ

**Q1: Can I return JSON?**\
Yes. As long as the HTTP status is 200, the response format does not matter.

**Q2: Does HTTP work?**\
Yes, both HTTP and HTTPS are supported.

**Q3: Can I subscribe dynamically?**\
No. Subscriptions can only be configured in the User Center.

**Q4: How to handle different event types?**\
Use the `X-EVENT-TYPE` header to branch logic.

**Q5: Are events ordered?**\
The system tries to preserve order for the same event type, but it’s not guaranteed.

**Q6: How should I handle event versioning?**\
The current protocol version is `20260918`. Use the `X-EVENT-VERSION` header to select your parsing logic and ignore unknown fields. Allow `business_type` to be absent when handling older delegation notifications.

**Q7: Has `delegation_type` been removed?**\
No. It is deprecated but is still included for compatibility with existing receivers. Use `business_type` for new integrations and templates.

***

**Version: v1.3.0 (2026-09-20); event protocol version: 20260918**
