Beta preview — heading toward 1.0. Issues?
API & Developers

DDoS Protection API

Complete reference for the Fusiora DDoS Protection REST API — authentication, protected IPs, filter profiles, IP lists and attack history.

Jun 22, 202642 min readapiddosauthenticationprotected-ipsfilter-profilesip-listsattack-historyreference

DDoS Protection API — Overview & Authentication

The Fusiora DDoS Protection API is a wrapper around the Avoro DDoS Manager. With it you can inspect protected IP addresses, review attack history, attach filter profiles to IPs, manage reusable IP lists, and configure per-IP protection settings.

With it you can:

  • Inspect protected IP addresses on your account.
  • Review the history of attacks that hit your IPs.
  • Attach filter profiles (presets + protocol/port ranges) to IPs.
  • Manage reusable IP lists with WHITELIST / BLACKLIST / TRUST entries.
  • Configure per-IP protection settings: default action, symmetric mode, ASN blocklist, country blocklist.

Base URL

All endpoints live under:

https://dpm.fusiora.com

Send every request to a path under that base, e.g. https://dpm.fusiora.com/api/attacks.

Endpoint groups

The API is organized around the resources you manage:

  • Protected IPs/api/ips/{ip}, /api/ip/{ip}/… — Read & configure protection on a single IP.
  • Filter Profiles/api/filters, /api/ip/{ip}/profiles — Browse presets, attach/detach them per protocol+port range.
  • IP Lists/api/iplists, /api/iplists/{id}/entries — Reusable CIDR lists referenced by profiles.
  • Attacks/api/attacks, /api/attacks/{id}/stats — Read attack history and time-series statistics.

Conventions

  • Request bodies are JSON. Always send Content-Type: application/json for POST, PUT, and PATCH requests.
  • Successful responses return JSON, except 204 No Content for updates and deletes that have nothing to return.
  • Errors return JSON with an error field describing the problem. See the Reference for status codes.
  • PATCH endpoints under /api/ip/{ip}/... are field-scoped: they read the current IP config, change only the requested field, and write it back. All other settings are preserved.

Authentication

Every request must include your personal API key in the x-api-key HTTP header. Requests without a valid key are rejected with 401 Unauthorized.

x-api-key: YOUR_API_KEY

That's it — no Bearer prefix, no signature, no expiry parameter.

Quick test

A successful call to /api/attacks confirms your key is valid:

curl -X GET "https://dpm.fusiora.com/api/attacks" \
  -H "x-api-key: YOUR_API_KEY"

If the key is wrong or missing, you'll get 401:

{ "error": "Missing or invalid API key" }

Using the key

Send the same header on every endpoint:

# GET
curl -X GET "https://dpm.fusiora.com/api/ips/85.239.155.11" \
  -H "x-api-key: YOUR_API_KEY"

# POST with body
curl -X POST "https://dpm.fusiora.com/api/iplists" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "officevpn"}'

# PATCH with body
curl -X PATCH "https://dpm.fusiora.com/api/ip/85.239.155.11/default-action" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"defaultAction": "FILTER"}'

Keeping the key secret

  • Never commit it to a public repository. Treat it like a password.
  • Don't use it from client-side JavaScript running in a browser — proxy calls through your own backend instead.
  • Rotate it if you suspect it leaked.
  • Use one key per environment (production / staging) where possible.

What the key can do

The key is bound to one user account and to a fixed list of IPs on the Avoro side. It can do everything that account is allowed to do — there are no per-key scopes today.

Permissions and ownership

The API is multi-tenant. Every IP and every IP list belongs to exactly one account, and the API never lets you cross that boundary.

When you call an endpoint, the API checks:

  1. Is the key valid? (No → 401)
  2. If the URL contains an IP — is that IP on your account? (No → 403)
  3. If the URL contains a list ID — was that list created by your account? (No → 404)

Why 403 for IPs but 404 for lists?

It's deliberate.

  • IPs are a known shape (a.b.c.d). Returning 403 confirms the IP exists somewhere, just not on your account. That's fine — IPs are public information.
  • IP list IDs are internal numeric handles. Returning 403 for someone else's list would let attackers enumerate other users' lists by trying IDs in sequence. So the API returns 404 Not Found — indistinguishable from a list that never existed.

