Verification API

One call, and you know what happens if you send.

Check addresses at signup and before every send, so bad data never reaches your list or your sender reputation. Bearer token in, verdict out, with the score and reason codes behind it.

Request and response

The whole integration, on one screen.

No SDK, no client to construct, no wrapper to learn. A bearer token, one POST, and an object whose field names your code can branch on.

verify.sh
curl -X POST https://api.bounceintel.com/v1/check_email \
  -H "Authorization: Bearer $BOUNCEINTEL_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]"}'
response.json200
{
  "input": "[email protected]",
  "is_reachable": "safe",
  "syntax": {
    "domain": "stripe.com",
    "username": "ada",
    "is_valid_syntax": true
  },
  "mx": {
    "accepts_mail": true,
    "records": ["aspmx.l.google.com", "alt1.aspmx.l.google.com"]
  },
  "smtp": {
    "can_connect_smtp": true,
    "is_deliverable": true,
    "is_catch_all": false,
    "is_disabled": false,
    "has_full_inbox": false
  },
  "misc": {
    "is_disposable": false,
    "is_role_account": false,
    "is_b2c": false
  },
  "provider": "google_workspace",
  "provider_rules_applied": true,
  "score": {
    "score": 100,
    "category": "valid",
    "sub_reason": "deliverable",
    "safe_to_send": true,
    "confidence": 0.97,
    "confidence_level": "high",
    "reason_codes": ["deliverable", "tenant_history_positive"]
  },
  "bounce_risk": {
    "score": 3,
    "category": "low",
    "confidence": 0.94,
    "action": "send",
    "model_version": "br-2026.06",
    "risk_factors": [
      {
        "signal": "smtp_is_deliverable",
        "direction": "decreases_risk",
        "contribution": -0.41,
        "description": "Mailbox accepted the recipient at RCPT TO."
      }
    ]
  }
}
  • 01

    One endpoint

    POST /v1/check_email with an address. There is no session to establish.

  • 02

    Reason codes

    Documented codes you can branch on, not free-text English.

  • 03

    Score you own

    A 0 to 100 number, so your threshold is a config value rather than our decision.

  • 04

    Honest unknowns

    An inconclusive check returns 200 with an unknown verdict, never a fabricated one.

  • 05

    Batch as a job

    POST /v1/bulk takes a list and returns a job id you poll.

  • 06

    Rotatable keys

    More than one live key, revoked independently, without downtime.

Getting started

From no account to a verdict in your own code.

  1. 01

    Create a key

    Keys are issued from the dashboard. You can hold more than one live at a time and revoke them independently, so a rotation costs no downtime.

  2. 02

    Send the address

    One POST with an Authorization header and a JSON body. There is no session to establish and no handshake before it.

  3. 03

    Branch on the response

    Read the verdict, or the score against your own threshold, or the reason codes. All three are in the same object, so you never make a second call to find out why.

  4. 04

    Scale to lists

    The same key submits a batch as a job and polls it. The verdicts are identical to the ones the single endpoint returns, because it is the same pipeline.

Reference

The surface you integrate against.

Four endpoints and two headers. The full reference, with a live playground, is in the documentation.

Endpoint or headerKindWhat it does
POST /v1/check_emailsynchronousVerify one address and get the scored report back in the same response. This is the call almost every integration makes.
POST /v1/bulkjobSubmit a list and get a job id. Accepts far more addresses than you would want to hold a connection open for.
GET /v1/bulk/{job_id}jobPoll a job for its state and how far through it is, so your own UI can show progress rather than a spinner.
GET /v1/bulk/{job_id}/resultsjson | csvFetch a finished job's rows, paged, as JSON or as the same CSV the dashboard downloads.
Authorization: BearerheaderHow every request authenticates. Keep the key on your server: a key that reaches the browser is a public credit balance.
429 / Retry-AfterheaderWhat you get if you outrun your plan's rate limit. Wait the number of seconds in the header and retry; nothing is charged for a rejected request.

FAQ

What developers ask first

How do I authenticate?

An Authorization header with a bearer token. Keep the key on your server: a key that reaches the browser is a public credit balance.

What should I do with an unknown verdict?

Let the user through, flag the record and re-check later. Most unknowns are the receiving server declining to answer rather than a fact about the address.

Which plans include API keys?

Any paid plan, monthly or pay as you go. Free accounts verify in the dashboard, which is enough to see the response shape first.

Can I call it from the browser?

No. Proxy it through your own server. A key in the browser is a public credit balance.

What are the rate limits?

They are set per plan rather than published as one global number, because a signup-form integration and a nightly list run need very different shapes. When you exceed yours the API answers 429 with a Retry-After header and does not charge for the request.

Is there an SDK?

No, and that is the point. One endpoint with a JSON body needs no client library, and a thin wrapper is a dependency you have to keep current for no gain. Every language in the samples above uses its own standard HTTP client.

Read the response before you write against it.

100 credits on signup, no card. Run real addresses and see the exact object your code will get.