API reference/monitors

Monitor a list on a schedule

POST/api/v1/email/monitors

authentication
Secret API key as a bearer token
billing
Creation is free. Each run bills every address like a single lookup — 1 credit for a fresh deliverable or risky verdict; undeliverable, suppressed and 7-day repeats are free.

Saves up to 500 addresses and re-verifies them every week or every month. The first run starts right away and only sets the baseline; from the next run on, every address that was deliverable last time and no longer is counts as decayed and is reported to the account's email. Runs honor the suppression list and the 7-day repeat cache, so a stable list costs little to keep watching.

Answers 201 with the monitor. The baseline run is queued, not finished: poll the monitor for last_run_at and last_summary.

Request body

field type description
namerequiredstringA label for the dashboard and the decay alerts. At most 100 characters.
emailsrequiredstring[]1 to 500 addresses; each item at most 254 characters.
cadencerequiredstringHow often the list is re-verified. One of: weekly, monthly.

Example request

curl -X POST https://spaw.co/api/v1/email/monitors \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Newsletter list",
  "emails": [
    "[email protected]",
    "[email protected]"
  ],
  "cadence": "weekly"
}'
const response = await fetch('https://spaw.co/api/v1/email/monitors', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk_live_…',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "name": "Newsletter list",
    "emails": [
      "[email protected]",
      "[email protected]"
    ],
    "cadence": "weekly"
  }),
});
const result = await response.json();
import requests

response = requests.post(
    'https://spaw.co/api/v1/email/monitors',
    headers={'Authorization': 'Bearer sk_live_…'},
    json={
        'name': 'Newsletter list',
        'emails': [
            '[email protected]',
            '[email protected]'
        ],
        'cadence': 'weekly'
    },
)
result = response.json()
$ch = curl_init('https://spaw.co/api/v1/email/monitors');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer sk_live_…', 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'name' => 'Newsletter list',
        'emails' => [
            '[email protected]',
            '[email protected]'
        ],
        'cadence' => 'weekly'
    ]),
]);
$result = json_decode(curl_exec($ch), true);

Responses

201The monitor was saved and its baseline run queued.

{
    "success": true,
    "data": {
        "monitor": {
            "id": 41,
            "name": "Newsletter list",
            "cadence": "weekly",
            "email_count": 2,
            "next_run_at": "2026-09-10T10:12:44+00:00",
            "last_run_at": null,
            "last_summary": null,
            "created_at": "2026-09-03T10:12:44+00:00"
        }
    }
}

401The key is missing, malformed, or revoked.

{
    "success": false,
    "error": {
        "code": "UNAUTHENTICATED",
        "message": "Provide a valid API key as a bearer token.",
        "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"
    }
}

429Over 5 requests per second for the key. Retry after the limit resets.

{
    "success": false,
    "error": {
        "code": "RATE_LIMITED",
        "message": "Too many requests. Retry after the limit resets.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}

Error codes

Failures answer { success: false, error: { code, message, request_id } }. Each code has its own page.

markdown version·openapi.json