Same logic for list entries: deleting an entry that belongs to another user's list returns 404.

What you can and can't do

You can:

  • Read any IP on your account: GET /api/ips/{ip}.
  • List, create, update, delete your own IP lists: /api/iplists/....
  • Add / remove entries on your own lists: /api/iplists/{id}/entries.
  • Read attacks against your IPs: GET /api/attacks (results are auto-filtered to your IPs).
  • Reference another of your own lists as a nested entry.

You can't:

  • Touch an IP that isn't on your account → 403.
  • Read, modify, or delete a list you didn't create → 404.
  • Nest a list owned by someone else inside your own list → 400 ("nested list not found").
  • Delete an entry through a list URL that doesn't own that entry → 404.

Attack history scope

The /api/attacks endpoint is special: instead of failing with 403, it silently filters out any attack whose destination IP isn't on your account. An empty array is a valid answer — this makes pagination + filtering safe to call from background jobs without per-attack ownership checks.

Common pitfalls

  • Wrong key for the wrong environment. Production and staging IPs live on different accounts. Mixing keys yields confusing 403s.
  • Copy-pasted list IDs from a teammate's account. Use your own.
  • Self-referential nested lists. Adding list 730 as an entry inside list 730 returns 400.

Next steps

With the base URL, x-api-key authentication, and the ownership model clear, you're ready to explore the rest of the documentation and start configuring protection for your IPs.

Protected IPs

Endpoints for inspecting and configuring DDoS protection on a single IP that's assigned to your account.

All PATCH endpoints below are field-scoped: they read the current IP config, change only the requested field, and write it back. Thresholds, attached filter profiles, and other settings are preserved.

Get IP details

Returns the full configuration of one of your protected IPs.

GET /api/ips/{ip}

Path parameter

  • ip (required) — IPv4 address you own (e.g. 85.239.155.11).

Example

curl -X GET "https://dpm.fusiora.com/api/ips/85.239.155.11" \
  -H "x-api-key: YOUR_API_KEY"

Response (200 OK)

{
  "ID": 1234,
  "Ipv4": "85.239.155.11",
  "Description": "Game server #1",
  "Enabled": true,
  "DefaultAction": "FILTER",
  "SymmetricMode": "FULL",
  "CountryBlockMode": 0,
  "CountryBlockList": [],
  "AsnBlockMode": 0,
  "AsnBlockList": [],
  "SynThreshold": 50000,
  "UdpThreshold": 50000
}

Additional protection thresholds may appear in the response — they are read-only here. Use the dedicated PATCH endpoints below to change individual settings.

Errors: 401 invalid key · 403 IP not on your account · 500 upstream failed.

Default action

The default action decides what happens to traffic on ports that don't have a specific filter profile. It's effectively the catch-all rule for an IP.

PATCH /api/ip/{ip}/default-action

Body

{ "defaultAction": "FILTER" }

Values

  • ACCEPT — DDoS protection disabled. Only ports with a filter profile are protected. Use when you handle protection yourself — rare.
  • FILTER — Standard protection on every port. Recommended default. Normal setting for production servers.
  • DROP — Drop all traffic. Only filter-attached ports let traffic through. Killswitch: incident response, maintenance, strict-allowlist setups.

Examples

# Standard protection (recommended)
curl -X PATCH "https://dpm.fusiora.com/api/ip/85.239.155.11/default-action" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"defaultAction": "FILTER"}'

# Killswitch
curl -X PATCH "https://dpm.fusiora.com/api/ip/85.239.155.11/default-action" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"defaultAction": "DROP"}'

# Disable protection (accept all)
curl -X PATCH "https://dpm.fusiora.com/api/ip/85.239.155.11/default-action" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"defaultAction": "ACCEPT"}'

Response (200 OK)

{ "success": true, "message": "Default action set to FILTER", "data": {} }

Errors: 400 invalid value · 401 invalid key · 403 IP not yours · 500 upstream failed.

Symmetric protection

