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_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Rate 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.

LimitScopeApplies to
Free 30, Starter 120, Pro 600, Agency 2000 requests/minAPI keyEvery authenticated /api/v1 request.
120 email verification rows/minUser or workspace/api/v1/validate, /api/v1/validate/batch, and /api/v1/validate/bulk.
Monthly tests, validations, and bulk rowsUser or workspaceShared web app and API usage.
Monthly API callsUser or workspaceAPI-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.

WorkflowEndpoint familyProduction policy
Signup and lead capture/api/v1/validateAccept high-confidence valid results, block confirmed invalid, segment risky, and retry unknown.
CSV imports and list hygiene/api/v1/validate/bulkKeep 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, webhooksRoute 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-eventsKeep 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/signup

Error 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);
POST/api/v1/validate

Validate 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
}
GET/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"
POST/api/v1/validate/batch

Validate 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
  }
}
POST/api/v1/validate/bulk

Upload 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]"
GET/api/v1/credit-wallet

Return 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"
GET/api/v1/credit-packs/quote

Quote 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
    }
  }
}
POST/api/v1/credit-checkout

Create 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}'
GET/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"
}
GET/api/v1/bulk/{job_id}/download

Download 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
POST/api/v1/bounce-events/ingest

Upload 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]"
POST/api/v1/feedback-complaints/ingest

Upload 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]"
GET/api/v1/suppression-entries

List 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"
POST/api/v1/suppression-entries

Create 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"}'
POST/api/v1/tests

Generate 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..."
}
GET/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"
POST/api/v1/reports/{token}/share

Create 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"
GET/api/v1/reports/{token}/pdf

Download 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
GET/api/v1/usage

Return 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"
GET/api/v1/usage/series

Return 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 }
  ]
}
GET/api/health

Return 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
      }
    }
  }
}
POST/api/v1/webhooks

Create 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"]}'
GET/api/v1/webhook-deliveries

List recent webhook delivery attempts, response codes, failures, and delivered timestamps.

curl "$WILLITINBOX_API_URL/api/v1/webhook-deliveries" \
  -H "Authorization: Bearer $WILLITINBOX_API_KEY"
POST/api/v1/webhooks/{webhook_id}/test

Send 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"
POST/api/v1/webhook-deliveries/{delivery_id}/resend

Create 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"
POST/api/v1/domains

Create 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"}'
POST/api/v1/domains/{domain_id}/scan

Run 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"
GET/api/v1/domains/{domain_id}/history

Return 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"
POST/api/v1/postmaster/google/oauth/start

Start 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"}'
GET/api/v1/postmaster/google/oauth/callback

Browser 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=...
GET/api/v1/postmaster-integrations

List 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"
POST/api/v1/postmaster-integrations/{integration_id}/sync

Run 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"
DELETE/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"
GET/api/v1/postmaster-integrations/{integration_id}/domains

List 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"
PATCH/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"}'
GET/api/v1/domains/{domain_id}/provider-reputation

Return 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"
GET/api/v1/provider-reputation-snapshots

List 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"
POST/api/v1/dmarc/upload

Upload 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]"
GET/api/v1/dmarc/forensic-reports

List 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"
GET/api/v1/dmarc/tlsrpt-reports

List 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"
GET/api/v1/dmarc/summary

Return 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"
GET/api/v1/dmarc/sources

List sending sources ordered by failed DMARC volume, then total volume.

curl "$WILLITINBOX_API_URL/api/v1/dmarc/sources" \
  -H "Authorization: Bearer $WILLITINBOX_API_KEY"
PATCH/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}'
POST/api/v1/dmarc/mailboxes

Beta: 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"}'
POST/api/v1/dmarc/mailboxes/{mailbox_id}/ingest

Beta: 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"
PATCH/api/v1/dmarc/mailboxes/{mailbox_id}/schedule

Beta: 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}'
GET/api/v1/dmarc/timeseries

Return 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"
GET/api/v1/dmarc/rollout-planner

Return 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"
GET/api/v1/dmarc/source-ownership

Summarize 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"
GET/api/v1/dmarc/reports/{report_id}/rows

Inspect 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"
GET/api/v1/dmarc/alerts

List open DMARC alerts created from monitored-domain aggregate report ingestion.

curl "$WILLITINBOX_API_URL/api/v1/dmarc/alerts" \
  -H "Authorization: Bearer $WILLITINBOX_API_KEY"
PATCH/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"}'
POST/api/v1/notification-channels

Beta: 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/..."}'
POST/api/v1/placement-tests

Create 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"}'
POST/api/v1/placement-schedules

Create 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"]}'
POST/api/v1/placement-schedules/{schedule_id}/run

Manually 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"
POST/api/v1/placement-send-identities

Store 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"}'
POST/api/v1/seed-inboxes

Add 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"}'
GET/api/v1/seed-providers

Return provider-level seed counts and credential readiness for placement testing.

curl "$WILLITINBOX_API_URL/api/v1/seed-providers" \
  -H "Authorization: Bearer $WILLITINBOX_API_KEY"
GET/api/v1/placement-heatmaps

Summarize recent placement outcomes by provider and folder.

