Start with the industries endpoint
Anindustry rule matches the enriched company industry exactly, case-insensitive. A value that never appears in your data suppresses nothing, silently, and you keep paying for those visitors. Ed Tech does not match Higher Education.
Call the industries endpoint first and copy each value verbatim into your rules.
visitors is how many identified visitors carry that industry, so you can see what a rule would actually cost you. suppressed tells you a rule already exists.
meta.visitorsWithoutIndustry counts identified visitors with no company industry at all. No industry rule can reach them. Suppress those by domain or email instead.
The email, domain, and company_domain types do not have this problem. They are normalized on both sides, so an exact-match mistake is not possible in the same way.
Rule types
Values are normalized before storage
Values are lowercased. Domains lose their scheme,www., path, and port. Submitting https://www.acme-partners.example/pricing stores acme-partners.example, and that normalized value is what you get back when you read the list. This surprises people reconciling an upload against a source file.
Because normalization is deterministic, re-uploading the same list is a no-op. Retries are safe and no Idempotency-Key is needed.
Append or replace
UsePOST to add rules on top of what is already stored. This is the normal upload path.
Use PUT when a file is your source of truth. It deletes every existing rule and replaces it with what you submit, in one transaction, so re-posting the whole list on every sync run keeps the stored list matching the file exactly.
Pass types on PUT to scope the replace to certain rule types and leave the rest untouched — sync your email list without disturbing industry rules. Send an empty rules array together with types to clear a category.
Both endpoints accept up to 25,000 rules per call. A list longer than that cannot be replaced atomically, so build it up with POST instead.
One bad row does not fail the batch
Rows that fail validation come back inrejected. Every other row is still applied, so a 5,000-row CSV does not fail on one bad cell.
index is the position of the row in the array you submitted. rejected carries detail for the first 100 failures; rejectedCount is the true total. duplicates counts rows skipped because they were already stored or repeated inside the same request.
Rules take effect going forward
Suppression is forward-only. A new rule applies from the next sync cycle onward, and visitors you were already charged for are not refunded. Removing a rule works the same way: it stops suppressing from the next cycle.Reading the list back
limit defaults to 500 and caps at 5000. counts and total always describe the whole list, not the page you requested, so use them to drive pagination rather than counting rows.
Removing rules
Delete in bulk by rule id, bytype and value, or both at once. Values are normalized the same way as on upload, so you can delete using the exact rows you uploaded without ever tracking ids. Unknown ids and values are ignored.
DELETE /v1/data/suppression-rules/{ruleId} when you already hold the id of a single rule.