DEVELOPER API
Build around the evidence.
Integrate email investigation, scoped evidence retrieval, and package verification with clear request contracts and explicit failure handling.
Updated Technical report, source handlers, and read-only route checks
- Interface
- HTTP / JSON / NDJSON
- Access
- Scoped server-side keys
- Evidence
- Complete signed packages
Deployment and version boundaries
This guide reconciles the 12 October 2026 technical report with the production-integration implementation synchronized into main on 13 October. A report records a particular source/runtime snapshot; a route definition, healthy host, or HTTP 200 does not prove model readiness, successful persistence, or final mail delivery.
| Capability | Production-integration implementation | 12 October reference |
|---|---|---|
| Text and direct raw email | Canonical handlers are present; text GET returns 405 because POST is required. | Evidence-aware text and original-email investigation. |
| Upload reservation and reference analysis | /uploads reserves a private original email; /analyze-upload verifies and analyzes the uploaded reference. | Private Storage, reservation expiry, and size/hash validation require the compatible deployed schema. |
| Full-package verification | POST handler accepts evidence + Passport; GET correctly returns 405. | Signature, both hashes, key identity, and configured issuer trust. |
| Key lifetime and provisioning | Owner/admin creation is plan-entitled. lifetime_days accepts 1–90 days and defaults to 30; authentication checks expiry and active membership. | Keys are returned once, stored as hashes, and exposed later as masked metadata. |
| Model hosting and schedules | Private AWS inference uses production workload identity. Model readiness remains separate from web/API availability. | The reviewed pilot used private AWS classifiers and a 07:00–19:00 IST window. |
Older releases may lack private intake and current key-lifecycle enforcement. Confirm the deployed handler/schema before reusing this guide with another installation. The documented pilot’s availability, capacity, receiver assignment, and benchmarks are separate from current route presence.
Authentication and API-key handling
Use a VeriTrust developer key as a Bearer token over HTTPS from a trusted backend or private script. The official browser uses its own same-origin session flow; do not copy browser tokens or embed developer keys in frontend JavaScript, mobile binaries, public repositories, or shared notebooks.
Authorization: Bearer vtg_live_YOUR_API_KEYUse API Access to view and manage keys permitted by your workspace plan and role. The raw key is returned once; later list responses show masked/prefix metadata. The stored key hash is not a recoverable secret. Never log request Authorization headers or signed upload tokens.
Gateway access checks the key/session’s organization, scopes, integration, feature availability, and applicable usage limits. A provided org_id cannot select a foreign organization. Key creation requires an active owner/admin membership and an enabled workspace plan. Keys expire after the configured lifetime; revocation, inactive membership, and inactive integrations also prevent later use.
Scopes and management permissions
Default detection/Gateway scopes are filtered by enabled modules. Request only the permissions your integration needs. A valid key can still be denied by an inactive integration, plan, quota, or workspace boundary.
| Scope | Purpose |
|---|---|
phishing:scan | Standalone /api/v1/phishing classifier. |
link:scan | Standalone /api/v1/link-check URL-string classification. |
usage:read | Key usage and workspace limits. |
gateway:scan | Canonical email-v2 and bounded generic Gateway submissions. |
gateway:read | Authorized scan, evidence, report, and review reads. |
gateway:cancel | Request cancellation of unfinished Gateway work. |
gateway:policy:read | Policy inventory and operations reads. |
gateway:policy:write | Policy creation/activation and review resolution. |
gateway:webhook:manage | Webhook configuration, test, and disable operations. |
Management scopes are not included in the default six scopes. Management writes additionally require owner/admin permission. A scope name alone does not authorize a foreign tenant or a receiver deployment.
Canonical email-text investigation
POST /api/v2/phishing/analyze-text requires gateway:scan, JSON, and an Idempotency-Key. Submit a subject, body, or both; the subject limit is 998 characters and the body limit 12,000. The strict schema rejects unknown fields.
{
"subject": "Payment request for review",
"body": "Please confirm this invoice through our usual contact.",
"channel": "email",
"retention_policy": "metadata_only"
}curl -X POST "https://YOUR_DOMAIN/api/v2/phishing/analyze-text" \
-H "Authorization: Bearer $VERITRUST_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: YOUR_STABLE_REQUEST_ID" \
--data-binary @message.jsonAccepted optional fields are channel, locale_hint, retention_policy, org_id, integration_id, and parent_scan_id. The channel contract accepts email (default) or sms; this guide’s product workflow is email. A locale hint is bounded to 32 characters. Retention values are none, metadata_only, temporary_file, or retained_file, subject to route and deployment behavior.
Plain text has no original MIME, headers, attachment, or directly observed SMTP facts. A linked parent must be a completed same-workspace investigation at an earlier evidence stage; linkage is not independent same-message proof. Inspect returned coverage and limitations instead of treating missing checks as passed.
Direct .eml transport and limits
POST /api/v2/phishing/analyze-eml accepts original RFC822 bytes with Content-Type: message/rfc822, Gateway scan permission, and an Idempotency-Key. Preserve bytes using --data-binary rather than converting the message into pasted JSON text.
curl -X POST "https://YOUR_DOMAIN/api/v2/phishing/analyze-eml" \
-H "Authorization: Bearer $VERITRUST_API_KEY" \
-H "Idempotency-Key: YOUR_STABLE_REQUEST_ID" \
-H "Content-Type: message/rfc822" \
--data-binary @original.emlThe parser contract allows up to 10 MiB, but the deployment’s HTTP request-body limit can be lower. The report records Vercel’s 4.5 MB direct-body boundary. For larger originals within the 10 MiB intake limit, reserve a private upload and analyze its reference rather than sending the entire file through the Vercel function.
| Boundary | Limit |
|---|---|
| Header bytes | 256 KiB |
| MIME depth / parts | 10 / 100 |
| Decoded total / attachment bytes | 25 MiB / 10 MiB |
| Normalized HTML / parser time | 1 MiB / 5 seconds |
The direct route accepts X-Retention-Policy values ephemeral_24h or temporary_file and an optional X-VeriTrust-Parent-Scan-Id. A retention request is not proof of completed deletion. Raw EML enables message-carried DKIM/ARC/alignment and relay evidence; trusted SPF requires directly observed SMTP facts.
Private RFC822 intake
The integrated runtime implements the reservation and reference-analysis routes below. It requires compatible private Storage policies and intake RPCs. Upload bytes go directly to the authorized Storage object; analysis receives a reference and verifies the stored size and hash.
- Compute the original file’s byte count and lowercase SHA-256 before reserving it.
- POST /api/v2/phishing/uploads with Gateway scan permission, JSON, and a stable Idempotency-Key. Required fields are size_bytes and sha256; optional fields are input_mode, parent_scan_id, and integration_id.
- A 201 response contains upload.id, upload_url, storage_origin, expires_at, and max_bytes. Validate the signed URL’s HTTPS origin and expected single-object path against the authorized response.
- PUT message/rfc822 bytes to that signed Storage URL. Do not forward the VeriTrust API key, cookies, or receiver secret to Storage; do not follow arbitrary redirects.
- POST only {"upload_id":"…"} to /api/v2/phishing/analyze-upload using the same identity and Idempotency-Key. The server verifies original size/hash and cannot upgrade the stored input mode through this request.
{
"size_bytes": 1024,
"sha256": "REPLACE_WITH_64_LOWERCASE_HEX_DIGITS",
"input_mode": "raw_eml"
}The reservation expires after 15 minutes; Storage-token validity and cleanup are separate windows. Its 10 MiB original-email limit does not grant permission for arbitrary media. Trusted-receiver reservations require the separate receiver authorization and validated transport context.
Retries, progress, and final responses
Email-v2 and generic Gateway submissions require an Idempotency-Key containing 1–200 printable characters. Generate and persist one identifier per logical input; reuse it for the same input and identity. A changed request with an already-used key can return 409. Standalone v1 classifiers do not implement this Gateway replay contract merely because a caller supplies the header.
Optional X-Request-ID and X-Trace-ID support correlation. Do not confuse a request ID with a stored scan ID, a delivery receipt, or a replay guarantee. Inspect scan status and any returned degraded/failed evidence before recording success.
For supported analysis paths, Accept: application/x-ndjson requests progress on the same authenticated HTTP request. This is newline-delimited JSON, not WebSockets or a durable in-memory job service. Ignore heartbeat blank lines, process sequenced progress events, and use the final result event’s status and payload.
{
"type": "result",
"status": 503,
"payload": {
"ok": false,
"error": {
"code": "EXAMPLE_FAILURE",
"message": "Illustrative failed final event"
}
}
}An outer HTTP 200 may already have been sent when streaming begins. It does not make a failed final event successful. A 202 response is pending work rather than a completed signed investigation. Retry transient failures only when the route’s idempotency contract supports safe replay; fix schema, identity, expiry, or permission errors first.
Evidence retrieval, exports, and verification
Use GET /api/v2/phishing/evidence/{scan_id} with Gateway read permission for authorized evidence. Export routes use /api/v2/phishing/export/{scan_id}/{format} with json, csv, iocs, or stix. The default export path without a format is JSON. The iocs format describes observed artifacts; STIX output is not independently confirmed maliciousness.
Keep the complete exported evidence JSON when cryptographic verification matters. A display summary, CSV, PDF, redacted excerpt, or Passport-only object is not the complete original signed package. If a historical record lacks the exact signed snapshot, do not reconstruct current rows and attach an old signature.
POST /api/v2/phishing/verify-evidence is a bounded public API, even though the website’s verifier page requires sign-in. It accepts only passport and evidence objects, with a 1 MiB request limit. It does not require an investigation key or an Idempotency-Key.
curl -X POST "https://YOUR_DOMAIN/api/v2/phishing/verify-evidence" \
-H "Content-Type: application/json" \
--data-binary @verification-request.jsonVerification returns 200 for a valid package and 422 for failed checks. Inspect verification.valid, signature_valid, evidence_hash_valid, manifest_hash_valid, key_id_valid, issuer_trusted, and error codes. Key trust is defined by the target deployment’s issuer policy.
Integrity and issuer checks do not establish safe mail, sender identity, claim truth, attribution, or legal admissibility. Verifying JSON does not separately retrieve an original .eml and recompute its byte hash.
Generic Gateway and management routes
/api/v1/gateway supports bounded text/URL correlation separately from canonical email-v2 intake. POST /scans needs Gateway scan permission and an Idempotency-Key. Content accepts text (up to 12,000 characters) and up to 20 explicitly submitted HTTP/HTTPS URLs. Generic media/deepfake fields are not accepted by the production schema.
{
"source": {
"kind": "api"
},
"content": {
"text": "Review this account message.",
"urls": [
"https://example.com/account"
]
},
"processing_mode": "synchronous",
"metadata": {
"context_categories": [
"email"
]
}
}| Route and method | Scope / behavior |
|---|---|
| GET /scans and /scans/{id} | gateway:read; tenant-scoped list/status/evidence. |
| GET /reports/{id} | gateway:read; returned report envelope. |
| POST /scans/{id}/cancel | gateway:cancel; unfinished-work cancellation request. |
| GET/POST /policies; POST /policies/{id}/activate | Policy read/write scopes; write actions require manager authorization. |
| GET/POST /webhooks; POST /webhooks/{id}/test or /disable | gateway:webhook:manage; approved destinations and manager controls. |
| GET /reviews; POST /reviews/{id}/resolve | gateway:read for listing; gateway:policy:write for resolution. |
| GET /operations | gateway:policy:read; operational evidence. |
Processing modes are synchronous, asynchronous, or hybrid. A callback references an authorized webhook_endpoint_id; configuring delivery is a separate management action. Signed webhooks and private signed worker invocations have different credentials and replay controls. Workers are not ordinary API-key or browser-session endpoints.
Standalone classifiers and compatibility paths
POST /api/v1/phishing requires phishing:scan and JSON text with the supported model alias fast. POST /api/v1/link-check requires link:scan; its implemented model is swift and its JSON can contain url, text, and context. Link classification examines the URL string and does not fetch a destination page or follow redirects.
curl -X POST "https://YOUR_DOMAIN/api/v1/phishing" \
-H "Authorization: Bearer vtg_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Please review this unexpected payment request.","model":"fast"}'curl -X POST "https://YOUR_DOMAIN/api/v1/link-check" \
-H "Authorization: Bearer $VERITRUST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/account","model":"swift"}'These standalone routes return their model/result/scores/usage envelope and record API usage. They do not create canonical email investigations or legacy dashboard history simply by completing a classifier request. The /api/v1/gateway/email analysis/evidence/export aliases are compatibility paths; use canonical v2 names in new email integrations.
Usage and error handling
GET /api/v1/usage requires usage:read and returns masked key information, daily usage, and an available workspace usage/limits snapshot. Usage reads are themselves API usage events. Key and workspace quotas, subscription status, enabled modules, and runtime/provider availability are independent checks; do not assume a fixed quota across plans.
| Status | Interpretation |
|---|---|
| 400 / 415 | Invalid schema, input, or content type. |
| 401 / 403 | Invalid authentication or denied scope/role/feature. |
| 404 | Unknown/unavailable route or resource outside authorized scope; not evidence of benign content. |
| 409 / 410 | Conflicting/replayed input state or expired upload in supporting runtimes. |
| 413 / 422 | Payload boundary / failed evidence verification. |
| 429 / 5xx | Quota/overload / provider, persistence, or runtime failure. |
API v1 responses include request_id and structured error code/message fields. Other routes have their own response envelope; do not assume every result shares the standalone v1 shape. Store bounded request/scan identifiers for support without logging credentials or raw submitted mail.
Trusted receiver and runtime prerequisites
Internal receiver-eml and receiver-event routes require both scoped Gateway authentication and the configured receiver secret. Original raw email or an authorized stored reference must be accompanied by validated client_ip, mail_from, helo, receiver_id, authserv_id, received_at, and event_id facts.
Arbitrary message headers cannot create trusted SMTP provenance. A controlled hardened edge supplies transport observations; the bare Node companion requires a private environment or a separate hardened TLS edge. Consult the receiver guide for controlled setup.
The supplied report’s connected receiver/status and Gmail pilot are operator-assigned integrations, not an automated multi-organization provisioning wizard. New organizations require explicit credential, recipient, domain/routing, delivery, and recovery validation. Analysis completion, policy disposition, and confirmed recipient delivery are separate events.
The integrated source uses private AWS classifier hosting with production workload identity. The documented pilot schedule is 07:00–19:00 IST, with startup readiness checked separately. Web deployment checks do not run model inference or prove final recipient delivery; verify those runtime outcomes before treating hosting or schedule labels as live guarantees.
Node.js example with explicit result handling
This example uses built-in Node.js APIs, performs one text investigation, preserves its response, and submits the complete evidence/Passport pair for verification. Use a fresh identifier for new input and the persisted identifier for retries. It intentionally stops on pending, failed, missing-package, or oversized-verification outcomes.
// Save as investigate.mjs and run with Node.js 24.
// Provide VERITRUST_API_KEY through your private server environment.
import { randomUUID } from 'node:crypto';
import { writeFile } from 'node:fs/promises';
const base = 'https://www.veritrustlab.in';
const apiKey = process.env.VERITRUST_API_KEY;
if (!apiKey) throw new Error('VERITRUST_API_KEY is required.');
// Persist this ID before sending; reuse it for a retry of this input.
const requestId = process.env.VERITRUST_REQUEST_ID || randomUUID();
console.log('Retry identity:', requestId);
const response = await fetch(base + '/api/v2/phishing/analyze-text', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + apiKey,
'Content-Type': 'application/json',
'Idempotency-Key': requestId,
Accept: 'application/json'
},
body: JSON.stringify({
subject: 'Payment request for review',
body: 'Please confirm this invoice through our usual contact.',
channel: 'email',
retention_policy: 'metadata_only'
}),
signal: AbortSignal.timeout(190000)
});
const result = await response.json();
if (response.status === 202) {
throw new Error('Not finalized. Retain the retry identity and review scan status.');
}
if (!response.ok || result.ok !== true) {
throw new Error(result.error?.message || 'Investigation request failed.');
}
// Preserve the returned package before making any display/redaction changes.
await writeFile('investigation.json', JSON.stringify(result, null, 2));
const evidence = result.evidence;
const passport = evidence?.evidence_passport;
if (!evidence || !passport) {
throw new Error('No complete signed package is available; do not reconstruct one.');
}
const body = JSON.stringify({ passport, evidence });
if (Buffer.byteLength(body, 'utf8') > 1024 * 1024) {
throw new Error('The complete verification request exceeds 1 MiB.');
}
// The public verification route does not require the investigation API key.
const checked = await fetch(base + '/api/v2/phishing/verify-evidence', {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body,
signal: AbortSignal.timeout(30000)
});
const checkedBody = await checked.json();
if (![200, 422].includes(checked.status) || !checkedBody.verification) {
throw new Error('Verification did not return a usable result.');
}
console.log(checkedBody.verification);
if (!checkedBody.verification.valid) {
throw new Error('Signed package verification failed.');
}There is no official VeriTrustLab SDK in this repository. Do not share a notebook or sample containing a live key. Code examples demonstrate contracts; they do not certify inference availability, a production SLA, or valid results for arbitrary input.
Security, retention, and further references
- Keep keys, receiver credentials, and webhook/worker signing material server-side. Use narrow scopes and rotate/revoke access when required.
- Preserve complete signed records before formatting or redaction. Exported entities and hashes can still contain sensitive identifiers.
- Retention and erasure are hold-aware governance workflows; a deadline or an erasure request is not proof that every copy was deleted.
- Treat classifiers, authentication, infrastructure location, and campaign overlap as bounded evidence for human review.
Read Documentation, Security, Privacy, and Limitations. The email-v2 and Gateway OpenAPI files describe versioned schemas; reconcile them with deployed handlers because newer specifications can precede runtime availability.

