API reference/email
Verify an address from the browser with a publishable key
POST/api/v1/email/public
- authentication
- Publishable key in the body, checked against the browser Origin header
- billing
- Bills the key owner like a single lookup; capped by the key's daily credit cap when one is set.
The endpoint behind the form widget (https://spaw.co/spaw-form.js). It is authenticated by a publishable pk_ key in the body plus the browser's Origin header, which must match one of the domains the key is locked to. A missing Origin is rejected on purpose: servers use a secret key and POST /api/v1/email instead.
The lookup bills the key's owner under the normal rules and answers { "success", "data" } with no meta block, so page visitors never see the owner's balance. Because the key sits in page source, give it a daily credit cap in the dashboard: once the cap is spent the endpoint answers 429 KEY_SPEND_CAP_REACHED until the next day. Free answers (undeliverable, cache hits, test addresses) never count toward the cap.
For forms open to the public, store a Cloudflare Turnstile site key and secret on the publishable key. The endpoint then requires a confirmed turnstile_token with every lookup and answers 403 TURNSTILE_FAILED without one, before any credit is spent. Tokens are single-use. The form widget obtains a fresh token per lookup when the script tag carries data-turnstile-site-key.
Throttled at 20 requests per minute per IP.
Parameters
| name | in | type | description |
|---|---|---|---|
| Originrequired | header | string | Sent by browsers automatically. Its host must be on the key's allowed-domain list. |
Request body
| field | type | description |
|---|---|---|
| keyrequired | string | A publishable key, which starts with `pk_`. At most 64 characters. |
| emailrequired | string | The address to verify. At most 254 characters. |
| turnstile_token | string | null | Required when the key carries a Turnstile pair. A single-use token from the Turnstile widget on the page. At most 2,048 characters. |
Example request
curl -X POST https://spaw.co/api/v1/email/public \
-H "Origin: https://www.example.com" \
-H "Content-Type: application/json" \
-d '{
"key": "pk_live_…",
"email": "[email protected]"
}'Responses
200The same fields as `POST /api/v1/email`, without a meta block.
{
"success": true,
"data": {
"email": "[email protected]",
"deliverable": "deliverable",
"reason": null,
"risk_score": 0,
"risk_level": "low",
"did_you_mean": null
}
}401The publishable key does not exist or was revoked.
{
"success": false,
"error": {
"code": "INVALID_PUBLISHABLE_KEY",
"message": "That publishable key does not exist or was revoked.",
"request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
}
}402The balance is empty. The lookup did not run.
{
"success": false,
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Your credit balance is empty.",
"request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
}
}403The page's origin is not on the key's allowed-domain list (`ORIGIN_NOT_ALLOWED`), or the key requires a Turnstile token that was missing or not confirmed (`TURNSTILE_FAILED`).
{
"success": false,
"error": {
"code": "ORIGIN_NOT_ALLOWED",
"message": "This publishable key cannot be used from this origin.",
"request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
}
}422The request body could not be validated; `error.errors` lists the fields.
{
"success": false,
"error": {
"code": "VALIDATION_FAILED",
"message": "The email field is required.",
"errors": {
"email": [
"The email field is required."
]
},
"request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
}
}429The key has spent its owner's daily credit cap (`KEY_SPEND_CAP_REACHED`), or the IP exceeded 20 requests per minute (`RATE_LIMITED`).
{
"success": false,
"error": {
"code": "KEY_SPEND_CAP_REACHED",
"message": "This publishable key has reached its daily credit cap. The counter resets each day.",
"request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
}
}Error codes
Failures answer { success: false, error: { code, message, request_id } }. Each code has its own page.