Event Drains Enterprise
Event drains let you forward real-time server events to external services via webhooks. Unlike triggers, which are for FiniAC events, such as player connections and detections, event drains operate on server events, such as entity creation, weapon damage, particle effects, explosions, etc.
Each drain can filter by event type and use field-level filter queries to match only the events you care about. Matched events are delivered as JSON payloads to your configured webhook URL.
Enterprise
Event drains are an Enterprise feature, contact support for more information.
Creating a Drain
Each event drain consists of:
- Name - a descriptive label (max 120 characters)
- URL - the webhook endpoint that receives matched events
- Enabled - toggle the drain on or off without deleting it
- Event Types - optional list of event types to match (e.g.,
entityCreating,weaponDamage). Leave empty to match all types - Filter Query - optional USQL field expression for fine-grained matching against event data
Event Types
Event types correspond to the server-side events processed by FiniAC. Common types include:
weaponDamage- weapon damage dealt to another playerentityCreating- entity spawned on the serverexplosionEvent- explosion occurredfireEvent- fire started or extinguishedptFxEvent- particle effect created or removedgiveWeaponEvent- weapon given to a playerremoveWeaponEvent- weapon removed from a player
Filter by one or more types to limit which events the drain receives. If no event types are specified, the drain matches all events.
Filter Queries
Filter queries use an extended USQL syntax with field-level expressions. This lets you target specific fields in the event data without matching against every field.
Operators
| Operator | Description | Example |
|---|---|---|
: | Exact match (default) | type:player_damage |
= | Exact match | type=player_damage |
!= | Not equal | type!=Secret |
~ | Contains (case-insensitive) | data.weapon~PISTOL |
> | Greater than (numeric) | data.damage>50 |
< | Less than (numeric) | data.damage<100 |
>= | Greater than or equal | data.damage>=50 |
<= | Less than or equal | data.damage<=100 |
Boolean Logic
Combine expressions with AND/OR (&&/||), negate with ! or -, and group with parentheses:
type:player_damage && sender.discord:123456789
data.damage>50 || data.weapon~EXPLOSIVE
!(type:player_heal)Available Fields
Events are flattened to dot-notation paths for filtering. These are the fields available in filter queries:
| Field | Description |
|---|---|
type / event_type | Event type name |
player_name | Player name |
player_id | Player ID |
sender.* | Sender identifiers - sender.discord, sender.license, sender.name, sender.steam, etc. |
target.* | Target identifiers - target.discord, target.license, target.name, etc. |
data.* / payload.* | Event data fields - data.weapon, data.damage, data.amount, etc. |
position.* / pos_x / pos_y / pos_z | Position coordinates |
Examples
Match pistol damage from a specific player:
type:player_damage && sender.discord:123456789 && data.weapon~PISTOLMatch high-damage events, excluding heals:
data.damage>50 && !type:player_healMatch events near a map location:
position.x>100 && position.x<500 && position.y>200 && position.y<600Match any event involving a specific player:
sender.discord:123456789 || target.discord:123456789Webhook Payload
When events match a drain, a POST request is sent to the configured URL. The request includes a JSON body with the following structure:
{
"version": 1,
"generated_at": "2026-04-08T10:30:45.123Z",
"server_id": 44,
"drain": {
"id": "abc123def456",
"name": "Damage Events"
},
"match": {
"event_types": ["weaponDamage"],
"filter_query": "sender.discord:123456789"
},
"matched_count": 1,
"events": [
{
"event_time": "2026-04-08T10:30:44Z",
"server_id": 44,
"type": "weaponDamage",
"player_name": "Alpha",
"player_id": "12",
"sender_identifiers": {
"discord": "123456789",
"license": "license:abc123",
"name": "Alpha",
"fivem": "117632387"
},
"target_identifiers": {
"discord": "987654321",
"license": "license:xyz789",
"name": "Bravo"
},
"pos": [100.5, 200.3, 35.8],
"data": {
"weapon": "WEAPON_PISTOL",
"damage": 34
}
}
]
}Payload Fields
| Field | Type | Description |
|---|---|---|
version | number | Payload schema version (currently 1) |
generated_at | string | ISO 8601 timestamp when the payload was generated |
server_id | number | Server that produced the events |
drain.id | string | Drain identifier |
drain.name | string | Drain name |
match.event_types | string[] | Event type filter configured on the drain |
match.filter_query | string | null | Filter query configured on the drain |
matched_count | number | Number of events in this delivery |
events | object[] | Array of matched event objects |
Event Object
Each event in the events array contains:
| Field | Type | Description |
|---|---|---|
event_time | string | ISO 8601 timestamp of the event |
server_id | number | Server ID |
type | string | Event type name |
player_name | string | Player name |
player_id | string | Player ID |
sender_identifiers | object | Sender player identifiers (discord, license, steam, fivem, name, ip, xbl, live, license2, etc.) |
target_identifiers | object | null | Target player identifiers, if applicable |
pos | number[] | null | Position as [x, y, z] coordinates |
data | object | Event-specific data payload |
Headers
Webhook requests include the following headers:
| Header | Value |
|---|---|
Content-Type | application/json |
User-Agent | fini-log-ingest-event-drain/1.0 |
Limits
- Webhook endpoints must respond within 4 seconds
- URLs cannot point to localhost or private addresses
- Filter query maximum length: 2048 characters
- Drain name maximum length: 120 characters
- Maximum number of drains per server is determined by your subscription plan
Permissions
Managing event drains requires the following panel permissions:
| Permission | Access |
|---|---|
WEBHOOKS.VIEW | View event drains |
WEBHOOKS.WRITE | Create, update, and delete event drains |