Stateful filter that requires every connection to behave consistently in both directions. Effective against spoofed traffic, since spoofed packets never receive matching reply traffic.

PATCH /api/ip/{ip}/symmetric

Body

{ "symmetricMode": "FULL" }

Values

  • FULL — Enforce symmetric inspection. Asymmetric flows are challenged or dropped. Recommended.
  • DISABLED — Don't enforce symmetric routing. Use only if your network is intentionally asymmetric.

Examples

# Enable (recommended)
curl -X PATCH "https://dpm.fusiora.com/api/ip/85.239.155.11/symmetric" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"symmetricMode": "FULL"}'

# Disable
curl -X PATCH "https://dpm.fusiora.com/api/ip/85.239.155.11/symmetric" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"symmetricMode": "DISABLED"}'

Response (200 OK)

{ "success": true, "message": "Symmetric mode set to FULL", "data": {} }

Errors: 400 invalid value · 401 invalid key · 403 IP not yours · 500 upstream failed.

ASN blocklist

Filter traffic by source ASN (Autonomous System Number). Useful for blocking abusive networks or locking an IP down to a specific cloud provider's ASN.

The list is capped at 20 ASNs per IP and works as either blacklist or whitelist.

PATCH /api/ip/{ip}/asn-blocklist

Body

{
  "asnBlockMode": 1,
  "asnBlockList": [12345, 67890]
}

Modes

  • 0 — Disabled — ASN filtering is off. asnBlockList is ignored.
  • 1 — Blacklist — Traffic from listed ASNs is blocked. Everything else is allowed.
  • 2 — Whitelist — Only traffic from listed ASNs is allowed. Everything else is blocked.

Send both fields together. ASN numbers are integers between 1 and 4,294,967,295. No AS prefix — send 13335, not "AS13335". Duplicates are de-duplicated server-side.

Examples

# Block two networks
curl -X PATCH "https://dpm.fusiora.com/api/ip/85.239.155.11/asn-blocklist" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"asnBlockMode": 1, "asnBlockList": [12345, 67890]}'

# Whitelist only Cloudflare (AS13335)
curl -X PATCH "https://dpm.fusiora.com/api/ip/85.239.155.11/asn-blocklist" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"asnBlockMode": 2, "asnBlockList": [13335]}'

# Disable
curl -X PATCH "https://dpm.fusiora.com/api/ip/85.239.155.11/asn-blocklist" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"asnBlockMode": 0, "asnBlockList": []}'

Response (200 OK)

{ "success": true, "message": "ASN blocklist updated", "data": {} }

Errors: 400 invalid mode / non-array list / >20 entries / invalid ASN · 401 invalid key · 403 IP not yours · 500 upstream failed.

Country blocklist

Filter traffic by source country (GeoIP). The list is capped at 20 countries per IP and uses ISO 3166-1 alpha-2 codes.

PATCH /api/ip/{ip}/country-blocklist

Body

{
  "countryBlockMode": 1,
  "countryBlockList": ["CN", "RU", "KP"]
}

Modes

  • 0 — Disabled — Country filtering is off. countryBlockList is ignored.
  • 1 — Blacklist — Traffic from listed countries is blocked. Everything else is allowed.
  • 2 — Whitelist — Only traffic from listed countries is allowed. Everything else is blocked.

Codes are case-insensitive on input and stored uppercase ("cz" becomes "CZ"). Duplicates are de-duplicated server-side.

Examples

# Block three countries
curl -X PATCH "https://dpm.fusiora.com/api/ip/85.239.155.11/country-blocklist" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"countryBlockMode": 1, "countryBlockList": ["CN", "RU", "KP"]}'

# Whitelist Czechia and Slovakia only
curl -X PATCH "https://dpm.fusiora.com/api/ip/85.239.155.11/country-blocklist" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"countryBlockMode": 2, "countryBlockList": ["CZ", "SK"]}'

# Disable
curl -X PATCH "https://dpm.fusiora.com/api/ip/85.239.155.11/country-blocklist" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"countryBlockMode": 0, "countryBlockList": []}'

Response (200 OK)

{ "success": true, "message": "Country blocklist updated", "data": {} }

