SAFETY
Identity verification
Let a recipient confirm that an address is operated by one of your agents. Publication is off by default, everything it reports is self-asserted by you rather than checked by TekMail, and turning it on also confirms to anyone who asks that the address exists.
What a recipient can check
Every message an agent sends can carry provenance headers naming the agent and a verification token. A recipient — or their mail tooling — can hand either that token or the address itself to a public endpoint and get back one of exactly two answers. No API key is involved: the person checking your message is not your customer, and requiring a TekMail account to answer “is this real?” would make the feature useless.
GET /api/public/verify/{token}Resolve the token from a message's X-TekMail-Verify header. Tokens never expire, so an archived message stays checkable; publication is revoked by switching the setting off, not by waiting.
GET /api/public/verify?address=The same answer for a recipient who has the address but not the header. Exact match, case-insensitive. There is no prefix search, no wildcard, no listing and no bulk form.
curl https://api.tekmail.app/api/public/verify?address=support%40agents.tekmail.app
{
"status": "tekmail_agent",
"agent_address": "support@agents.tekmail.app",
"declared_purpose": "Answers billing questions for Acme customers",
"operator": "ops@acme.example",
"domain_verified": "verified"
}Publishing is opt-in, and the trade-off is real
The switch is off by default on every agent, and nothing about an agent is published until its owner turns it on.
For an agent that has not opted in, the endpoint answers {"status":"unknown"} — the identical body it returns for an address that has never existed and for a forged token. All three are indistinguishable, and every one of them is an HTTP 200. There is deliberately no 404: a status code that said “no such agent” would answer through the response line the question the body refuses to answer.
# An unpublished agent, a stranger's address and a forged token — all identical.
{
"status": "unknown"
}What verification does not say
The endpoint reports two things: that an address is operated by a TekMail agent, and what that agent's owner declares about it. That is the entire claim, and the wording is chosen to keep it that narrow — the status field reads tekmail_agent rather than verified, because TekMail attests to who runs an address and never to whether a particular message is trustworthy.
- The declared purpose and operator contact are self-asserted. You write them; TekMail publishes them unchanged and does not check them. A recipient should read them as “the owner says this”, not as anything TekMail confirmed.
- It is not an endorsement. A published identity is not a statement that a message is safe, wanted, or legitimate. Treat it as identification, the way a return address identifies a sender without vouching for the letter.
- It says nothing about where mail lands. Verification is unrelated to inbox placement, spam-folder outcomes and tab classification, and
domain_verifiedreports sender-authentication state for the sending domain only. - There is no score, grade or rating. Nothing here compresses an identity into a number, and nothing should be built on top of it that does.
- A null is not a failure.
declared_purposeandoperatorare null when the owner published nothing, anddomain_verifiedis null when TekMail has nothing to assert — which is not the same as knowing the domain failed.
Calling it from a browser
These are the only TekMail endpoints that accept a cross-origin browser request, because the person checking a message is a recipient rather than an account holder. Send a plain fetch(url) and read the JSON.
const res = await fetch(
"https://api.tekmail.app/api/public/verify?address=" + encodeURIComponent(address)
);
const body = await res.json();
// Branch on status and nothing else. "unknown" carries no reason field, by design.
if (body.status === "tekmail_agent") {
show(body.agent_address, body.declared_purpose, body.operator);
}Add no custom request headers. A plain GET is a simple request that needs no CORS preflight; adding a header turns it into a preflighted one, and the preflight is answered by the API-wide policy rather than this route's.
Rate limit
Verification is capped at roughly 30 requests per hour per client address. That number is an abuse cap, not a contract: the counter lives in memory inside a single API process, so the effective ceiling scales with however many instances are running and every counter resets when we deploy. Build for “this is rate limited, handle a 429” rather than for the specific figure. A 429 is a statement about your request volume and never an answer about the address you asked about.