Profile Blacklist
The Profile Blacklist feature lets you define validation rules that block specific emails, mobile numbers, or names from being created, updated, or imported via the API. When a profile operation is attempted with a blacklisted value, the API returns a 422 error with a descriptive message.
Concepts
Validation Rule
A Validation Rule defines what field to check, how to match against it, and when to apply the check.
| Field | Description |
|---|---|
name | Human-readable label for the rule |
type | Field to validate: email, mobile, or name |
rule_type | How to match: exact, domain, prefix, or regex |
applies_to | When to enforce: create, update, import, or all |
pattern | Regex pattern — only used when rule_type is regex |
error_message | Custom error message returned to the caller. Falls back to a default if not set |
priority | Integer. Lower numbers are evaluated first |
is_active | Whether the rule is currently enforced |
effective_from | Optional datetime — rule is ignored before this time |
effective_to | Optional datetime — rule is ignored after this time |
Validation Rule Value
A Value is a single entry that the rule matches against. Each rule can have many values. Values default to is_active: false and must be explicitly activated.
| Field | Description |
|---|---|
value | The string to match against (email address, domain, phone prefix, name, etc.) |
is_active | Whether this value is active. Defaults to false |
Rule Types
rule_type | Applies to | Behaviour |
|---|---|---|
exact | email, mobile, name | Blocks an exact match against the normalised value |
domain | email | Blocks any email address from the specified domain |
prefix | email, mobile | Blocks any value that starts with the specified prefix |
regex | email, mobile, name | Blocks any value matching the regex pattern on the rule. No values needed |
Normalisation
Values are normalised before matching to avoid trivial bypasses:
- Email — lowercased and trimmed.
[email protected]matches[email protected] - Mobile — normalised to E.164 format using the phone number library
- Name — lowercased, leading/trailing whitespace trimmed, internal whitespace collapsed to a single space
Applies To
| Value | When the rule is checked |
|---|---|
create | Profile creation via POST /profiles |
update | Profile update via PATCH /profiles/{id} |
import | Batch/import via POST /batches |
all | All of the above |
Note: For
updateandimportupdates, a field is only checked if its value is actually changing. Sending the existing email in an update payload will not trigger the blacklist.
API Endpoints
Validation Rules
| Method | Endpoint | Description |
|---|---|---|
GET | /profiles/validation-rules | List all rules (paginated, includes values) |
POST | /profiles/validation-rules | Create a rule |
GET | /profiles/validation-rules/{ruleId} | Get a rule with its values |
DELETE | /profiles/validation-rules/{ruleId} | Delete a rule and all its values |
Values
| Method | Endpoint | Description |
|---|---|---|
GET | /profiles/validation-rules/{ruleId}/values | List values for a rule |
POST | /profiles/validation-rules/{ruleId}/values | Add a value to a rule |
GET | /profiles/validation-rules/{ruleId}/values/{valueId} | Get a single value |
DELETE | /profiles/validation-rules/{ruleId}/values/{valueId} | Delete a value |
Examples
Block an entire email domain
Create the rule:
POST /profiles/validation-rules
{
"name": "Block disposable email domains",
"type": "email",
"rule_type": "domain",
"applies_to": "all",
"error_message": "This email domain is not permitted.",
"is_active": true
}Add a domain value and activate it:
POST /profiles/validation-rules/1/values
{
"value": "mailinator.com",
"is_active": true
}Any profile creation or update using an @mailinator.com address will now receive:
{
"message": "This email domain is not permitted.",
"errors": {
"email": ["This email domain is not permitted."]
}
}Block specific email addresses
POST /profiles/validation-rules
{
"name": "Known fraud emails",
"type": "email",
"rule_type": "exact",
"applies_to": "all",
"is_active": true
}POST /profiles/validation-rules/2/values
{
"value": "[email protected]",
"is_active": true
}Block mobile number prefixes
POST /profiles/validation-rules
{
"name": "Block premium rate numbers",
"type": "mobile",
"rule_type": "prefix",
"applies_to": "all",
"is_active": true
}POST /profiles/validation-rules/3/values
{
"value": "+1900",
"is_active": true
}Any mobile number starting with +1900 will be blocked.
Block names using regex
POST /profiles/validation-rules
{
"name": "Block test names",
"type": "name",
"rule_type": "regex",
"applies_to": "create",
"pattern": "/^test\\s/i",
"is_active": true
}No values are needed for regex rules — the pattern field on the rule is used directly.
Inline values on rule creation
You can create a rule and its values in a single request:
POST /profiles/validation-rules
{
"name": "Block spam domains",
"type": "email",
"rule_type": "domain",
"applies_to": "all",
"is_active": true,
"values": [
{ "value": "spam.com", "is_active": true },
{ "value": "trash.com", "is_active": true }
]
}When updating a rule, passing values replaces all existing values. Omitting values leaves them untouched. Passing values: [] removes all values.
Deactivate a single value
PATCH /profiles/validation-rules/1/values/5
{
"is_active": false
}Error Response
When a profile operation is blocked, the API returns 422 Unprocessable Entity:
{
"message": "Cannot create profile with blacklisted contact details",
"errors": {
"email": ["Cannot create profile with blacklisted contact details"]
}
}The error key matches the offending field (email, mobile_phone, or first_name). The message is either the rule's custom error_message or one of the built-in defaults below.
| Operation | Field | Default message |
|---|---|---|
| Create / Import | email or mobile | Cannot create profile with blacklisted contact details |
| Update | email or mobile | Blacklisted contact details cannot be added to this profile |
| Create / Import | name | Cannot create profile with blacklisted name |
| Update | name | Blacklisted name cannot be added to this profile |
Updated about 18 hours ago