Common country codes

Frequently used ISO 3166-1 alpha-2 codes:

  • CZ — Czech Republic
  • RU — Russia
  • SK — Slovakia
  • CN — China
  • DE — Germany
  • UA — Ukraine
  • US — United States
  • IN — India
  • GB — United Kingdom
  • BR — Brazil
  • FR — France
  • JP — Japan
  • PL — Poland
  • KR — South Korea
  • NL — Netherlands
  • AU — Australia

Errors: 400 invalid mode / non-array list / >20 entries / invalid code · 401 invalid key · 403 IP not yours · 500 upstream failed.

Combine these endpoints to tune protection per IP — set a sensible default action, enforce symmetric inspection, and tighten access with ASN and country lists as your traffic demands.

Filter Profiles

A filter preset is a named ruleset prepared by Fusiora (tuned for FiveM, web traffic, DNS, etc.). To use one, you attach it to an IP as a filter profile bound to a specific protocol and port range.

A profile is the combination of:

  • A preset (the ruleset).
  • A protocol (UDP, TCP, ICMP).
  • A destination port range (minDstPortmaxDstPort, both inclusive).

You can attach many profiles to a single IP — one per service.

List available presets

GET /api/filters

No path or query parameters.

Example

curl -X GET "https://dpm.fusiora.com/api/filters" \
  -H "x-api-key: YOUR_API_KEY"

Response (200 OK)

[
  { "id": 42, "name": "GameUDP", "protocol": "UDP" },
  { "id": 43, "name": "WebTCP",  "protocol": "TCP" },
  { "id": 44, "name": "DNS",     "protocol": "UDP" }
]

Each entry exposes exactly what you need to attach a profile:

  • id — use this as presetId when attaching.
  • name — display name, useful for logs and dashboards.
  • protocol — protocol this preset is built for. Must match the protocol you send.

Errors: 401 invalid key · 500 upstream failed.

List profiles attached to an IP

GET /api/ip/{ip}/profiles

Example

curl -X GET "https://dpm.fusiora.com/api/ip/85.239.155.11/profiles" \
  -H "x-api-key: YOUR_API_KEY"

Response (200 OK)

[
  {
    "ID": 5511,
    "PresetID": 42,
    "PresetName": "GameUDP",
    "Protocol": "UDP",
    "MinDstPort": 30120,
    "MaxDstPort": 30130,
    "Notes": "FiveM"
  }
]

Errors: 401 invalid key · 403 IP not yours · 500 upstream failed.

Attach a profile

POST /api/ip/{ip}/profiles

Body

{
  "presetId": 42,
  "protocol": "UDP",
  "minDstPort": 30120,
  "maxDstPort": 30130,
  "notes": "FiveM server"
}
  • presetId (required) — ID from GET /api/filters.
  • protocol (required) — protocol name, typically UDP, TCP, or ICMP. Must match the preset's protocol.
  • minDstPort (required) — lower bound of destination ports, inclusive (065535).
  • maxDstPort (required) — upper bound, inclusive (065535). Must be >= minDstPort.
  • notes (optional) — free-form note (string, can be empty).

Example — FiveM game server

curl -X POST "https://dpm.fusiora.com/api/ip/85.239.155.11/profiles" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "presetId": 42,
    "protocol": "UDP",
    "minDstPort": 30120,
    "maxDstPort": 30130,
    "notes": "FiveM"
  }'

Response (200 OK)

{
  "ID": 5512,
  "PresetID": 42,
  "Protocol": "UDP",
  "MinDstPort": 30120,
  "MaxDstPort": 30130,
  "Notes": "FiveM server"
}

Save the ID — you'll need it to delete the profile later.

Errors: 401 invalid key · 403 IP not yours · 500 upstream rejected — invalid preset, overlapping profile, mismatched protocol. The error message includes the upstream reason.

Delete a profile

DELETE /api/ip/{ip}/profiles/{profileId}

The profile must belong to the IP in the URL — profiles attached to a different IP can't be deleted through this path.

Example

curl -X DELETE "https://dpm.fusiora.com/api/ip/85.239.155.11/profiles/5512" \
  -H "x-api-key: YOUR_API_KEY"

