SPF.Guru

The API

The same evaluations the pages render, as JSON. No account, no key, no payment. Every response is computed from live DNS at the moment you ask, so it is never a cached opinion about your record.

Three endpoints

What does this domain's record cost?

GET https://spf.guru/api/analyse?domain=example.com

Returns the DNS lookup count, whether it is over the limit of ten, the record published today, and a replacement a receiving server resolves in one lookup.

Where do the lookups go?

GET https://spf.guru/api/tree?domain=example.com

Expands every nested include and gives each branch its total cost including everything beneath it, which is how the ten term limit is actually applied. A record at fourteen could be fourteen cheap includes or one vendor costing eleven, and the fix is completely different in each case.

Would this message pass?

GET https://spf.guru/api/check?sender=user@example.com&ip=192.0.2.1

Walks the record the way a receiving server does and returns the result plus every mechanism, DNS query and macro expansion along the way. Add &record=v=spf1%20... to evaluate a proposed record instead of the published one, so a change can be tested before it goes live. Includes inside it still resolve for real, which is what makes the preview truthful.

Reading the numbers

Every response carries api_version, the domain or sender it measured, and checked, an ISO 8601 timestamp. A lookup count without its subject and its date is the thing that ends up quoted back a year later, so they travel together.

dns_lookups always arrives with dns_lookup_limit and over_limit rather than leaving you to compare it against a number you had to know. Where a record is over the limit, note says what that actually means: senders matched within the first ten still pass, and only what needs an eleventh gets permerror.

Machine-readable description

An OpenAPI 3.1 document is at /openapi.json, and /llms.txt summarises the site and this API in the llmstxt.org format.

Rate limits

10/minute per address, and 40/minute per /24 or /64 so a range is not a multiplier. Tighter than the website, because an API invites automation and every call is real recursive DNS against somebody else's nameservers.

An API call is charged against the site-wide budget too, so the API is a stricter slice of one allowance rather than a second one alongside it.

Over the limit you get 429 with Retry-After and a retry_after_seconds field. Nothing is charged for a refused request, so retrying does not extend your own lockout.

If you have a use that needs more than this, the about page says who to ask. It is a free service run by one person, so the answer depends on what you are doing, but asking works better than working around it.

Fair use

Every call performs live DNS resolution against the domain you name and every vendor it includes. That cost lands on their nameservers, not ours, which is the real reason the limits exist. Cache what you get; a record does not change between two calls a second apart.

Errors

400 for a missing or malformed parameter, with an error saying which. 429 when rate limited. A domain that does not resolve, or publishes no SPF record, is a 200 with ok: false and an error explaining why, because that is an answer about the domain rather than a fault in the request.

Stability

api_version is 1. Fields may be added without changing it; anything that would break a caller reading existing fields will not happen silently.

This is a free, best-effort service. The disclaimer covers what that means for relying on it.