Blocklist Propagation: Making One Confirmed Abuse Case Kill the Whole Network
Banning an account removes one head from the hydra. Blocklisting from a session auto-extracts every identifier it touched — face, document, phone, email, IP, device — across 12 entry types, so the next account fails at the door.

There is a specific moment where most abuse programmes leak value: the moment after you win.
Your traffic layer flags an account. An analyst investigates. The evidence is solid, the case is confirmed, the account is banned. And then, hours later, the same operator is back on new accounts, because the only thing your enforcement touched was a row in a users table.
Anthropic described exactly this dynamic in its February 2026 report on distillation campaigns — a proxy network that "managed more than 20,000 fraudulent accounts simultaneously," replacing them as they were removed. Removal was not the bottleneck. Regeneration was cheaper than removal.
The fix is to make enforcement operate on identifiers instead of accounts. Didit's Lists API is built around one mechanic that does this in a single call.
Key takeaways
- Blocklisting with
reference_session_idmakes Didit auto-extract the right value from the session — face, document, phone, email, IP or device — mark the underlying model blocklisted, and link the entry back to the source session. - 12 entry types:
face,document,phone,email,ip_address,device_fingerprint,wallet_address,bank_account,user,business,country,key. - Blocklists are system-created, one per entry type, and immutable. You cannot create them, which is what makes enforcement uniform.
- Entries take effect immediately at verification time. Deleting an entry unblocks the match.
ip_addressaccepts a CIDR range, so you can blocklist infrastructure rather than a single address.- Allowlists across the same 12 types keep trusted developers out of every escalation path.
The two list types that matter
The API has three list types, and the distinction between them is deliberate.
Blocklists are system-created — one per entry type — and immutable. You cannot create them, rename them, or delete them. You add and remove entries. That constraint is a feature: it means "blocklisted" has exactly one meaning across your organisation, and there is no way to end up with four competing face blocklists that different services check inconsistently.
Allowlists are yours to create. Known-good devices, address ranges, business entities and users go here.
Custom lists are for everything else — your own taxonomies, watch groups, review cohorts.
# Find the face blocklist
curl -X GET 'https://verification.didit.me/v3/lists/?list_type=blocklist&entry_type=face' \
-H 'x-api-key: YOUR_API_KEY'
The mechanic that matters
Here is the ordinary way to blocklist something, and it is the wrong way in almost every real situation:
curl -X POST 'https://verification.didit.me/v3/lists/{list_uuid}/entries/' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{ "value": "203.0.113.44" }'
That blocklists one address. Meanwhile the session you were investigating also carried a face, a document number, a phone, an email and a device fingerprint — every one of them an identifier the operator has to replace before returning.
The better call:
curl -X POST 'https://verification.didit.me/v3/lists/{list_uuid}/entries/' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{ "reference_session_id": "a7f3...c19" }'
Pass reference_session_id and Didit auto-extracts the right value for that list's entry type from the session, marks the underlying model as blocklisted, and links the entry back to the session so the console can show you where it came from.
Three things fall out of that, and all three matter operationally:
No manual extraction. Your analyst does not read a device fingerprint off a screen and retype it. Transcription errors in enforcement data are silent failures — the ban simply does not fire, and nobody finds out.
Provenance is preserved. Every entry links back to the session that justified it. When someone asks in four months why this device is blocked, the answer is one click, not an archaeology project.
Enforcement is repeatable. The same call against each entry-type blocklist covers the session's whole identifier surface.
If a session contains multiple instances of the same type, pass value alongside reference_session_id to disambiguate.
You can also enforce from outside a verification session. reference_object_uuid together with metadata.reference_type — transaction, vendor_user or vendor_business — blocklists from a transaction or from a vendor user or business, and keeps the same link back to the source.
The 12 entry types
| Entry type | Blocks | Notes |
|---|---|---|
face | The person | Also loadable directly via face-upload |
document | The credential | |
phone | The number | Auto-normalised to E.164 |
email | The address | |
ip_address | The address or range | Accepts CIDR, e.g. 10.0.0.0/8 |
device_fingerprint | The machine | Minimum 8 alphanumeric characters |
wallet_address | The on-chain address | |
bank_account | The account | |
user | The user record | |
business | The entity | |
country | The jurisdiction | |
key | A custom key |
Two are worth calling out for this problem.
ip_address accepts a CIDR range. Blocklisting 203.0.113.0/24 blocks the infrastructure, not one address. When a farming operation runs on a rented subnet, this is the difference between enforcement that scales and enforcement that plays whack-a-mole. Use it carefully — a range covers real users too, and over-broad ranges are how you quietly ban a country's mobile carrier.
face supports direct upload. When you have an image but no session, load it straight in:
curl -X POST 'https://verification.didit.me/v3/lists/{list_uuid}/entries/face-upload/' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{ "image": "<base64-encoded image>" }'
Didit extracts the biometric. From then on, that face is screened at every verification.
What happens after an entry lands
Adding to a system blocklist blocks future matches immediately at verification time. There is no propagation delay and no batch job.
At the next verification, the enforcement surfaces as warnings:
FACE_IN_BLOCKLIST— definitive match, verification declined.POSSIBLE_FACE_IN_BLOCKLISTis a borderline match below the hard threshold and should route to review, not decline.IP_ADDRESS_IN_BLOCKLIST/DEVICE_FINGERPRINT_IN_BLOCKLIST— network and device hits.
In Face Search, a blocklist match is the only thing that sets status to "Declined". Every match in the response also carries is_blocklisted, so an investigation shows you immediately which parts of a cluster are already under enforcement and which are still live.
Removal is symmetric: deleting an entry unblocks the matching entity. Enforcement is reversible by design, which matters because over-broad enforcement is a real risk and you need a clean path back.
curl -X DELETE 'https://verification.didit.me/v3/lists/{list_uuid}/entries/{entry_uuid}/' \
-H 'x-api-key: YOUR_API_KEY'
Allowlists: protecting the developers you want
Enforcement that only escalates eventually strangles the product. The same 12 entry types support allowlists, and they are the pressure valve.
Allowlist the office IP ranges of a design partner. Allowlist the devices of an enterprise customer's engineering team. Allowlist a verified business entity so its users never hit an escalation path. IP_ADDRESS_IN_ALLOWLIST and DEVICE_FINGERPRINT_IN_ALLOWLIST fire when a match occurs, so you can confirm the exemption applied rather than assuming it did.
This is the mechanism that makes aggressive enforcement survivable. You can afford a strict policy on unknown infrastructure precisely because your known-good population is explicitly carved out.
Errors worth handling
- 400 — the value failed the entry type's validator, the
list_typeis wrong for the operation (for example, a face-upload against a non-face list), orreference_session_idhas no data of the requested type. That last case is common and benign: not every session captures every identifier. - 403 —
{"detail": "You do not have permission to perform this action."}
Note that a 400 from "session has no data of that type" is expected when you loop a session across all the entry-type blocklists. Handle it as a skip, not a failure.
A worked enforcement flow
An analyst has confirmed abuse on account acct_8842.
- Resolve the cluster first. Face Search on the session's face returns twelve accounts; device and IP correlation pulls in another dozen. Enforcement before resolution bans one account and warns the operator.
- Blocklist from the confirmed session —
reference_session_idagainst the face, device, IP, email, phone and document blocklists. Six calls, no manual extraction, full provenance. - Consider the range. If the network evidence points at rented infrastructure, a CIDR entry covers the subnet. Check what else lives there first.
- Act on the cluster according to your own policy — the accounts you already identified do not un-ban themselves.
- Verify the enforcement. Re-run the face search. Matches should now carry
is_blocklisted: true. - Wait for the regeneration attempt. The next account created on that face, device or subnet declines at verification instead of appearing in your traffic three weeks later.
Step 6 is the whole point. The operator's cost to return is no longer "make a new email address." It is "acquire new hardware, new network, and a new person."
Use cases
AI API platforms converting a confirmed distillation or abuse case into enforcement across every identifier the operator touched.
Trial and credit abuse where the same device and face keep returning for a new free allocation.
Marketplaces blocking removed sellers from re-registering under a new business.
iGaming enforcing self-exclusion, where a returning excluded player is a regulatory failure and face-level enforcement is the only reliable control.
Frequently asked questions
Can I create my own blocklist?
No. Blocklists are system-created, one per entry type, and immutable — you add and remove entries. You can create allowlists and custom lists freely. The constraint keeps "blocklisted" meaning one thing everywhere.
How fast does an entry take effect?
Immediately, at the next verification.
What if I blocklist something by mistake?
Delete the entry and the entity is unblocked. This is why provenance matters — every entry created from a session links back to it, so you can audit what an entry was for before removing it.
Does blocklisting an IP range affect legitimate users on that range?
Yes, and that is the risk. A CIDR entry blocks everything inside it. Use ranges when the evidence points at dedicated infrastructure, use single addresses otherwise, and allowlist known-good ranges first.
Can I blocklist from something that is not a verification session?
Yes. reference_object_uuid plus metadata.reference_type (transaction, vendor_user or vendor_business) covers transactions and vendor users or businesses.
Does this stop model extraction?
No. It stops a specific known actor from re-entering through the identifiers you have enforced against, and it raises the cost of regeneration. Detecting extraction in the first place is your traffic layer's job, and limiting what extraction yields is your model layer's job. This is the enforcement arm of a three-layer defense, not a replacement for the other two.
Ready to get started?
The Lists API is available on every Didit account.
- Read the docs — Lists API overview and the IP & Device warning catalogue.
- See the product — User Verification.
- Check the pricing — publicly listed, pay-per-success, no minimums.
- Start free — business.didit.me, 500 KYC verifications a month at no cost.
Related articles
- The Hydra Account Problem: Why Distillation Defense Starts With Identity Resolution
- Business Verification for AI API Access: Who Actually Controls This Account?
- Verified API Access for AI Model Providers: A Risk-Tiered Architecture
- Face Search 1:N: Finding Every Account One Person Controls
- Biometric Step-Up for AI API Access: Binding Privilege to a Person
- Hydra Account Networks: How 20,000 Accounts Become One Actor