Response (200 OK)

{
  "success": true,
  "message": "Profile 5512 deleted from IP 85.239.155.11",
  "data": {}
}

Errors: 401 invalid key · 403 IP not yours · 404 profile doesn't belong to this IP · 500 upstream failed.

Filter profiles are how you apply Fusiora's protection rules exactly where you need them, service by service, across each of your IPs.

IP Lists

IP Lists are reusable, named collections of CIDR addresses you can reference from DDoS protection profiles. Instead of duplicating the same set of IPs across many filters, you maintain one list and update it in one place.

Why use them

  • DRY. One change updates every filter that references the list.
  • Composable. Lists can include other lists as entries — build a hierarchy (e.g. partnersacme-corp + globex).
  • Per-entry expiry. Address entries can auto-remove themselves after N seconds — perfect for time-boxed bans.

Action types

Every entry has an ipListAction. It decides what the protection layer does when traffic matches.

  • WHITELIST — Traffic is always allowed through, even when other rules would block it. Use for trusted partners or monitoring services. Default if you don't set one.
  • BLACKLIST — Traffic is always dropped. Use for known attackers or fine-grained blocks where country/ASN filtering is too broad.
  • TRUST — Traffic skips all DDoS filtering entirely. Use only for internal infrastructure or networks where you have full control.
Be careful with TRUST. It's a bypass, not just an allow rule. Use sparingly.

Ownership

  • Each list belongs to the user who created it.
  • You can only see, modify, or delete lists you created.
  • Other users' lists are reported as 404 Not Found — not 403 — so list IDs can't be enumerated.
  • Nested-list references must point to a list you also own.

Nesting

A list can contain another list as an entry:

{ "listId": 729, "ipListAction": "BLACKLIST" }

Two important rules:

  1. No self-reference. Adding list 730 as an entry of list 730 returns 400.
  2. No cross-user references. The nested list must be yours.

If you delete a list that another of your lists referenced, the reference becomes inactive — the parent doesn't error, it just no longer matches what the child used to.

Limits and quotas

  • Max entries per list: 11,000,000, configurable via maxEntries. Defaults to 1000.
  • List name format: 1-64 alphanumeric characters only — no spaces, dashes, or underscores.
  • List description: up to 500 characters.

Create a list

POST /api/iplists

Body

{
  "name": "officevpn",
  "description": "Allowed IPs for office VPN",
  "maxEntries": 1000
}
  • name (required) — 1-64 alphanumeric characters (a-z, A-Z, 0-9). No spaces, dashes, or underscores.
  • description (optional) — Free-form text up to 500 characters.
  • maxEntries (optional) — 11,000,000. Defaults to 1000.

Examples

# Minimal
curl -X POST "https://dpm.fusiora.com/api/iplists" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "officevpn"}'

# Full
curl -X POST "https://dpm.fusiora.com/api/iplists" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "blockedasns", "description": "Known bad networks", "maxEntries": 5000}'

Response (201 Created)

{
  "ID": 730,
  "Name": "officevpn",
  "Description": "Allowed IPs for office VPN",
  "MaxEntries": 1000,
  "EntryCount": 0,
  "CreatedAt": "2026-05-13T10:00:00Z"
}

Save the ID — you'll need it for every other operation on this list.

List your lists

GET /api/iplists

Query parameters

  • includeItems (optional) — "true" to include the entries inline. Omit or "false" for metadata only.

Examples

# Metadata only
curl -X GET "https://dpm.fusiora.com/api/iplists" \
  -H "x-api-key: YOUR_API_KEY"

# With entries
curl -X GET "https://dpm.fusiora.com/api/iplists?includeItems=true" \
  -H "x-api-key: YOUR_API_KEY"

Response (200 OK)

[
  {
    "ID": 730,
    "Name": "officevpn",
    "Description": "Allowed IPs for office VPN",
    "MaxEntries": 1000,
    "EntryCount": 3,
    "CreatedAt": "2026-05-13T10:00:00Z",
    "UpdatedAt": "2026-05-13T10:05:00Z"
  }
]

Lists owned by other users are never returned.

