API documentation

Two APIs share one base URL: verification, paid with verification credits, and sending, paid with email credits. Both speak JSON over HTTPS.

Overview

The base URL for every request is https://wisesender.com. Requests and responses are JSON, encoded as UTF-8. All endpoints allow cross-origin calls, but keep your keys on your server: a key in browser code can be copied by anyone.

EndpointWhat it doesBilled in
GET /v1/verifyCheck one addressVerification credits
POST /v1/verify/bulkCheck up to 1,000 addressesVerification credits
POST /v1/email/sendSend transactional emailEmail credits

Authentication

Create keys in the dashboard. Each key is shown once; only a hash is stored, so copy it somewhere safe. You can hold up to 10 keys of each type and revoke any of them instantly.

Key typeStarts withSend it as
Verification keyws_live_X-API-Key header, or ?key= in the URL
Sending keyws_send_Authorization: Bearer header, or X-API-Key
Prefer the header over the query string. URLs end up in server logs and browser history.

Verify one email

ParameterDescription
emailRequired. The address to check.
modepower (default) checks the mailbox with the receiving server and takes a few seconds. quick skips the mailbox and answers in under a second.
curl "https://wisesender.com/v1/[email protected]&mode=power" \
  -H "X-API-Key: ws_live_YOUR_KEY"

Verify in bulk

POST/v1/verify/bulk

Send up to 1,000 addresses in one request. Duplicates are removed before charging. The request waits until every address is checked, so allow a long timeout in power mode; for bigger lists, upload a file in the dashboard instead.

curl https://wisesender.com/v1/verify/bulk \
  -H "X-API-Key: ws_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "emails": ["[email protected]", "[email protected]"], "mode": "power" }'

The result object

FieldMeaning
statussafe, risky or invalid. The short answer.
categoryThe detailed verdict. See categories.
score0 to 100. Higher is more likely to be delivered.
reasonA plain-language explanation, e.g. "Mailbox does not exist".
safe_to_sendtrue for safe and role results.
syntaxThe address is well formed.
domain_existsThe domain resolves. null if DNS failed.
mx_foundThe domain publishes mail servers.
mx_recordsMail server host names, best first.
mailbox_existsThe server confirmed the inbox. null if not checked or not answered.
mailbox_fullThe inbox exists but is over quota.
catch_allThe domain accepts every address.
disposableA throwaway inbox provider.
role_accountA shared address such as info@ or sales@.
free_providerGmail, Outlook, Yahoo and similar.
suggestionThe likely intended domain for a typo, or null.
smtp_noteThe mail server's own reply, for debugging.
modeThe mode that was used.

Categories

categorystatusscoreWhat to do
safesafe90 to 95Send.
rolesafe75Send; expect lower engagement.
valid_domainrisky60Quick mode only. Run power mode before a campaign.
catch_allrisky55Send carefully, watch bounces.
unknownrisky40Retry later. Refunded in power mode.
inbox_fullrisky25Retry later.
disposablerisky10Don't send.
invalidinvalid0Remove from your list.

Send an email

POST/v1/email/send

The from domain must be verified under Transactional email, Domains. Without cc or bcc, each to address receives its own copy and can carry its own merge_data. With cc or bcc, one message goes to everyone.

FieldDescription
fromRequired. "[email protected]" or "Acme <[email protected]>".
toRequired. An address, or a list. Items may be objects: { "email", "name", "merge_data" }.
cc, bccOptional. Same formats as to. 50 recipients in total.
subjectRequired unless a template is used. Up to 500 characters.
html, textAt least one, unless a template is used. 500 KB in total.
template_keySend a saved template, e.g. tpl_3f9a1c2b7d4e.
merge_dataValues for {{placeholders}}, shared by all recipients.
reply_toOptional reply address.
attachmentsSee attachments.
tagsUp to 10 key/value pairs, returned in logs and webhooks.
verifytrue runs a quick check first and skips invalid addresses (not charged).
unsubscribe_urlAn https URL added as a one-click List-Unsubscribe header.
curl https://wisesender.com/v1/email/send \
  -H "Authorization: Bearer ws_send_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <[email protected]>",
    "to": [{ "email": "[email protected]", "name": "Jane", "merge_data": { "code": "482913" } }],
    "subject": "Your login code",
    "html": "<p>Hi {{name}}, your code is <b>{{code}}</b></p>",
    "tags": { "type": "otp" }
  }'

Each recipient's status is sent, suppressed (on your do-not-send list), invalid (failed the optional check) or failed. Only sent uses an email credit.

Templates

Create templates in the dashboard and send them with template_key. Placeholders use double braces and support dotted paths:

{{name}}Inserted with HTML escaping. Safe for user-supplied values.
{{order.id}}Reads nested values from merge_data.
{{{html_block}}}Triple braces insert the value as raw HTML. Use only with trusted content.

Unknown placeholders become empty text. A recipient's own merge_data overrides the shared values, and name and email are filled from the recipient automatically.

Attachments

Pass a list of objects with a file name and base64 content. Up to 10 files and 10 MB in total. Executable file types are refused because mailbox providers block them.

"attachments": [
  { "name": "invoice-10482.pdf", "content": "JVBERi0xLjQK..." },
  { "name": "logo.png", "content": "iVBORw0KGgo...", "content_id": "logo" }
]
// reference the inline image in html as <img src="cid:logo">

SMTP relay

Use the relay when your software only speaks SMTP. The same domain checks, limits, logs and webhooks apply, and Bcc headers are removed before delivery.

Hostsmtp.wisesender.com
Port587 with STARTTLS, or 465 with TLS
Usernamewisesender
PasswordA sending key (ws_send_...)

Webhooks

Set an https URL under Transactional email, Settings. We POST one JSON event per recipient for sent, delivered, bounced, soft_bounced, complained, delayed, failed, opened and clicked.

{
  "event": "delivered",
  "message_id": "1842",
  "agent": "OTP",
  "from": "[email protected]",
  "to": "[email protected]",
  "recipient_type": "to",
  "subject": "Your login code",
  "tags": { "type": "otp" },
  "timestamp": "2026-11-10T09:14:03.120Z"
}

Check the signature

Every request carries X-WiseSender-Signature: sha256=<hex>, an HMAC-SHA256 of the raw body using your webhook secret. Compare it before trusting the event.

const crypto = require('node:crypto');
function isValid(rawBody, header, secret) {
  const good = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  return header?.length === good.length && crypto.timingSafeEqual(Buffer.from(header), Buffer.from(good));
}

Errors

Errors return a non-2xx status and a body like { "error": "Invalid API key" }.

StatusMeaning
400A field is missing or invalid. The message names it.
401The key is missing, wrong or revoked.
402Not enough credits. Buy a pack or wait for the daily refill.
403The sending domain is not verified, or sending is paused for the account.
404The endpoint or template does not exist.
413Too many addresses, recipients or bytes in one request.
429A rate or daily limit was reached. Slow down or try tomorrow.

Limits

Bulk verify1,000 addresses per request; 20,000 per file in the dashboard
Free checks without a key100 per IP address per day
Send API300 requests a minute per account, 50 recipients per request
Daily sending200 emails a day for new accounts, raised as your bounce and complaint rates stay low
Automatic pauseAbove 5% bounces or 0.3% complaints over 7 days, after 100 sends

Need a higher limit? Ask support with your expected volume.