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 INSUFFICIENT_CREDITS: the wallet can't cover the call;detailshasrequired,remainingandcanTopUp403 PLAN_UPGRADE_REQUIRED: the feature needs a higher plan;details.requiredTiernames it403 FORBIDDEN: not allowed for this key or role404 NOT_FOUND: unknown id429 TOO_MANY_REQUESTS: rate limited
Email roast
Score a cold email for spam risk and copy strength and get a rewrite. Optionally include the subject line and up to three follow-ups. Costs 3 credits, plus 2 per follow-up. Browser-extension keys can call this endpoint on any plan.
POST/api/v1/analysis
Runs synchronously and usually returns in 5 to 15 seconds.
Body parameters
rawTextstringrequiredThe email body, 20 to 8,000 characters. Merge tags are kept as-is.
targetPersonastringrequiredWho the email is for.
subjectLinestringoptionalOptional subject line to score.
followUpsstring[]optionalUp to 3 follow-up emails, in order.
Response fields
spamScoreinteger1 to 100, higher is safer.
riskLevelstringLow · Medium · High.
flaggedPhrasesstring[]Exact phrases that hurt deliverability.
critiquestringWhat's working and what isn't.
optimizedRewritestringA rewritten version.
details.subScoresobjecthook, personalization, valueProp, cta, brevity, tone (0 to 100).
details.followUpsarrayPer-step score, critique and rewrite.
{
"id": "4f1a…", "spamScore": 82, "riskLevel": "Low", "flaggedPhrases": [],
"critique": "Specific hook, but the ask is vague.",
"optimizedRewrite": "Hi {{firstName|there}}, …",
"details": { "subScores": { "hook": 78, "personalization": 64, "valueProp": 55, "cta": 48, "brevity": 90, "tone": 81 } }
}curl https://api.hookroast.com/api/v1/analysis \
-X POST \
-H "x-api-key: hr_live_…" \
-H "Content-Type: application/json" \
-d '{"rawText":"Hi {{firstName|there}}, saw Acme is hiring SDRs. Worth a quick chat?","targetPersona":"Heads of sales at Series A SaaS","subjectLine":"Quick question"}'https://api.hookroast.com/api/v1/analysisShow as cURL
curl https://api.hookroast.com/api/v1/analysis \
-X POST \
-H "x-api-key: hr_live_your_key"
\
-H "Content-Type: application/json" \
-d '{
"rawText": "Hi Sam, saw Acme is hiring SDRs. Worth a quick chat next week?",
"targetPersona": "Heads of sales at Series A SaaS"
}'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 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 · INVALID · RISKY (deliverable but may bounce: catch-all domain or role mailbox) · UNKNOWN (the mail server would not confirm).
reasonstring | nullinvalid_format · disposable_domain · domain_not_found · mailbox_not_found · catch_all · role_account · unverifiable (null when valid). Catch-all and role detection need Growth or above.
{ "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 that will bounce.
riskyCountintegerDeliverable but risky (catch-all or role mailbox).
unknownCountintegerMail server wouldn't confirm the mailbox.
resultsarrayPer-email outcomes (see fields below).
results[].emailstringThe normalized email address.
results[].statusstringVALID · INVALID · RISKY (deliverable but may bounce: catch-all domain or role mailbox) · UNKNOWN (the mail server would not confirm).
results[].reasonstring | nullinvalid_format · disposable_domain · domain_not_found · mailbox_not_found · catch_all · role_account · unverifiable (null when valid). Catch-all and role detection need Growth or above.
results[].flagsstring[]Extra attributes such as free_provider. Omitted when empty.
{
"id": "9c1e…", "status": "COMPLETED", "totalCount": 2, "validCount": 1, "invalidCount": 1, "riskyCount": 0, "unknownCount": 0,
"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 instead of polling (Pro and above). Events: reputation.completed, bulk_reputation.completed, email_validation.completed, monitor.alert, test_email.completed, dmarc.report_received, widget.lead. 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. Requests also carry x-hookroast-event and a unique x-hookroast-delivery id you can use to ignore duplicates. Any non-2xx response (or no response within 5 seconds) is retried after 1, 5, 30, 120 and 360 minutes.
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));
}