API Reference
Integrate HookRoast's reputation engine into your own apps, and try every endpoint live.
The HookRoast API is REST over HTTPS. All requests and responses are JSON. The base URL is:
https://api.hookroast.com/api/v1Create an API key on the Developers page (sign-in required). Every call draws from your monthly credit wallet.
Live console
Paste an API key to run the Try it panels against the real API. Calls spend credits. Your key is stored only in this browser. Don't use a production key on a shared machine.
No key set. Try it panels will prompt you.
Authentication
Pass your API key in the x-api-key header, or as a bearer token. Keys look like hr_live_… and are shown only once at creation.
curl https://api.hookroast.com/api/v1/reputation \
-X POST \
-H "x-api-key: hr_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"domain":"acme.io"}'Or Authorization: Bearer hr_live_your_key_here. A missing or revoked key returns 401.
Rate limits
Requests are rate limited per API key (default 60 requests / 60s). Every response includes:
x-ratelimit-limit: 60
x-ratelimit-remaining: 59
x-ratelimit-reset: 1782684309Exceeding the limit returns 429 TOO_MANY_REQUESTS with a retry-after header (seconds).
Credits
Each call spends credits from your monthly wallet: a reputation scan costs 5 credits, a bulk scan 5 × number of targets, and email validation 1 credit per email. When the wallet is exhausted the API returns 403 FORBIDDEN. Paid plans can buy top-up credits from the Billing page.
Errors
Errors use standard HTTP status codes and a consistent JSON body:
{ "error": "FORBIDDEN", "message": "…human readable…" }400 / 422 VALIDATION_ERROR: bad request body401 UNAUTHORIZED: missing/invalid API key403 FORBIDDEN: out of credits404 NOT_FOUND: unknown id429 TOO_MANY_REQUESTS: rate limited
Reputation scan
Start a scan for a single email address or domain. Scans run asynchronously: create one, then poll the GET endpoint until status is COMPLETED.
POST/api/v1/reputation
Create a scan. The body must contain exactly one of the fields below. Returns the scan id to poll.
Body parameters
emailstringoptionalEmail address to scan. Provide this or `domain` (exactly one).
domainstringoptionalBare domain to scan, e.g. acme.io. Provide this or `email` (exactly one).
Response fields
idstringUnique scan id. Use it to poll the GET endpoint.
statusstringPENDING · PROCESSING · COMPLETED · FAILED.
emailstring | nullThe email scanned, or null for a domain scan.
domainstringThe domain scanned.
{ "id": "b5f7c8ac-…", "status": "PENDING", "email": null, "domain": "acme.io" }curl https://api.hookroast.com/api/v1/reputation \
-X POST \
-H "x-api-key: hr_live_…" \
-H "Content-Type: application/json" \
-d '{"domain":"acme.io"}'https://api.hookroast.com/api/v1/reputationShow as cURL
curl https://api.hookroast.com/api/v1/reputation \
-X POST \
-H "x-api-key: hr_live_your_key"
\
-H "Content-Type: application/json" \
-d '{
"domain": "acme.io"
}'GET/api/v1/reputation/:id
Fetch a scan. Poll until status is COMPLETED. The report includes the overall score, per-category scores, verified analyzer data, and AI analysis.
Path parameters
idstringrequiredThe scan id returned by POST /reputation.
Response fields
idstringThe scan id.
statusstringPoll until COMPLETED (or FAILED).
overallScoreinteger | nullOverall reputation 0-100; null until completed.
gradestring | nullExcellent · Good · Fair · Poor.
reportobject | nullFull report; null until completed.
report.confidenceinteger0-100; share of analyzers that succeeded.
report.categoryScoresarray[{ category, score }] for each scored category.
report.analysisobjectVerified per-analyzer data, keyed by analyzer.
report.aiobjectAI insights: trustScore, riskLevel, replyProbability, summary, recommendations[].
{
"id": "b5f7c8ac-…",
"status": "COMPLETED",
"overallScore": 84,
"grade": "Good",
"report": {
"confidence": 100,
"categoryScores": [ { "category": "Deliverability", "score": 88 } ],
"ai": {
"trustScore": 84, "riskLevel": "Low", "replyProbability": 70, "summary": "…",
"recommendations": [ { "problem": "…", "impact": "Medium", "recommendation": "…", "expectedImprovement": "+5 points" } ]
}
}
}curl https://api.hookroast.com/api/v1/reputation/SCAN_ID \
-X GET \
-H "x-api-key: hr_live_…"https://api.hookroast.com/api/v1/reputation/:idShow as cURL
curl https://api.hookroast.com/api/v1/reputation/:id \
-X GET \
-H "x-api-key: hr_live_your_key"Bulk reputation
Score many emails/domains in one job (up to 1,000 targets). Targets can mix emails and bare domains.
POST/api/v1/bulk-reputation
Submit a batch of targets. Returns a job id to poll.
Body parameters
targetsstring[]requiredArray of emails and/or bare domains to score. 1-1,000 entries.
Response fields
idstringJob id. Use it to poll the GET endpoint.
statusstringPENDING · PROCESSING · COMPLETED · FAILED.
totalCountintegerNumber of targets queued.
{ "id": "4102e918-…", "status": "PENDING", "totalCount": 2 }curl https://api.hookroast.com/api/v1/bulk-reputation \
-X POST \
-H "x-api-key: hr_live_…" \
-H "Content-Type: application/json" \
-d '{"targets":["stripe.com","example.org"]}'https://api.hookroast.com/api/v1/bulk-reputationShow as cURL
curl https://api.hookroast.com/api/v1/bulk-reputation \
-X POST \
-H "x-api-key: hr_live_your_key"
\
-H "Content-Type: application/json" \
-d '{
"targets": ["stripe.com", "example.org"]
}'GET/api/v1/bulk-reputation/:id
Fetch the job with per-target results once processing completes.
Path parameters
idstringrequiredThe job id returned by POST /bulk-reputation.
Response fields
idstringThe job id.
statusstringPoll until COMPLETED (or FAILED).
totalCountintegerTotal targets in the job.
completedCountintegerTargets scored so far.
itemsarrayPer-target results (see fields below).
items[].targetstringThe email or domain scored.
items[].statusstringCOMPLETED or FAILED for that target.
items[].overallScoreinteger | nullOverall reputation 0-100.
items[].gradestring | nullExcellent · Good · Fair · Poor.
items[].riskLevelstring | nullLow · Medium · High · Critical.
items[].reportobject | nullFull report for that target.
{
"id": "4102e918-…", "status": "COMPLETED", "totalCount": 2, "completedCount": 2,
"items": [ { "target": "stripe.com", "status": "COMPLETED", "overallScore": 86, "grade": "Good", "riskLevel": "Low" } ]
}curl https://api.hookroast.com/api/v1/bulk-reputation/JOB_ID \
-X GET \
-H "x-api-key: hr_live_…"https://api.hookroast.com/api/v1/bulk-reputation/:idShow as cURL
curl https://api.hookroast.com/api/v1/bulk-reputation/:id \
-X GET \
-H "x-api-key: hr_live_your_key"Real-time verify
Verify a single email address synchronously: one request, one VALID/INVALID answer. Built for signup forms and lead capture, so you can block disposable and undeliverable addresses before they enter your product. Costs 1 credit per call.
POST/api/v1/verify
Also available as GET /api/v1/verify?email=jane@acme.io for easy wiring into form validators. Responses typically return in 1-3 seconds (the SMTP probe dominates); set a client timeout of at least 10 seconds.
Body parameters
emailstringrequiredThe email address to verify.
Response fields
emailstringThe normalized email address.
statusstringVALID or INVALID.
reasonstring | nullinvalid_format · disposable_domain · domain_not_found · mailbox_not_found (null when valid).
{ "email": "jane@acme.io", "status": "VALID", "reason": null }curl https://api.hookroast.com/api/v1/verify \
-X POST \
-H "x-api-key: hr_live_…" \
-H "Content-Type: application/json" \
-d '{"email":"jane@acme.io"}'https://api.hookroast.com/api/v1/verifyShow as cURL
curl https://api.hookroast.com/api/v1/verify \
-X POST \
-H "x-api-key: hr_live_your_key"
\
-H "Content-Type: application/json" \
-d '{
"email": "jane@acme.io"
}'Email validation
Validate a list of email addresses for format, domain deliverability (MX), disposable providers, and, where reachable, mailbox existence over SMTP. Runs asynchronously; poll the GET endpoint for results. Costs 1 credit per email.
POST/api/v1/email-validation
Submit a batch of emails. Returns a job id to poll.
Body parameters
emailsstring[]requiredEmail addresses to validate. 1-5,000 entries.
Response fields
idstringJob id. Use it to poll the GET endpoint.
statusstringPENDING · PROCESSING · COMPLETED · FAILED.
totalCountintegerNumber of emails submitted.
{ "id": "9c1e…", "status": "PENDING", "totalCount": 2 }curl https://api.hookroast.com/api/v1/email-validation \
-X POST \
-H "x-api-key: hr_live_…" \
-H "Content-Type: application/json" \
-d '{"emails":["jane@acme.io","ghost@acme.io"]}'https://api.hookroast.com/api/v1/email-validationShow as cURL
curl https://api.hookroast.com/api/v1/email-validation \
-X POST \
-H "x-api-key: hr_live_your_key"
\
-H "Content-Type: application/json" \
-d '{
"emails": ["jane@acme.io", "ghost@acme.io"]
}'GET/api/v1/email-validation/:id
Fetch the job with per-email results once validation completes.
Path parameters
idstringrequiredThe job id returned by POST /email-validation.
Response fields
idstringThe job id.
statusstringPoll until COMPLETED (or FAILED).
totalCountintegerTotal emails in the job.
validCountintegerEmails found valid.
invalidCountintegerEmails found invalid.
resultsarrayPer-email outcomes (see fields below).
results[].emailstringThe normalized email address.
results[].statusstringVALID or INVALID.
results[].reasonstring | nullinvalid_format · disposable_domain · domain_not_found · mailbox_not_found (null when valid).
{
"id": "9c1e…", "status": "COMPLETED", "totalCount": 2, "validCount": 1, "invalidCount": 1,
"results": [
{ "email": "jane@acme.io", "status": "VALID", "reason": null },
{ "email": "ghost@acme.io", "status": "INVALID", "reason": "mailbox_not_found" }
]
}curl https://api.hookroast.com/api/v1/email-validation/JOB_ID \
-X GET \
-H "x-api-key: hr_live_…"https://api.hookroast.com/api/v1/email-validation/:idShow as cURL
curl https://api.hookroast.com/api/v1/email-validation/:id \
-X GET \
-H "x-api-key: hr_live_your_key"Webhooks
Register webhook URLs on the Developers page to be notified when scans finish, instead of polling. Events: reputation.completed, bulk_reputation.completed. We POST:
{
"event": "reputation.completed",
"data": { "scanId": "b5f7c8ac-…" },
"timestamp": "2026-06-29T12:00:00.000Z"
}Each delivery is signed: x-hookroast-signature is the hex HMAC-SHA256 of the raw request body using the signing secret shown when you created the webhook. Verify it before trusting the payload:
import { createHmac, timingSafeEqual } from "crypto";
function verify(rawBody, signature, secret) {
const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
return expected.length === signature.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}