# Verify emails in n8n with Spaw

Call the Spaw API from n8n's HTTP Request node with a header credential, branch on the verdict with an IF node, and what the n8n-nodes-spaw community node adds.

Updated: 2026-09-03

n8n runs on n8n Cloud or on your own server, and either way its HTTP Request node can talk to Spaw with nothing installed. A community node, `n8n-nodes-spaw`, is built and will be published to npm; it wraps the same endpoints as resources and operations with a saved credential. Both paths are described here.

## What works today: the HTTP Request node

1. Create a secret API key on the API keys page of your Spaw dashboard.
2. In n8n, create a credential of the generic Header Auth type. Set the name to `Authorization` and the value to `Bearer sk_live_…`. The key is stored encrypted and never shows in the workflow JSON.
3. Add an HTTP Request node after the node that produces the address. Set the method to POST and the URL to `https://spaw.co/api/v1/email`.
4. Set authentication to the generic credential type, pick Header Auth, and choose the credential from step 2.
5. Turn on sending a body, choose JSON, and use an expression for the content:

```json
{
  "email": "{{ $json.email }}"
}
```

6. Execute the node once with `deliverable@spaw.test` in the incoming item. It is one of six free test addresses that answer a fixed result and never touch your history.

The node outputs the API's envelope as one item: `data` holds the 27 fields of the [single-address response](/docs/api/verify-email), `meta` holds `credits_used`, `credits_remaining`, `cache_hit` and `request_id`.

For many items at once, send them to the [batch endpoint](/docs/api/verify-email-batch) instead. Set the URL to `https://spaw.co/api/v1/email/batch`, enable the node's option to execute once, and build the body with an expression that gathers every incoming item:

```json
{{ { "emails": $input.all().map(item => item.json.email).slice(0, 50) } }}
```

The answer's `data.results` array is in input order; a Split Out node turns it back into one item per address. A batch counts as one request against the 5 requests per second limit, which matters for workflows fed by large lists.

## The community node

`n8n-nodes-spaw` is a declarative community node written in TypeScript with no runtime dependencies, which is what n8n asks of nodes it verifies. Once it is on npm, self-hosted instances install it from the community nodes settings by package name, and n8n Cloud shows it after n8n's verification. It offers:

- A Spaw API credential holding the secret key, tested against your account endpoint when saved.
- Email resource: Verify, and Verify Many for up to 50 addresses per call.
- Domain resource: Get, the same signals as the domain endpoint.
- Suppression resource: Add, Get Many, and Remove, so bounce lists from other systems can be kept in sync.

It is not published yet. The HTTP Request node above uses the same endpoints, so a workflow built today can swap nodes later without changing what is stored.

## What to do with the verdict

Add an IF node after the request and compare `{{ $json.data.deliverable }}` with `deliverable`. The true branch continues to your CRM or mailing tool. On the false branch, a Switch node on `{{ $json.data.reason }}` separates `catch_all` and `role`, which are often worth keeping, from `disposable` and `mailbox_not_found`, which are not. When `{{ $json.data.did_you_mean }}` is filled, the address was a near miss, and writing the suggestion back to the source recovers the record. For a numeric threshold use `data.risk_score`, whose weights are published.

Workflows that verify at scale should also read the suppression list occasionally through the [list endpoint](/docs/api/list-suppressions): every undeliverable verdict lands there, and batch and bulk runs answer suppressed addresses for free.

## Cost

A fresh deliverable or risky answer spends 1 credit; undeliverable answers, invalid input, repeats within seven days and the test addresses are free. n8n executions are counted by n8n separately. The node handles `429 RATE_LIMITED` like any HTTP error, so enable the HTTP Request node's retry option for bursty workflows.

Reference: https://spaw.co/integrations/n8n
