- 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 answered lookup; reserved addresses and 7-day repeats are free, so a daily list costs at most one credit per address a week.
Saves up to 500 of your own addresses, your egress addresses, mail servers and office connections, and re-checks them every day, week or month. Addresses are canonicalised and deduplicated. The first run starts right away and only sets the baseline; from the next run on, every address that newly lands on a threat blocklist (Spamhaus DROP, ASN-DROP or the botnet C2 list), becomes a Tor exit, or scores high is reported to the account's email with the reason, so you learn that a mail server sits on a blocklist before your recipients' inboxes do.
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 |
|---|---|---|
| namerequired | string | A label for the alerts. At most 100 characters. |
| ipsrequired | string[] | 1 to 500 IPv4 or IPv6 addresses; duplicates and alternative spellings of one address count once. |
| cadencerequired | string | How often the list is re-checked. One of: daily, weekly, monthly. |
Example request
curl -X POST https://spaw.co/api/v1/ip/monitors \
-H "Authorization: Bearer sk_live_…" \
-H "Content-Type: application/json" \
-d '{
"name": "Mail servers",
"ips": [
"203.0.113.25",
"2001:db8::25"
],
"cadence": "daily"
}'Responses
201The monitor was saved and its baseline run queued.
{
"success": true,
"data": {
"monitor": {
"id": 4,
"name": "Mail servers",
"cadence": "daily",
"ip_count": 2,
"next_run_at": "2026-09-06T10:12:44+00:00",
"last_run_at": null,
"last_summary": null,
"created_at": "2026-09-05T10: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.