curl "$WILLITINBOX_API_URL/api/v1/placement-heatmaps" \
  -H "Authorization: Bearer $WILLITINBOX_API_KEY"
POST/api/v1/placement-tests/{test_id}/poll

Poll 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"
GET/api/v1/workspaces

Return 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"
PATCH/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"}'
DELETE/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"
POST/api/v1/workspaces/{workspace_id}/restore

Restore 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"
POST/api/v1/workspace-projects

Create 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"}'
PATCH/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"}'
DELETE/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"
POST/api/v1/workspace-projects/{project_id}/restore

Restore 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"
GET/api/v1/workspace-members

List 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"
POST/api/v1/workspace-invitations

Create 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"}'
GET/api/v1/audit-events

List 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"
PUT/api/v1/branded-report-settings

Save 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

MethodPathUse
GET/api/v1/api-keys/{api_key_id}/usageInspect usage attributed to one API key for owner dashboards and audits.
GET/api/v1/alert-policiesList monitoring alert policies for domain, DMARC, TLS-RPT, and score signals.
POST/api/v1/alert-policiesCreate 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/alertsList 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}/eventsInspect 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}/testSend 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}/testSend a signed test payload to a persistent webhook endpoint.
POST/api/v1/webhook-deliveries/{delivery_id}/resendRetry a previous webhook delivery attempt with a fresh delivery record.
POST/api/v1/domains/{domain_id}/verifyCheck the ownership TXT token for a monitored domain.
POST/api/v1/domains/{domain_id}/scanRun a manual monitored-domain scan after verification.
GET/api/v1/domains/{domain_id}/runsList scan runs for a monitored domain.
GET/api/v1/domains/{domain_id}/historyRead domain drift history for authentication, transport security, DKIM selectors, and DNSBL state.
GET/api/v1/domains/{domain_id}/reputation-timelineRead normalized reputation and policy events for a monitored domain.
GET/api/v1/domains/{domain_id}/ramp-guidanceReturn advisory sender ramp guidance based on monitored evidence.
POST/api/v1/incidentsCreate an incident report to collect deliverability evidence and diagnosis notes.
GET/api/v1/incidentsList 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-testGenerate a deliverability test address from an incident workflow.
POST/api/v1/incidents/{incident_id}/link-reportAttach a deliverability report to an incident.
POST/api/v1/incidents/{incident_id}/link-domainAttach monitored-domain evidence to an incident.
POST/api/v1/incidents/{incident_id}/link-placementAttach inbox placement evidence to an incident.
POST/api/v1/incidents/{incident_id}/link-lead-validationAttach one recipient validation result to an incident.
POST/api/v1/incidents/{incident_id}/link-bulk-validationAttach a bulk validation job to an incident.
POST/api/v1/incidents/{incident_id}/diagnoseGenerate an evidence-ranked diagnosis from linked incident data.
GET/api/v1/bounce-eventsList ingested DSN bounce evidence.
GET/api/v1/feedback-complaintsList ingested ARF complaint evidence.
GET/api/v1/suppressionsAlias for listing suppression entries.
POST/api/v1/suppressionsAlias 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/reportsList 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/projectsList sandbox capture projects for the current account, workspace, or project.
POST/api/v1/sandbox/projectsCreate 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-credentialsRotate authenticated SMTP credentials and return the new password once.
POST/api/v1/sandbox/projects/{project_id}/archiveSoft-archive a sandbox project and stop accepting new captured messages.
GET/api/v1/sandbox/projects/{project_id}/messagesList 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}/sourceRead retained raw MIME source for an owned sandbox message.
POST/api/v1/sandbox/messages/{message_id}/analyzeRe-run deliverability analysis for a captured sandbox message when needed.
GET/api/v1/sandbox/messages/{message_id}/analysisFetch the linked deliverability analysis and CI threshold result for a message.
POST/api/v1/sandbox/messages/{message_id}/ci-checkEvaluate a captured message against score and check-status thresholds.
GET/api/v1/sandbox/ci-checksList reusable sandbox CI threshold profiles.
POST/api/v1/sandbox/ci-checksCreate 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}/testTest 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}/runsList runs created from a placement schedule.
POST/api/v1/placement-schedules/{schedule_id}/runCreate 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}/testTest SMTP connectivity for one authorized diagnostic send identity.
GET/api/v1/placement-trendsReturn 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}/resendResend a pending workspace invitation email.
POST/api/v1/workspace-invitations/{invitation_id}/revokeRevoke a pending workspace invitation.
POST/api/v1/workspace-invitations/acceptAccept an invitation token through API-key authenticated workflow automation.
POST/api/v1/dmarc/forensic-reports/uploadUpload a DMARC forensic/RUF report file.
POST/api/v1/dmarc/tlsrpt-reports/uploadUpload an SMTP TLS-RPT JSON gzip or JSON report file.
GET/api/v1/dmarc/reportsList 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}/rowsInspect 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}/testTest a DMARC mailbox IMAP connection.
POST/api/v1/dmarc/mailboxes/{mailbox_id}/ingestPull aggregate, RUF, and TLS-RPT attachments from a configured mailbox.
PATCH/api/v1/dmarc/mailboxes/{mailbox_id}/scheduleSet 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"
  }
}