POST /v1/phishing/url-assessments
URL Assessments
Combine URL reputation with local warning signals. Optional active mode inspects HTTP redirects and submits the URL to a private URLScan browser scan. Every result describes what ran and what remains unverified.
No verdict guarantees safety
no_known_threats means the requested checks completed without a detected threat. It does not mean safe or legitimate. New threats, targeting, changing content and scan limitations can cause misses. A familiar cloud-storage domain does not establish who authored its content.
Modes, privacy and credits
| Mode | Checks and limits | Credits |
|---|---|---|
| passive (default) | Up to 20 items. Reputation and local URL/context signals. No destination fetch or browser scan. | 2 |
| active | Exactly one item. HTTP redirect inspection, private URLScan analysis, and reputation for input, hops and effective URL. | 6 |
The aggregate endpoint charges credits only when all requested checks complete; incomplete assessments use zero credits. Sandbox request quotas are separate.
The public sandbox supports passive assessments only. Active mode requires a personal API key; sandbox active requests return HTTP 403 with code active_scan_requires_api_key, without starting an active scan.
Active mode requires privacy.visibility: "private" and privacy.allow_external_submission: true. It contacts the destination and sends the URL to URLScan. It may consume one-time links or notify a sender. Private visibility is required; there is no fallback to unlisted or public scanning. Confirm your data-processing policy before submitting sign-in tokens or confidential document links.
Passive mode still sends URLs to the reputation provider. Do not confuse no destination fetch with no external processing. Optional context should contain only the relevant facts, not a full email.
Request
Requires phishing:read permission. Each item requires a unique opaque id (1–100 letters, digits, underscores or hyphens) and an HTTP(S) url (up to 8192 characters, no credentials, whitespace or control characters). Optional context fields are message_is_spam (boolean), link_text, claimed_brand, and sender_domain (strings, limited to 500, 100 and 253 characters respectively). Unknown request fields are rejected. Context supplies warning signals; it does not prove a URL is malicious.
curl -X POST https://api.dfir-lab.ch/v1/phishing/url-assessments \
-H "Authorization: Bearer $DFIR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [{"id": "link-1", "url": "https://example.com/page"}],
"mode": "passive"
}'Active request body
{
"items": [
{
"id": "link-1",
"url": "https://example.com/page",
"context": {
"message_is_spam": true
}
}
],
"mode": "active",
"privacy": {
"visibility": "private",
"allow_external_submission": true
}
}Response and client handling
The standard envelope contains data.schema_version: "1", data.mode, data.results, and request/credit meta. Each item includes:
idandsubmitted_url: bind evidence to the requested item. Never substitute the first result for a missing URL.state:complete,partial, orfailed. This describes check completion separately from risk.risk:malicious,suspicious,no_known_threats, orunknown.coverage: separate reputation, redirects and content check states:complete,incomplete, ornot_requested. Passive mode does not inspect content or expand redirects.providers: source names, statuses and source-specific results. Provider failures remain explicit.evidence: reason code, severity, message, and optional URL. Positive evidence survives failures in other checks.checked_at,expires_at,limitations, andpolicy_version: "url-assessment-1".
Treat unknown fields additively, but reject unknown verdicts, malformed rows and missing identities as unverified. Do not map failed, partial, missing, timed-out, or empty results to a clean state. Cache using the returned expiry, keyed by exact URL, mode and relevant context. Unknown incomplete results expire immediately. Malicious or suspicious evidence remains valid until its returned expiry even when another check is incomplete; Safe Browsing matches retain at least the provider's cache duration. Expiry means evidence needs refreshing, not that a previously flagged URL became safe.
This endpoint returns synchronous results. There is no persisted job or polling API. A scan that does not finish returns explicit incomplete coverage. An HTTP success status alone is not evidence that all checks completed.
The route has a 55-second overall deadline within its 60-second runtime limit. Active browser analysis receives at most 30 seconds, reduced when needed to leave time for validation, reputation and billing. If the route cannot complete within its deadline, it returns HTTP 503 with code url_assessment_timeout; safety remains unknown. Allow transport overhead in the client timeout. A longer client timeout does not extend server-side scan coverage.
Coverage boundaries
HTTP expansion validates each destination and pins connections to validated public addresses. It does not execute JavaScript or follow HTML meta-refresh locally. Active content analysis comes from the external URLScan browser service. The browser-observed effective URL is independently checked for a public destination before being sent to reputation lookup or counted as complete content coverage. The browser-reported destination IP must also be a valid public address. A private, blocked or unverifiable destination leaves coverage incomplete. Authentication walls, anti-bot controls and different content served to the eventual user can limit coverage.
Use the existing Safe Browsing, URL Expand, and URLScan pages for individual operations. Their no-match results must also remain distinct from a safety guarantee.