Get one list

GET /api/iplists/{id}

Returns the full details and entries of a single list you own.

curl -X GET "https://dpm.fusiora.com/api/iplists/730" \
  -H "x-api-key: YOUR_API_KEY"

Returns 404 if the list doesn't exist or if you don't own it.

Update a list

PUT /api/iplists/{id}

Updates the list's name, description, or maxEntries. To change the entries themselves, use the entries endpoints below.

Body

{
  "name": "officevpn",
  "description": "Updated description",
  "maxEntries": 2000
}

Examples

# Rename
curl -X PUT "https://dpm.fusiora.com/api/iplists/730" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "officevpnv2"}'

# Increase capacity
curl -X PUT "https://dpm.fusiora.com/api/iplists/730" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "officevpn", "maxEntries": 5000}'

Response: 204 No Content. The body is empty on success.

Delete a list

DELETE /api/iplists/{id}

Permanently deletes the list and all its entries. Any profile or nested-list reference becomes inactive, so check usage first.

curl -X DELETE "https://dpm.fusiora.com/api/iplists/730" \
  -H "x-api-key: YOUR_API_KEY"

Response: 204 No Content.

List entries

GET /api/iplists/{id}/entries
curl -X GET "https://dpm.fusiora.com/api/iplists/730/entries" \
  -H "x-api-key: YOUR_API_KEY"

Response (200 OK)

[
  {
    "ID": 4501,
    "address": "203.0.113.5/32",
    "ipListAction": "WHITELIST",
    "expireAfterSec": 0,
    "ipListID": 730
  },
  {
    "ID": 4502,
    "address": "198.51.100.0/24",
    "ipListAction": "BLACKLIST",
    "ipListID": 730
  }
]

Add an entry

POST /api/iplists/{id}/entries

An entry is either an address (CIDR) or a nested list (listId). Provide exactly one of those fields per entry — never both, never neither.

Body — IP/CIDR entry

{
  "address": "203.0.113.5/32",
  "ipListAction": "WHITELIST",
  "expireAfterSec": 3600
}

Body — nested-list reference

{
  "listId": 729,
  "ipListAction": "BLACKLIST"
}
  • address (one of address/listId) — A valid CIDR. Single IPs must be /32 (IPv4) or /128 (IPv6). Leading zeros are rejected (01.2.3.4/32 is invalid).
  • listId (one of address/listId) — ID of another IP list you own. Cannot equal the parent list. Cannot reference a list you don't own.
  • ipListAction (optional) — WHITELIST, BLACKLIST, or TRUST. Defaults to WHITELIST.
  • expireAfterSec (optional, address only) — Auto-remove the entry after N seconds. Non-negative integer. Ignored for nested-list entries.

Examples

# Allow a single IP forever
curl -X POST "https://dpm.fusiora.com/api/iplists/730/entries" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"address": "203.0.113.5/32", "ipListAction": "WHITELIST"}'

# Block a /24 subnet
curl -X POST "https://dpm.fusiora.com/api/iplists/730/entries" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"address": "198.51.100.0/24", "ipListAction": "BLACKLIST"}'

# Temporary block — auto-expires in 1 hour
curl -X POST "https://dpm.fusiora.com/api/iplists/730/entries" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"address": "192.0.2.10/32", "ipListAction": "BLACKLIST", "expireAfterSec": 3600}'

# Include another of your lists (nested)
curl -X POST "https://dpm.fusiora.com/api/iplists/730/entries" \
  -H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"listId": 729, "ipListAction": "BLACKLIST"}'

Response (201 Created)

{
  "ID": 4503,
  "address": "203.0.113.5/32",
  "ipListAction": "WHITELIST",
  "expireAfterSec": 3600,
  "ipListID": 730
}

Delete an entry

DELETE /api/iplists/{id}/entries/{entryId}

