Developers
Email testing and validation API reference
Use WillItInbox API keys to capture development email, validate recipients, create test addresses, fetch reports, verify asynchronous workflows, monitor sender health, and build repeatable email QA.
What the API is for
The API is designed for product signup checks, CRM and CSV hygiene, release gates for important email templates, domain monitoring, DMARC evidence, provider reputation reviews, and webhook-driven operational workflows. Start with validation for recipient quality, generate test addresses when you need message-level evidence, then add webhooks and monitoring once the workflow is recurring.
Authentication
Create an API key from your account page. Send it as a bearer token. Raw keys are shown once; later you will only see prefix and last characters.
Authorization: Bearer wii_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxRate limits and quotas
Monthly plan quotas are shared across the web app and API for deliverability tests, email validations, and bulk CSV rows. API calls are consumed only by API-key traffic. Per-minute API limits protect throughput separately from monthly quota.
| Limit | Scope | Applies to |
|---|---|---|
| Free 30, Starter 120, Pro 600, Agency 2000 requests/min | API key | Every authenticated /api/v1 request. |
| 120 email verification rows/min | User or workspace | /api/v1/validate, /api/v1/validate/batch, and /api/v1/validate/bulk. |
| Monthly tests, validations, and bulk rows | User or workspace | Shared web app and API usage. |
| Monthly API calls | User or workspace | API-key requests only. |
Validation throughput is counted by rows, not by requests: a batch of 50 emails consumes 50 verification-row units, and a bulk CSV with 120 rows consumes the full minute window. Rate-limit responses use HTTP 429 with rate_limit_exceeded, Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset.
HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 30
{
"detail": {
"code": "rate_limit_exceeded",
"message": "Too many API email verifications. Try again in 30 seconds."
}
}How to design a production integration
Treat WillItInbox API responses as evidence for a business decision, not as throwaway diagnostics. Store validation evidence, report tokens, bulk job ids, webhook delivery ids, and the policy decision your system made from each result.
| Workflow | Endpoint family | Production policy |
|---|---|---|
| Signup and lead capture | /api/v1/validate | Accept high-confidence valid results, block confirmed invalid, segment risky, and retry unknown. |
| CSV imports and list hygiene | /api/v1/validate/bulk | Keep original row ids, append evidence columns, and apply a reviewed suppression policy. |
| Template QA | /api/v1/tests and /api/v1/reports/{token} | Fail release gates on deterministic critical issues; warn on policy or reputation signals. |
| Monitoring and alerts | /api/v1/domains, /api/v1/dmarc, /api/v1/postmaster-integrations, webhooks | Route drift, unknown senders, and failed alignment to the team that owns the sender. |
| Workspace operations | /api/v1/workspaces, /api/v1/workspace-invitations, /api/v1/audit-events | Keep client/project scope, teammate access, audit history, and branded report settings aligned. |
Browser auth and invite acceptance
Workspace invite links are accepted through the browser session flow, not API keys. The invite page accepts immediately for the invited signed-in user, explains wrong-account sessions, and lets logged-out invitees sign in or create the invited account without dropping the token.
POST /api/auth/workspace-invitations/accept
POST /api/auth/workspace-invitations/login
POST /api/auth/workspace-invitations/signupError handling and retries
Retry network and 5xx failures with backoff. Do not blindly retry provider policy blocks, quota errors, or validation results that are already conclusive. For bulk jobs, persist the job id and resume by polling status rather than uploading the same file repeatedly.
// Webhook verification sketch
const expected = hmacSha256(webhookSecret, rawBody);
if (signature !== "sha256=" + expected) {
return new Response("invalid signature", { status: 401 });
}
// Idempotency sketch
if (alreadyProcessed(event.id)) {
return new Response("ok", { status: 200 });
}
processEvent(event);/api/v1/validateValidate one email address. Fast mode costs 1 validation credit; Full mode costs 3. API-only Verify+ costs 5 credits and requires verify_plus_consent=true. API requests can pass spend_source=allowance_first, wallet_first, allowance_only, or wallet_only.
curl -X POST "$WILLITINBOX_API_URL/api/v1/validate?mode=full&spend_source=allowance_first" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"person [at] example.com","verification_depth":"deep"}'{
"result_id": "val_...",
"email": "person [at] example.com",
"status": "valid",
"sub_status": "mailbox_exists",
"confidence": 0.95,
"confidence_model_version": "validator-confidence-v1",
"verification_depth": "deep",
"verification_pending": false,
"provider": "google",
"deliverability_answer": "safe_to_send",
"recommended_action": "send",
"user_message": "The recipient server accepted this mailbox during verification.",
"next_step": {
"type": "none",
"status": "not_needed",
"reason": "mailbox_confirmed",
"next_recheck_at": null,
"expected_final_at": null
},
"risk_signals": [],
"suppression": null
}/api/v1/validate/results/{result_id}Fetch the latest DB-backed validation result for the API key owner. Foreign-user result ids return 404. Use this to refresh pending verification rows without uploading again.
curl "$WILLITINBOX_API_URL/api/v1/validate/results/$RESULT_ID" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/validate/batchValidate up to 100 email addresses in one JSON request. Monthly allowance and wallet credits are separate from API request rate limits.
curl -X POST "$WILLITINBOX_API_URL/api/v1/validate/batch" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"emails":["good [at] example.com","missing [at] example.com"],"verification_depth":"standard"}'{
"results": [...],
"summary": {
"total": 2,
"valid": 1,
"invalid": 1,
"risky": 0,
"catch_all": 0,
"unknown": 0
}
}/api/v1/validate/bulkUpload a CSV with an email column. Fast mode costs 1 credit per row; Full mode costs 3 credits per row; API-only Verify+ costs 5 credits per row and requires verify_plus_consent=true. Optional webhook_url receives a signed completion callback. Catch-all and unknown rows may continue as pending verification after the initial job completes.
curl -X POST "$WILLITINBOX_API_URL/api/v1/validate/bulk?mode=full&verification_depth=deep&spend_source=wallet_first&webhook_url=https://example.com/webhooks/willitinbox" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-F "[email protected]"/api/v1/credit-walletReturn wallet balance, recent credit transactions, and burn rules. Credits are for validation and deliverability testing only.
curl "$WILLITINBOX_API_URL/api/v1/credit-wallet" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/credit-packs/quoteQuote a PAYG credit pack before checkout. Valid values follow the pricing slider: 1k steps to 10k, 10k steps to 100k, then 100k steps to 1M.
{
"quote": {
"credits": 10000,
"amount_cents": 6000,
"price": 60,
"effective_price_per_1000": 6,
"estimates": {
"validation_fast": 10000,
"validation_full": 3333,
"deliverability_tests": 400
}
}
}/api/v1/credit-checkoutCreate a one-time Dodo checkout session for PAYG validation and testing credits. Credits do not unlock platform features or raise API rate limits.
curl -X POST "$WILLITINBOX_API_URL/api/v1/credit-checkout" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"credits":10000}'/api/v1/bulk/{job_id}Poll a bulk validation job. The job is only visible to the API key owner.
{
"job_id": "abc123",
"status": "complete",
"total": 1000,
"processed": 1000,
"valid": 812,
"invalid": 64,
"risky": 52,
"catch_all": 41,
"unknown": 31,
"resolution_status": "initial_complete_pending_followups",
"pending_verifications": 72,
"action_summary": {
"safe_to_send": 812,
"do_not_send": 64,
"pending_verification": 72,
"use_caution": 52
},
"next_pending_recheck_at": "2026-06-01T11:57:33Z",
"suppressed": 4,
"duplicate_rows": 12,
"risk_signal_rows": 88,
"hygiene_summary": {
"blank_rows": 2,
"duplicate_addresses": 7
},
"download_url": "/api/v1/bulk/abc123/download"
}/api/v1/bulk/{job_id}/downloadDownload the latest enriched CSV results for a completed initial bulk job. Rows with result_id are refreshed from the latest DB-backed validation result and include guidance columns.
curl -L "$WILLITINBOX_API_URL/api/v1/bulk/$JOB_ID/download" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-o validation-results.csv/api/v1/bounce-events/ingestUpload a raw DSN bounce email. Hard bounces create user-owned suppression evidence.
curl -X POST "$WILLITINBOX_API_URL/api/v1/bounce-events/ingest" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-F "[email protected]"/api/v1/feedback-complaints/ingestUpload a raw ARF complaint report. Complaints create do-not-mail suppression evidence.
curl -X POST "$WILLITINBOX_API_URL/api/v1/feedback-complaints/ingest" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-F "[email protected]"/api/v1/suppression-entriesList user-owned suppressions created manually or from bounce and complaint evidence.
curl "$WILLITINBOX_API_URL/api/v1/suppression-entries?active=true" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/suppression-entriesCreate or reactivate a manual suppression entry for an address.
curl -X POST "$WILLITINBOX_API_URL/api/v1/suppression-entries" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"person [at] example.com","reason":"manual"}'/api/v1/testsGenerate an owned deliverability test address. Counts as one deliverability test.
{
"token": "a1b2c3d4",
"email_address": "test-a1b2c3d4 [at] mail.example.com",
"instructions": "Send your test email to test-a1b2c3d4 [at] mail.example.com..."
}/api/v1/reports/{token}Fetch a report generated by the same API key owner. Pending reports return status only.
curl "$WILLITINBOX_API_URL/api/v1/reports/a1b2c3d4" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/reports/{token}/shareCreate a private share token for a completed or pending owned report. Use DELETE on the same path to revoke.
curl -X POST "$WILLITINBOX_API_URL/api/v1/reports/a1b2c3d4/share" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/reports/{token}/pdfDownload a completed report as PDF. Pending reports return report_not_ready.
curl -L "$WILLITINBOX_API_URL/api/v1/reports/a1b2c3d4/pdf" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-o willitinbox-report.pdf/api/v1/usageReturn the API key owner's current plan, usage counters, limits, and recent usage events.
curl "$WILLITINBOX_API_URL/api/v1/usage" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/usage/seriesReturn daily API usage, validation, test, and bulk-row series for dashboards.
{
"series": [
{ "date": "2026-05-01", "api_calls": 12, "validations": 500, "tests": 2, "bulk_rows": 450 }
]
}/api/healthReturn backend dependency health plus scheduler freshness for domain scans, placement schedules, and DMARC mailbox ingestion.
{
"status": "ok",
"database": true,
"redis": true,
"spamassassin": true,
"scheduler": {
"ok": true,
"jobs": {
"scan_due_domains": {
"stale": false,
"stale_after_seconds": 4500
}
}
}
}/api/v1/webhooksCreate a persistent signed webhook endpoint for bulk completion and future event types.
curl -X POST "$WILLITINBOX_API_URL/api/v1/webhooks" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Production","url":"https://example.com/webhooks/willitinbox","events":["bulk.completed","validation.updated"]}'/api/v1/webhook-deliveriesList recent webhook delivery attempts, response codes, failures, and delivered timestamps.
curl "$WILLITINBOX_API_URL/api/v1/webhook-deliveries" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/webhooks/{webhook_id}/testSend a signed test payload to a persistent webhook endpoint.
curl -X POST "$WILLITINBOX_API_URL/api/v1/webhooks/$WEBHOOK_ID/test" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/webhook-deliveries/{delivery_id}/resendCreate a new delivery attempt from a previous persistent webhook delivery.
curl -X POST "$WILLITINBOX_API_URL/api/v1/webhook-deliveries/$DELIVERY_ID/resend" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/domainsCreate a monitored domain and receive the TXT record required for ownership verification.
curl -X POST "$WILLITINBOX_API_URL/api/v1/domains" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain":"example.com","schedule":"daily"}'/api/v1/domains/{domain_id}/scanRun a manual domain scan after the TXT verification token has been published.
curl -X POST "$WILLITINBOX_API_URL/api/v1/domains/$DOMAIN_ID/scan" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/domains/{domain_id}/historyReturn monitored-domain history for MTA-STS, TLS-RPT, STARTTLS, DKIM selector drift, DNSSEC/DANE, DNSBL state, and delisting guidance.
curl "$WILLITINBOX_API_URL/api/v1/domains/$DOMAIN_ID/history" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/postmaster/google/oauth/startStart Google Postmaster OAuth for read-only provider reputation evidence. The response contains an authorization_url for the signed-in account.
curl -X POST "$WILLITINBOX_API_URL/api/v1/postmaster/google/oauth/start" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"redirect_path":"/domains"}'/api/v1/postmaster/google/oauth/callbackBrowser callback used by Google OAuth. It exchanges the code, stores the integration, runs an initial sync, and redirects back to the frontend.
GET /api/v1/postmaster/google/oauth/callback?code=...&state=.../api/v1/postmaster-integrationsList connected Google Postmaster integrations, status, scopes, last sync time, and last error.
curl "$WILLITINBOX_API_URL/api/v1/postmaster-integrations" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/postmaster-integrations/{integration_id}/syncRun a manual sync for one connected Postmaster integration. Sync uses Google's stable v2 API and treats empty stats as a no-data state.
curl -X POST "$WILLITINBOX_API_URL/api/v1/postmaster-integrations/$INTEGRATION_ID/sync" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/postmaster-integrations/{integration_id}Disconnect a Google Postmaster integration and remove its linked provider-domain state for this user.
curl -X DELETE "$WILLITINBOX_API_URL/api/v1/postmaster-integrations/$INTEGRATION_ID" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/postmaster-integrations/{integration_id}/domainsList Google Postmaster provider domains discovered for an integration and their links to monitored WillItInbox domains.
curl "$WILLITINBOX_API_URL/api/v1/postmaster-integrations/$INTEGRATION_ID/domains" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/postmaster-domain-links/{link_id}Link or unlink a Google Postmaster provider domain to a verified monitored domain in WillItInbox.
curl -X PATCH "$WILLITINBOX_API_URL/api/v1/postmaster-domain-links/$LINK_ID" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain_id":"monitored-domain-id"}'/api/v1/domains/{domain_id}/provider-reputationReturn the latest provider reputation summary and snapshots for a monitored domain.
curl "$WILLITINBOX_API_URL/api/v1/domains/$DOMAIN_ID/provider-reputation" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/provider-reputation-snapshotsList provider reputation snapshots across the user's linked domains, including date, reputation signals, compliance, and source API versions.
curl "$WILLITINBOX_API_URL/api/v1/provider-reputation-snapshots?domain_id=$DOMAIN_ID" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/dmarc/uploadUpload a DMARC aggregate XML, gzip, zip, or EML report for parsed source and alignment analytics.
curl -X POST "$WILLITINBOX_API_URL/api/v1/dmarc/upload" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-F "[email protected]"/api/v1/dmarc/forensic-reportsList parsed DMARC forensic/RUF authentication-failure reports ingested through upload or mailbox ingestion.
curl "$WILLITINBOX_API_URL/api/v1/dmarc/forensic-reports" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/dmarc/tlsrpt-reportsList SMTP TLS-RPT JSON reports with successful and failed session summaries.
curl "$WILLITINBOX_API_URL/api/v1/dmarc/tlsrpt-reports" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/dmarc/summaryReturn aggregate DMARC volume, alignment, disposition, unknown-source, and recent-report metrics.
curl "$WILLITINBOX_API_URL/api/v1/dmarc/summary" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/dmarc/sourcesList sending sources ordered by failed DMARC volume, then total volume.
curl "$WILLITINBOX_API_URL/api/v1/dmarc/sources" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/dmarc/sources/{source_ip}Label a known sending source so future dashboards separate approved senders from unknown traffic.
curl -X PATCH "$WILLITINBOX_API_URL/api/v1/dmarc/sources/192.0.2.10" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"source_name":"Google Workspace","owner_name":"Ops","service_type":"workspace","unresolved":false}'/api/v1/dmarc/mailboxesBeta: store encrypted IMAP settings for mailbox-based DMARC report ingestion.
curl -X POST "$WILLITINBOX_API_URL/api/v1/dmarc/mailboxes" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email_address":"dmarc [at] example.com","imap_host":"imap.example.com","imap_username":"dmarc [at] example.com","imap_password":"app-password"}'/api/v1/dmarc/mailboxes/{mailbox_id}/ingestBeta: poll a configured DMARC mailbox and route aggregate RUA, forensic RUF, and TLS-RPT attachments into separate tables.
curl -X POST "$WILLITINBOX_API_URL/api/v1/dmarc/mailboxes/$MAILBOX_ID/ingest" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/dmarc/mailboxes/{mailbox_id}/scheduleBeta: set recurring DMARC mailbox ingestion to manual, hourly, daily, or weekly.
curl -X PATCH "$WILLITINBOX_API_URL/api/v1/dmarc/mailboxes/$MAILBOX_ID/schedule" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"schedule":"daily","active":true}'/api/v1/dmarc/timeseriesReturn daily DMARC total, aligned, failed, SPF-aligned, DKIM-aligned, and disposition counts.
curl "$WILLITINBOX_API_URL/api/v1/dmarc/timeseries" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/dmarc/rollout-plannerReturn DMARC enforcement readiness, source-labeling gaps, alignment gaps, and the recommended policy step.
curl "$WILLITINBOX_API_URL/api/v1/dmarc/rollout-planner" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/dmarc/source-ownershipSummarize known versus unknown DMARC senders with ownership scores and failed/aligned volume.
curl "$WILLITINBOX_API_URL/api/v1/dmarc/source-ownership" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/dmarc/reports/{report_id}/rowsInspect normalized report rows. Optional filters include source_ip, disposition, aligned, failed, and limit.
curl "$WILLITINBOX_API_URL/api/v1/dmarc/reports/$REPORT_ID/rows?failed=true" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/dmarc/alertsList open DMARC alerts created from monitored-domain aggregate report ingestion.
curl "$WILLITINBOX_API_URL/api/v1/dmarc/alerts" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/dmarc/alerts/{alert_id}Acknowledge or resolve a DMARC alert.
curl -X PATCH "$WILLITINBOX_API_URL/api/v1/dmarc/alerts/$ALERT_ID" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"resolved"}'/api/v1/notification-channelsBeta: create a webhook, Slack, Discord, or email destination record for alert routing.
curl -X POST "$WILLITINBOX_API_URL/api/v1/notification-channels" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"DMARC alerts","channel_type":"slack","target":"https://hooks.slack.com/services/..."}'/api/v1/placement-testsCreate a diagnostic inbox placement test from configured seed inboxes. Optional send_identity_id sends one user-authorized diagnostic message to seeds only.
curl -X POST "$WILLITINBOX_API_URL/api/v1/placement-tests" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"May newsletter"}'/api/v1/placement-schedulesCreate a recurring placement schedule using manual, daily, weekly, or monthly recurrence.
curl -X POST "$WILLITINBOX_API_URL/api/v1/placement-schedules" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Weekly placement check","recurrence":"weekly","providers":["gmail"]}'/api/v1/placement-schedules/{schedule_id}/runManually create a linked placement test from an existing schedule.
curl -X POST "$WILLITINBOX_API_URL/api/v1/placement-schedules/$SCHEDULE_ID/run" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/placement-send-identitiesStore encrypted user-owned SMTP credentials for authorized diagnostic sends to seed inboxes.
curl -X POST "$WILLITINBOX_API_URL/api/v1/placement-send-identities" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Production SMTP","from_email":"sender [at] example.com","smtp_host":"smtp.example.com","smtp_username":"sender [at] example.com","smtp_password":"app-password"}'/api/v1/seed-inboxesAdd an encrypted IMAP seed inbox for diagnostic inbox placement tests.
curl -X POST "$WILLITINBOX_API_URL/api/v1/seed-inboxes" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"provider":"gmail","email_address":"seed [at] example.com","imap_host":"imap.gmail.com","imap_username":"seed [at] example.com","imap_password":"app-password"}'/api/v1/seed-providersReturn provider-level seed counts and credential readiness for placement testing.
curl "$WILLITINBOX_API_URL/api/v1/seed-providers" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/placement-heatmapsSummarize recent placement outcomes by provider and folder.
curl "$WILLITINBOX_API_URL/api/v1/placement-heatmaps" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/placement-tests/{test_id}/pollPoll configured seed inboxes over IMAP and classify inbox, spam, promotions/updates, missing, or delayed.
curl -X POST "$WILLITINBOX_API_URL/api/v1/placement-tests/$TEST_ID/poll" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/workspacesReturn active workspaces, project foundations, archive-aware capacity metadata, members, and account separation. Add include_archived=true when building restore UIs.
curl "$WILLITINBOX_API_URL/api/v1/workspaces" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/workspaces/{workspace_id}Rename a workspace visible to the current API key owner and record the change in workspace audit events.
curl -X PATCH "$WILLITINBOX_API_URL/api/v1/workspaces/$WORKSPACE_ID" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Client deliverability workspace"}'/api/v1/workspaces/{workspace_id}Archive a workspace without deleting historical reports, jobs, domains, placement evidence, or audit records.
curl -X DELETE "$WILLITINBOX_API_URL/api/v1/workspaces/$WORKSPACE_ID" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/workspaces/{workspace_id}/restoreRestore an archived workspace when the current plan still has workspace capacity.
curl -X POST "$WILLITINBOX_API_URL/api/v1/workspaces/$WORKSPACE_ID/restore" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/workspace-projectsCreate a project inside a workspace. Project limits are total per billing owner: Trial 0, Starter 5, Pro 25, Agency 100.
curl -X POST "$WILLITINBOX_API_URL/api/v1/workspace-projects" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"workspace_id":"wsp_123","name":"Client launch","client_name":"Acme","primary_domain":"example.com"}'/api/v1/workspace-projects/{project_id}Edit project name, client label, and primary domain while preserving scoped history.
curl -X PATCH "$WILLITINBOX_API_URL/api/v1/workspace-projects/$PROJECT_ID" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Client launch QA","client_name":"Acme","primary_domain":"example.com"}'/api/v1/workspace-projects/{project_id}Archive a project so selectors hide it while historical evidence remains linked.
curl -X DELETE "$WILLITINBOX_API_URL/api/v1/workspace-projects/$PROJECT_ID" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/workspace-projects/{project_id}/restoreRestore an archived project when the billing owner still has project capacity.
curl -X POST "$WILLITINBOX_API_URL/api/v1/workspace-projects/$PROJECT_ID/restore" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/workspace-membersList active workspace members and roles for the selected workspace.
curl "$WILLITINBOX_API_URL/api/v1/workspace-members?workspace_id=$WORKSPACE_ID" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/workspace-invitationsCreate a teammate invitation and send an accept-link email when transactional SMTP is configured.
curl -X POST "$WILLITINBOX_API_URL/api/v1/workspace-invitations" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"workspace_id":"wsp_123","email":"teammate [at] example.com","role":"member"}'/api/v1/audit-eventsList recent workspace/project audit events for administrative review.
curl "$WILLITINBOX_API_URL/api/v1/audit-events?workspace_id=$WORKSPACE_ID" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY"/api/v1/branded-report-settingsSave workspace or project branding used by report exports.
curl -X PUT "$WILLITINBOX_API_URL/api/v1/branded-report-settings" \
-H "Authorization: Bearer $WILLITINBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"workspace_id":"wsp_123","agency_name":"Acme Deliverability","accent_color":"#1f6feb"}'Additional public API endpoints
| Method | Path | Use |
|---|---|---|
| GET | /api/v1/api-keys/{api_key_id}/usage | Inspect usage attributed to one API key for owner dashboards and audits. |
| GET | /api/v1/alert-policies | List monitoring alert policies for domain, DMARC, TLS-RPT, and score signals. |
| POST | /api/v1/alert-policies | Create a policy that turns monitoring signals into routed alerts. |
| PATCH | /api/v1/alert-policies/{policy_id} | Update thresholds, scope, severity, or enabled state for an alert policy. |
| GET | /api/v1/alerts | List active and historical monitoring alerts across domains and DMARC workflows. |
| PATCH | /api/v1/alerts/{alert_id} | Acknowledge or resolve a monitoring alert. |
| GET | /api/v1/alerts/{alert_id}/events | Inspect signal events that contributed to a monitoring alert. |
| PATCH | /api/v1/notification-channels/{channel_id} | Update a Slack, Discord, webhook, or email notification destination. |
| POST | /api/v1/notification-channels/{channel_id}/test | Send a test notification to a configured alert channel. |
| PATCH | /api/v1/webhooks/{webhook_id} | Update a persistent webhook endpoint URL, name, enabled state, or event list. |
| DELETE | /api/v1/webhooks/{webhook_id} | Disable and remove a persistent webhook endpoint. |
| POST | /api/v1/webhooks/{webhook_id}/test | Send a signed test payload to a persistent webhook endpoint. |
| POST | /api/v1/webhook-deliveries/{delivery_id}/resend | Retry a previous webhook delivery attempt with a fresh delivery record. |
| POST | /api/v1/domains/{domain_id}/verify | Check the ownership TXT token for a monitored domain. |
| POST | /api/v1/domains/{domain_id}/scan | Run a manual monitored-domain scan after verification. |
| GET | /api/v1/domains/{domain_id}/runs | List scan runs for a monitored domain. |
| GET | /api/v1/domains/{domain_id}/history | Read domain drift history for authentication, transport security, DKIM selectors, and DNSBL state. |
| GET | /api/v1/domains/{domain_id}/reputation-timeline | Read normalized reputation and policy events for a monitored domain. |
| GET | /api/v1/domains/{domain_id}/ramp-guidance | Return advisory sender ramp guidance based on monitored evidence. |
| POST | /api/v1/incidents | Create an incident report to collect deliverability evidence and diagnosis notes. |
| GET | /api/v1/incidents | List incident reports for the current account or workspace. |
| GET | /api/v1/incidents/{incident_id} | Fetch one incident report with linked report, domain, placement, and validation evidence. |
| PATCH | /api/v1/incidents/{incident_id} | Update incident status, severity, audience, or summary fields. |
| POST | /api/v1/incidents/{incident_id}/generate-test | Generate a deliverability test address from an incident workflow. |
| POST | /api/v1/incidents/{incident_id}/link-report | Attach a deliverability report to an incident. |
| POST | /api/v1/incidents/{incident_id}/link-domain | Attach monitored-domain evidence to an incident. |
| POST | /api/v1/incidents/{incident_id}/link-placement | Attach inbox placement evidence to an incident. |
| POST | /api/v1/incidents/{incident_id}/link-lead-validation | Attach one recipient validation result to an incident. |
| POST | /api/v1/incidents/{incident_id}/link-bulk-validation | Attach a bulk validation job to an incident. |
| POST | /api/v1/incidents/{incident_id}/diagnose | Generate an evidence-ranked diagnosis from linked incident data. |
| GET | /api/v1/bounce-events | List ingested DSN bounce evidence. |
| GET | /api/v1/feedback-complaints | List ingested ARF complaint evidence. |
| GET | /api/v1/suppressions | Alias for listing suppression entries. |
| POST | /api/v1/suppressions | Alias for creating a suppression entry. |
| PATCH | /api/v1/suppressions/{suppression_id} | Update an address suppression through the short alias path. |
| PATCH | /api/v1/suppression-entries/{suppression_id} | Update active state or reason for a suppression entry. |
| GET | /api/v1/reports | List owned deliverability reports for the current API key owner. |
| GET | /api/v1/reports/shared/{share_token} | Fetch a shared report by private share token. |
| GET | /api/v1/sandbox/projects | List sandbox capture projects for the current account, workspace, or project. |
| POST | /api/v1/sandbox/projects | Create a sandbox project with a generated address and one-time SMTP password. |
| GET | /api/v1/sandbox/projects/{project_id} | Fetch sandbox project setup metadata without exposing the stored SMTP secret. |
| PATCH | /api/v1/sandbox/projects/{project_id} | Update sandbox project name, status, or capture settings. |
| POST | /api/v1/sandbox/projects/{project_id}/rotate-credentials | Rotate authenticated SMTP credentials and return the new password once. |
| POST | /api/v1/sandbox/projects/{project_id}/archive | Soft-archive a sandbox project and stop accepting new captured messages. |
| GET | /api/v1/sandbox/projects/{project_id}/messages | List captured sandbox messages for one project with status and recipient filters. |
| GET | /api/v1/sandbox/messages/{message_id} | Fetch parsed headers, bodies, metadata, and linked report information for a message. |
| GET | /api/v1/sandbox/messages/{message_id}/source | Read retained raw MIME source for an owned sandbox message. |
| POST | /api/v1/sandbox/messages/{message_id}/analyze | Re-run deliverability analysis for a captured sandbox message when needed. |
| GET | /api/v1/sandbox/messages/{message_id}/analysis | Fetch the linked deliverability analysis and CI threshold result for a message. |
| POST | /api/v1/sandbox/messages/{message_id}/ci-check | Evaluate a captured message against score and check-status thresholds. |
| GET | /api/v1/sandbox/ci-checks | List reusable sandbox CI threshold profiles. |
| POST | /api/v1/sandbox/ci-checks | Create a reusable sandbox CI threshold profile for a project. |
| PATCH | /api/v1/sandbox/ci-checks/{check_id} | Update an existing sandbox CI threshold profile. |
| DELETE | /api/v1/sandbox/ci-checks/{check_id} | Delete a sandbox CI threshold profile. |
| PATCH | /api/v1/seed-inboxes/{seed_id} | Update an encrypted seed inbox used for placement polling. |
| POST | /api/v1/seed-inboxes/{seed_id}/test | Test IMAP connectivity for one seed inbox. |
| PATCH | /api/v1/placement-schedules/{schedule_id} | Update a recurring placement diagnostic schedule. |
| DELETE | /api/v1/placement-schedules/{schedule_id} | Delete a placement diagnostic schedule. |
| GET | /api/v1/placement-schedules/{schedule_id}/runs | List runs created from a placement schedule. |
| POST | /api/v1/placement-schedules/{schedule_id}/run | Create one diagnostic placement run from a schedule. |
| PATCH | /api/v1/placement-send-identities/{identity_id} | Update encrypted SMTP identity metadata or credentials. |
| DELETE | /api/v1/placement-send-identities/{identity_id} | Remove a saved SMTP send identity. |
| POST | /api/v1/placement-send-identities/{identity_id}/test | Test SMTP connectivity for one authorized diagnostic send identity. |
| GET | /api/v1/placement-trends | Return placement trend summaries across recent diagnostic tests. |
| GET | /api/v1/placement-tests/{test_id} | Fetch one placement test with seed results and classification evidence. |
| PATCH | /api/v1/workspace-members/{member_id} | Update a workspace member role. |
| DELETE | /api/v1/workspace-members/{member_id} | Remove a workspace member. |
| POST | /api/v1/workspace-invitations/{invitation_id}/resend | Resend a pending workspace invitation email. |
| POST | /api/v1/workspace-invitations/{invitation_id}/revoke | Revoke a pending workspace invitation. |
| POST | /api/v1/workspace-invitations/accept | Accept an invitation token through API-key authenticated workflow automation. |
| POST | /api/v1/dmarc/forensic-reports/upload | Upload a DMARC forensic/RUF report file. |
| POST | /api/v1/dmarc/tlsrpt-reports/upload | Upload an SMTP TLS-RPT JSON gzip or JSON report file. |
| GET | /api/v1/dmarc/reports | List parsed DMARC aggregate reports. |
| GET | /api/v1/dmarc/reports/{report_id} | Fetch report metadata and summary for one DMARC aggregate report. |
| GET | /api/v1/dmarc/reports/{report_id}/rows | Inspect normalized source rows for one DMARC aggregate report. |
| PATCH | /api/v1/dmarc/alerts/{alert_id} | Acknowledge or resolve a DMARC dashboard alert. |
| PATCH | /api/v1/dmarc/mailboxes/{mailbox_id} | Update encrypted IMAP settings for a DMARC ingestion mailbox. |
| POST | /api/v1/dmarc/mailboxes/{mailbox_id}/test | Test a DMARC mailbox IMAP connection. |
| POST | /api/v1/dmarc/mailboxes/{mailbox_id}/ingest | Pull aggregate, RUF, and TLS-RPT attachments from a configured mailbox. |
| PATCH | /api/v1/dmarc/mailboxes/{mailbox_id}/schedule | Set the recurring ingestion schedule for a DMARC mailbox. |
Client examples
// Node.js
const baseUrl = process.env.WILLITINBOX_API_URL;
const apiKey = process.env.WILLITINBOX_API_KEY;
const res = await fetch(baseUrl + "/api/v1/validate", {
method: "POST",
headers: {
"Authorization": "Bearer " + apiKey,
"Content-Type": "application/json",
},
body: JSON.stringify({ email: "person [at] example.com" }),
});
const result = await res.json();# Python
import os, requests
res = requests.post(
f"{os.environ['WILLITINBOX_API_URL']}/api/v1/validate",
headers={"Authorization": f"Bearer {os.environ['WILLITINBOX_API_KEY']}"},
json={"email": "person [at] example.com"},
timeout=30,
)
result = res.json()Webhooks
Bulk jobs POST completion payloads to persistent webhook endpoints and optional ad-hoc webhook URLs. WillItInbox sends X-WillItInbox-Signature using HMAC SHA-256 over the raw JSON body.
X-WillItInbox-Event: bulk.completed
X-WillItInbox-Signature: sha256=<hex-hmac>Error format
API errors include a stable code for client handling.
{
"detail": {
"code": "quota_exceeded",
"message": "Monthly quota exceeded.",
"feature": "validations"
}
}