Overview
Introduction
Brand Assure Screen is a real-time fraud detection API that screens signup identity across five parallel checks: email verification, phone validation, IP reputation, domain reputation, and domain age.
A single POST request returns a composite trust score (0-100), component scores for each check, hard-fail signals, human-readable risk and trust factors, cross-signal intelligence alerts, and an AI-generated summary with salesperson-friendly notes.
The instant response is delivered in under 500ms. The AI summary is generated asynchronously and can be retrieved by polling or received via webhook.
Base URL: https://screen.brandassure.com/api/v1
Security
Authentication
All API requests require a Bearer token in the Authorization header. API keys can be created and managed from the API Keys page in your dashboard.
Authorization: Bearer ba_live_your_api_key_hereKey format
Live keys start with ba_live_ followed by 32 hex characters. The full key is shown only once at creation time.
Keep your API key secret. Do not commit it to version control or expose it in client-side code.
Endpoint
POST /v1/screen
Submit identity data to be screened. All four identity fields are required. Optional metadata can be included for HubSpot integration and OTP verification status.
POST /api/v1/screen
Content-Type: application/json
Authorization: Bearer ba_live_...
{
"email": "john@example.com",
"phone": "+447700900123",
"domain": "example.com",
"ip": "203.0.113.42",
"metadata": {
"hubspot_record_id": "12345",
"email_otp_verified": false,
"phone_otp_verified": false
}
}Required Fields
| Field | Type | Validation |
|---|---|---|
| string | Valid email format (RFC 5321) | |
| phone | string | E.164 format with country code (e.g., +447700900123) |
| domain | string | Valid domain name without protocol (e.g., example.com) |
| ip | string | Valid IPv4 or IPv6 address |
Optional Metadata
| Field | Type | Description |
|---|---|---|
| hubspot_record_id | string | HubSpot record ID for automatic CRM push |
| email_otp_verified | boolean | Whether the email has been OTP-verified by your system |
| phone_otp_verified | boolean | Whether the phone has been OTP-verified by your system |
Reference
Response Format
A successful response returns the full screening result including all component scores, risk factors, and AI summary status.
{
"request_id": "ba_scr_k8x9m2p4q7w1",
"email": {
"trust_score": 85,
"is_disposable": false,
"is_free_provider": false,
"is_valid_format": true,
"is_deliverable": true,
"is_catch_all": false,
"domain_age_days": 2920,
"domain_registered": true,
"has_mx_records": true,
"has_spf_record": true,
"has_dmarc_record": true,
"smtp_exists": true,
"should_block": false,
"suspicious_tld": false,
"risky_tld": false,
"domain_popular": true,
"role_address": false
},
"phone": {
"trust_score": 70,
"is_valid": true,
"phone_type": "voip",
"carrier": "Vonage",
"country_code": "GB",
"country_name": "United Kingdom",
"is_disposable": false,
"is_voip": true,
"has_abuse_reports": false,
"abuse_score": 0
},
"ip": {
"trust_score": 62,
"risk_score": 38,
"is_tor": false,
"is_proxy": false,
"is_vpn": false,
"is_hosting": false,
"blacklist_count": 3,
"total_blacklists": 112,
"country_code": "GB",
"country_name": "United Kingdom",
"city": "London",
"isp": "BT",
"asn": "AS2856"
},
"domain_reputation": {
"trust_score": 78,
"risk_score": 22,
"is_blacklisted": false,
"blacklist_count": 0,
"total_blacklists": 56,
"alexa_rank": 1523,
"is_parked": false,
"has_whois_privacy": false,
"is_free_hosting": false,
"suspicious_tld": false,
"server_country": "US",
"registrar": "GoDaddy",
"domain_not_registered": false
},
"domain_age": {
"trust_score": 100,
"domain_age_days": 9125,
"creation_date": "2001-01-15T00:00:00Z",
"expiration_date": "2028-01-15T00:00:00Z",
"age_band": "mature"
},
"score": {
"composite": 73,
"components": {
"email_trust": 85,
"phone_trust": 70,
"ip_trust": 62,
"domain_trust": 78,
"domain_age_trust": 100
},
"cross_signal_modifier": -5,
"final_score": 68,
"hard_fails": [],
"risk_factors": [
"IP flagged on 3 blacklists",
"VoIP phone number detected",
"Domain hosted in different country than IP"
],
"trust_factors": [
"Email domain is 8 years old",
"Domain has high Alexa rank (1523)",
"No disposable indicators",
"Business domain registered for 25 years"
],
"cross_signal_alerts": [
"Domain server country (US) differs from IP country (GB)"
]
},
"ai_summary": {
"status": "pending",
"poll_url": "/api/v1/screen/ba_scr_k8x9m2p4q7w1/summary"
},
"degraded_checks": []
}Graceful degradation: When domain age data is unavailable (WHOIS lookup failed), the response includes degraded_checks: ["domain_age"], domain_age.unavailable: true, and domain_age_trust: null in the component scores. The composite score is re-weighted across the remaining 4 checks. The array is empty when all checks succeed.
Email Fields
| Field | Type | Description |
|---|---|---|
| trust_score | number | Composite email trust score (0-100, trust direction) |
| is_disposable | boolean | Email uses a disposable/temporary provider |
| is_free_provider | boolean | Email uses a free provider (Gmail, Yahoo, etc.) |
| is_valid_format | boolean | Email address passes format validation |
| is_deliverable | boolean | Email is likely deliverable (derived from MX records + valid format) |
| is_catch_all | boolean | Domain accepts all email addresses |
| domain_age_days | number | null | Age of the email domain in days |
| domain_registered | boolean | Email domain is registered and active |
| has_mx_records | boolean | Domain has MX records configured |
| has_spf_record | boolean | Domain has SPF record configured |
| has_dmarc_record | boolean | Domain has DMARC record configured |
| smtp_exists | boolean | SMTP server responds for this domain |
| should_block | boolean | Upstream recommends blocking this email |
| suspicious_tld | boolean | Email uses a suspicious top-level domain |
| risky_tld | boolean | Email uses a high-risk top-level domain |
| domain_popular | boolean | Domain is a well-known provider |
| role_address | boolean | Address is a role-based address (info@, admin@, etc.) |
Phone Fields
| Field | Type | Description |
|---|---|---|
| trust_score | number | Derived phone trust score (0-100, trust direction) |
| is_valid | boolean | Phone number passes format and carrier validation |
| phone_type | string | Number type: mobile, fixed_line, voip, toll_free, unknown |
| carrier | string | null | Carrier/operator name |
| country_code | string | ISO 3166-1 alpha-2 country code |
| country_name | string | Full country name |
| is_disposable | boolean | Number is from a disposable/virtual provider |
| is_voip | boolean | Number is a VoIP number |
| has_abuse_reports | boolean | Number has been reported for abuse/spam |
| abuse_score | number | Abuse confidence score (0-100) |
IP Fields
| Field | Type | Description |
|---|---|---|
| trust_score | number | Inverted IP risk score (0-100, trust direction) |
| risk_score | number | Original risk score from upstream (0-100, risk direction) |
| is_tor | boolean | IP is a known Tor exit node |
| is_proxy | boolean | IP is a known proxy server |
| is_vpn | boolean | IP is a known VPN endpoint |
| is_hosting | boolean | IP belongs to a hosting/cloud provider |
| blacklist_count | number | Number of blacklists this IP appears on |
| total_blacklists | number | Total blacklists checked |
| country_code | string | ISO 3166-1 alpha-2 country code |
| country_name | string | Full country name |
| city | string | null | City name from geolocation |
| isp | string | null | Internet Service Provider name |
| asn | string | null | Autonomous System Number |
Domain Reputation Fields
| Field | Type | Description |
|---|---|---|
| trust_score | number | Inverted domain risk score (0-100, trust direction) |
| risk_score | number | Original risk score from upstream (0-100, risk direction) |
| is_blacklisted | boolean | Domain appears on reputation blacklists |
| blacklist_count | number | Number of blacklists this domain appears on |
| total_blacklists | number | Total blacklists checked |
| alexa_rank | number | null | Alexa global traffic rank (lower = more popular) |
| is_parked | boolean | Domain is parked (no real content) |
| has_whois_privacy | boolean | WHOIS records use privacy protection |
| is_free_hosting | boolean | Domain uses free hosting service |
| suspicious_tld | boolean | Domain uses a suspicious TLD |
| server_country | string | null | Country where domain is hosted |
| registrar | string | null | Domain registrar name |
| domain_not_registered | boolean | Domain WHOIS lookup failed (not registered) |
Domain Age Fields
| Field | Type | Description |
|---|---|---|
| trust_score | number | Age-based trust score (0-100, graduated bands) |
| domain_age_days | number | null | Domain age in days since registration |
| creation_date | string | null | Domain registration date (ISO 8601) |
| expiration_date | string | null | Domain expiration date (ISO 8601) |
| age_band | string | Categorised age: very_new, new, moderate, established, mature, unknown |
| unavailable | boolean | True when WHOIS lookup failed. All other fields will be null/zero/unknown. |
Scoring
Scoring Framework
Trust Direction
All scores use trust direction: 0 = maximum risk, 100 = maximum trust. Some upstream providers return scores in risk direction (0 = safe, 100 = risky) - we invert these before returning them.
Composite Formula
Standard (5 components):
Brand Assure Score = (email × 0.25) + (phone × 0.10) + (ip × 0.25)
+ (domain × 0.20) + (domain_age × 0.20)
Degraded (domain age unavailable — 4 components, re-weighted):
Brand Assure Score = (email × 0.3125) + (phone × 0.125)
+ (ip × 0.3125) + (domain × 0.25)
Cross-signal modifier applied after composite (clamped to 0-100).
Final score = composite + cross_signal_modifierWhen domain age data is unavailable (e.g. WHOIS lookup failed for certain TLDs or privacy-protected domains), the score is calculated from 4 components with proportionally re-weighted values. The response will include degraded_checks: ["domain_age"] and domain_age_trust: null in the component scores.
Score Interpretation
| Range | Band | Interpretation |
|---|---|---|
| 70-100 | Pass | Strong identity signals across all checks |
| 40-69 | Review | Mixed signals — some checks flagged concerns |
| 0-39 | Fail | Multiple negative indicators detected |
Brand Assure provides screening data — your team decides how to act on it. Any hard-fail signal overrides the composite score regardless of the numeric value.
Signals
Hard Fail Signals
Hard-fail signals indicate critical risk indicators that should trigger immediate action regardless of the composite score. Review triggers are less severe but warrant manual inspection.
| Code | Source | Condition | Severity |
|---|---|---|---|
| DISPOSABLE_EMAIL | is_disposable is true | Hard Fail | |
| SHOULD_BLOCK_EMAIL | should_block is true | Hard Fail | |
| DISPOSABLE_PHONE | Phone | is_disposable is true | Hard Fail |
| INVALID_PHONE | Phone | is_valid is false | Hard Fail |
| TOR_EXIT_NODE | IP | is_tor is true | Hard Fail |
| IP_HEAVILY_BLACKLISTED | IP | blacklist_count > 10 | Hard Fail |
| DOMAIN_BLACKLISTED | Domain | is_blacklisted is true | Hard Fail |
| DOMAIN_NOT_REGISTERED | Domain | domain_not_registered is true | Hard Fail |
| DOMAIN_VERY_NEW | Domain Age | domain_age_days < 30 (skipped when unavailable) | Review |
| ABUSIVE_PHONE | Phone | has_abuse_reports is true | Review |
Intelligence
Cross-Signal Intelligence
After individual checks complete, Brand Assure Screen correlates signals across all five data sources to detect inconsistencies that individual checks might miss.
Geographic Consistency
Compares the IP geolocation country, phone number country code, and domain server country. Mismatches between these reduce the composite score and generate alerts.
Email-Domain Alignment
Checks whether the email address domain matches the submitted business domain. A mismatch (e.g., using a Gmail address for a business claiming to be example.com) triggers a negative modifier.
Infrastructure Consistency
Analyses hosting provider patterns. If the IP belongs to a known hosting/cloud provider but the user claims to be a residential customer, this generates an alert.
AI
AI Summary
Every screen check generates a natural-language AI summary using Claude. The summary is generated asynchronously after the instant response is returned.
Polling Endpoint
GET /api/v1/screen/{request_id}/summary
Authorization: Bearer ba_live_...
Response:
{
"status": "complete", // pending | generating | complete | failed
"summary": "Email domain doesn't match business domain...",
"salesperson_notes": "- VoIP number detected\n- Domain registered 3 days ago",
"generated_at": "2026-02-20T14:30:07Z"
}Webhook Delivery
If you have a webhook endpoint configured, the full screening result including the AI summary will be delivered automatically once the summary is complete. See the Webhook Specification section below.
Typical latency: AI summaries complete in 2-4 seconds after the instant response. Poll every 1 second until status is complete or failed.
Delivery
Webhook Specification
Configure webhook endpoints from your Webhooks dashboard page. Webhooks deliver the full screening result including the AI summary once it is generated.
Delivery Headers
POST {your_webhook_url}
Content-Type: application/json
X-BrandAssure-Event-Type: screen.completed
X-BrandAssure-Delivery-Id: del_a1b2c3d4e5
X-BrandAssure-Timestamp: 2026-02-20T14:30:05Z
X-BrandAssure-Signature: sha256=<HMAC-SHA256 hex digest>Verifying Signatures
To verify a webhook delivery, compute the HMAC-SHA256 hex digest of the raw request body using your endpoint signing secret and compare it with the value in X-BrandAssure-Signature (after stripping the sha256= prefix). Use a constant-time comparison to prevent timing attacks.
Replay protection: Always validate the X-BrandAssure-Timestamp header. Reject deliveries where the timestamp is more than 5 minutes old. This prevents attackers from replaying captured webhook payloads.
Retry Strategy
| Attempt | Delay | Cumulative |
|---|---|---|
| 1 | Immediate | 0s |
| 2 | 5 seconds | 5s |
| 3 | 30 seconds | 35s |
| 4 | 2 minutes | ~2.5min |
| 5 | 15 minutes | ~17.5min |
| 6 | 1 hour | ~1.3hr |
| 7 | 4 hours | ~5.3hr |
| 8 | 8 hours | ~13.3hr |
Response Handling
- 2xxDelivery successful - marked as delivered
- 4xxPermanent failure - not retried (except 429)
- 5xxTemporary failure - retried per schedule above
Failed Deliveries: After 8 failed attempts, the delivery is marked as failed. Failed deliveries are retained for 30 days and can be retried from the Failed Deliveries page. Use the X-BrandAssure-Delivery-Id header for idempotent processing.
Errors
Error Codes
All error responses follow a consistent JSON structure. Each error includes a machine-readable code, a human-readable message, and a unique request ID for support enquiries.
| Code | Status | Description & Customer Action |
|---|---|---|
| AUTHENTICATION_REQUIRED | 401 | Missing or invalid API key. Ensure the Authorization header is set with a valid Bearer token. |
| API_KEY_REVOKED | 401 | The API key has been revoked. Generate a new key from your dashboard. |
| API_KEY_EXPIRED | 401 | The API key has expired. Generate a new key from your dashboard. |
| IP_NOT_ALLOWED | 403 | Request IP is not in the key's allowlist. Update IP restrictions in your dashboard. |
| RATE_LIMIT_EXCEEDED | 429 | Per-second rate limit exceeded. Wait and retry after the X-RateLimit-Reset timestamp. |
| INSUFFICIENT_BALANCE | 402 | Insufficient balance for this check. Top up your account to continue. |
| VALIDATION_FAILED | 400 | One or more input fields failed validation. Check the details object for specifics. |
| INVALID_JSON | 400 | Request body is not valid JSON. Ensure Content-Type is application/json. |
| UPSTREAM_TIMEOUT | 504 | Upstream check(s) timed out after retry. Retry the request. |
| UPSTREAM_OVERLOADED | 503 | System at capacity. Retry after a brief wait. |
| UPSTREAM_ERROR | 502 | Upstream server error after retry. Retry the request. |
| UPSTREAM_PERMANENT_ERROR | 422 | Upstream reported an input/configuration error. Check input data. |
| INTERNAL_ERROR | 500 | Unexpected server error. Contact support if the issue persists. |
Error Response Format
Validation errors include a details object with per-field error messages:
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Invalid input",
"request_id": "ba_req_k8x9m2p4q7w1",
"details": {
"email": ["Invalid email format"],
"phone": ["Expected string, received number"]
}
}
}Upstream Error Responses
When one or more upstream checks fail (timeout, overloaded, or error), the response includes an endpoint_status object showing the outcome of each individual check:
{
"error": {
"code": "UPSTREAM_TIMEOUT",
"message": "Screen could not be completed: 1 of 5 upstream checks timed out",
"request_id": "ba_req_abc123",
"endpoint_status": {
"email": "ok",
"phone": "ok",
"ip": "timeout",
"domain_reputation": "ok",
"domain_age": "ok"
}
}
}Endpoint status values: ok (check succeeded), timeout (timed out after retry), error (upstream server error), permanent_error (upstream input/configuration error), degraded (check unavailable — result calculated without this check).
Domain age is currently the only degradable check. When it fails, the screen still completes with a re-weighted score from the remaining 4 checks.
Quick Start
Code Examples
Complete examples including screen check and AI summary polling. Choose your language below.
curl -X POST https://screen.brandassure.com/api/v1/screen \
-H "Authorization: Bearer ba_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"email": "john@example.com",
"phone": "+447700900123",
"domain": "example.com",
"ip": "203.0.113.42",
"metadata": {
"hubspot_record_id": "12345",
"email_otp_verified": false,
"phone_otp_verified": false
}
}'
# Poll for AI summary
curl https://screen.brandassure.com/api/v1/screen/ba_scr_k8x9m2p4/summary \
-H "Authorization: Bearer ba_live_your_api_key"Need help? Contact support from your dashboard settings.