The entry must belong to the list named in the URL — even if you know an entry ID from a different list (yours or someone else's), it can't be deleted through the wrong parent.

curl -X DELETE "https://dpm.fusiora.com/api/iplists/730/entries/4503" \
  -H "x-api-key: YOUR_API_KEY"

Response: 204 No Content.

Common errors

  • 400 — Invalid list ID, name format, description length, or maxEntries range.
  • 400 — Both address and listId sent — or neither. Send exactly one.
  • 400address isn't valid CIDR — check leading zeros.
  • 400ipListAction isn't WHITELIST / BLACKLIST / TRUST.
  • 400expireAfterSec is negative or not an integer.
  • 400listId equals the parent list ID — self-reference.
  • 400 — Referenced nested list doesn't exist or isn't yours.
  • 401 — Missing or invalid API key.
  • 404 — List doesn't exist or it isn't yours — same response on purpose, see Getting Started.

With IP Lists you centralize the management of trusted and blocked addresses in a single reusable place, keeping your protection profiles clean and consistent.

Attack History

Read the history of attacks against your protected IPs and pull time-series statistics for any specific attack.

Results are automatically scoped to the IPs assigned to your account — you can call these endpoints freely without worrying about leaking other tenants' data.

Get attack history

Returns the list of attacks that hit your protected IPs.

GET /api/attacks

Query parameters

  • page (no) — Page number for pagination.
  • query (no) — Free-text filter forwarded to Avoro (e.g. attack type or IP).

Examples

# Latest attacks (page 1)
curl -X GET "https://dpm.fusiora.com/api/attacks" \
  -H "x-api-key: YOUR_API_KEY"

# Paginated
curl -X GET "https://dpm.fusiora.com/api/attacks?page=2" \
  -H "x-api-key: YOUR_API_KEY"

# Filtered (e.g. only UDP floods)
curl -X GET "https://dpm.fusiora.com/api/attacks?query=UDP" \
  -H "x-api-key: YOUR_API_KEY"

Response (200 OK)

[
  {
    "ID": 88123,
    "DstAddressString": "85.239.155.11",
    "Type": "UDP_FLOOD",
    "Bps": 12500000000,
    "Pps": 8500000,
    "StartedAt": "2026-05-13T09:14:22Z",
    "EndedAt": "2026-05-13T09:18:55Z"
  }
]

Each item is a separate attack event:

  • ID — Use this to fetch statistics (next section).
  • DstAddressString — The IP that was targeted. Always one of yours.
  • Type — Attack classification (e.g. UDP_FLOOD, SYN_FLOOD, …).
  • Bps — Peak bandwidth in bits per second.
  • Pps — Peak packet rate in packets per second.
  • StartedAt — ISO 8601 timestamp when the attack began.
  • EndedAt — ISO 8601 timestamp when the attack ended.

An empty array is a perfectly valid response — it just means no attacks matched.

Errors: 401 invalid key · 500 upstream failed (body includes a debugId — quote it in support tickets).

Get attack statistics

Returns time-series statistics — bandwidth and packet rate samples — for a specific attack event. Use it to plot how an attack ramped up and tailed off.

GET /api/attacks/{id}/stats
  • id (yes) — Numeric attack ID from GET /api/attacks.

Example

curl -X GET "https://dpm.fusiora.com/api/attacks/88123/stats" \
  -H "x-api-key: YOUR_API_KEY"

Response (200 OK)

{
  "AttackID": 88123,
  "Samples": [
    { "T": "2026-05-13T09:14:22Z", "Bps": 8000000000,  "Pps": 6500000 },
    { "T": "2026-05-13T09:14:32Z", "Bps": 12500000000, "Pps": 8500000 }
  ]
}

Each sample is a single observation:

  • T — ISO 8601 timestamp of the sample.
  • Bps — Bandwidth at that moment, in bits per second.
  • Pps — Packet rate at that moment, in packets per second.

The cadence between samples depends on attack length and upstream sampling — don't assume fixed intervals when graphing.

Errors: 401 invalid key · 500 upstream failed.

With these two endpoints you can reconstruct both the high-level overview of recent attacks and the minute-by-minute detail of any one of them.

API Reference

Lookup material that supports the rest of the API documentation: HTTP status codes the API returns, and the CIDR notation used in every IP entry.

HTTP status codes

The Fusiora API uses standard HTTP status codes. Below: every code the API returns, when you'll see it, and what to do.

Success

  • 200 OK — Request succeeded. Response body contains the result.
  • 201 Created — A new resource was created. Returned by POST /api/iplists and POST /api/iplists/{id}/entries.
  • 204 No Content — Update or delete succeeded. Response body is empty — don't try to parse it as JSON.

Client errors

  • 400 Bad Request — The request body or query is malformed. The error field describes what's wrong. Fix the payload. Check enums, array sizes, value formats (CIDR, ISO country codes).
  • 401 Unauthorizedx-api-key header missing or unknown. Add the header. Check the key for trailing spaces or wrong environment.
  • 403 Forbidden — Key is valid, but the IP in the URL is not assigned to your account. Use only IPs assigned to your account.
  • 404 Not Found — Resource doesn't exist — or you don't own it. Ownership errors on IP lists are reported as 404 by design to prevent ID enumeration. Verify the resource exists and that you created it.

Server errors

  • 500 Internal Server Error — The upstream Avoro API failed. The error field includes details. Attack-history errors include a debugId. Retry with exponential backoff. If it persists, contact support with the debugId.
  • 502 Bad Gateway — Upstream Avoro returned an unexpected response. Retry. If it persists, contact support.

Quick decision tree

When you get a non-success response:

  1. 400? Read the error field — it tells you the exact validation failure. Don't retry without fixing the payload.
  2. 401? Don't retry — fix your header.
  3. 403? The IP isn't yours. Check the URL.
  4. 404? The resource is missing or you don't own it. Double-check the ID.
  5. 500 / 502? Retry with exponential backoff. Contact support if it persists.

Error response shape

All errors share the same JSON shape:

{ "error": "Description of what went wrong" }

Some 500 responses include extra fields:

{
  "error": "Upstream API failed",
  "debugId": "abc123-xyz"
}

Quote the debugId when contacting support — it's the fastest way for us to look up your specific failure.

CIDR notation

Every IP entry in the Fusiora API is given in CIDR (Classless Inter-Domain Routing) notation: address/prefix. The prefix is the number of leading bits the address shares.

A single IP is /32 for IPv4 or /128 for IPv6. There's no "bare IP" format; always include the prefix.

IPv4 quick reference

  • 1.2.3.4/321.2.3.4 only — 1 address.
  • 192.168.1.0/24192.168.1.0192.168.1.255 — 256 addresses.
  • 10.0.0.0/1610.0.0.010.0.255.255 — 65 536 addresses.
  • 10.0.0.0/810.0.0.010.255.255.255 — ~16.7 M addresses.
  • 0.0.0.0/0 — All IPv4 — extreme caution.

IPv6 quick reference

  • 2001:db8::1/128 — A single IPv6 address.
  • 2001:db8::/32 — A typical ISP allocation — millions of /48s.
  • 2001:db8::/48 — A single site / customer.

Rules the API enforces

  • Always include the prefix. Even single IPs need /32 or /128. 1.2.3.4 alone is rejected.
  • No leading zeros in octets. 01.2.3.4/32 is invalid. Use 1.2.3.4/32.
  • IPv6 must be valid RFC 4291 form. The compact :: shorthand is fine; uppercase or lowercase hex digits are both accepted.

Common patterns

  • Allow your office static IP203.0.113.5/32
  • Block an entire abusive /24198.51.100.0/24
  • Allow your entire AWS VPC range10.0.0.0/16
  • IPv6 single host2001:db8::1/128

Where CIDR appears in the API

CIDR strings appear in the address field of IP list entries — see IP Lists.

Country and ASN filtering use country codes and ASN numbers instead — they don't take CIDR. See Protected IPs for those.

Mental shortcut

The smaller the prefix number, the bigger the range:

  • /32 = 1 address (smallest possible).
  • /24 = 256 addresses (a typical "Class C" subnet).
  • /16 = 65 536 addresses.
  • /8 = ~16.7 million addresses.
  • /0 = the entire internet.

When in doubt, use an online CIDR calculator to double-check your range.

Was this article helpful?

Be the first to rate it

We use cookies

We use cookies to improve your experience, analyse site traffic and personalise content. You can choose which cookies to accept.