AttestPage · Docs · Pricing · OpenAPI · llms.txt

Scan a bot reply before it is sent

Last updated: 2026-10-21

POST /v1/scan/reply checks a draft reply your bot is about to send to a person. Send the reply, and optionally the text the bot answered from and the hosts it may link to; get back verdict (pass, caution or block) and a list of findings, under a signed receipt. Nothing is fetched: every check runs on the text you send. Price: US$0.003 per call.

Free sample, no payment: curl -s https://vehcdj664efetfrsolne5umanq.srv.us/v1/sample/scan-reply runs the real check on a support bot's draft that copied a phishing link, a hidden instruction and a made-up discount from a poisoned ticket. It answers block.

Request

{
  "text": "Your refund of $25 is on its way. Track it at https://shop.example.net/orders or confirm your card at https://shop-example.net.verify-account.io/login.",
  "source_text": "Refund approved: $25, back to the original card in 5 to 7 days. Order page: https://shop.example.net/orders",
  "allowed_urls": ["https://shop.example.net"]
}
FieldRequiredMeaning
textyesthe draft reply: plain text, Markdown or HTML, 1 to 10,000 characters
source_textnothe text the bot answered from (a ticket, a tool result, a page), at most 40,000 characters. Links whose host is not in it, and price or discount numbers not in it, become findings
allowed_urlsnoup to 50 URLs or bare hosts the bot may link to. A link is allowed when its host is one of these or a subdomain of one; paths are not compared

The request body is capped at 64 KB. Every field is checked before payment, so a bad request is answered with 400 and not charged. An unpaid call gets the 402 offer; an empty body or {} also gets the 402 offer (not a 400), so the price can be read.

Response

{
  "verdict": "block",
  "findings": [
    { "type": "url_not_allowed", "severity": "high", "url": "https://shop-example.net.verify-account.io/login", "host": "shop-example.net.verify-account.io", "detail": "This link's host is not in allowed_urls or source_text." },
    { "type": "lookalike_host", "severity": "high", "url": "https://shop-example.net.verify-account.io/login", "host": "shop-example.net.verify-account.io", "detail": "The host uses the name \"example\" of shop.example.net but belongs to verify-account.io." }
  ],
  "urls": [
    { "url": "https://shop.example.net/orders", "host": "shop.example.net", "allowed": true },
    { "url": "https://shop-example.net.verify-account.io/login", "host": "shop-example.net.verify-account.io", "allowed": false }
  ],
  "checks": { "urls_against_allowlist": true, "numbers_against_source": true, "hosts": true, "injection": true },
  "counts": { "urls": 2, "findings": 2, "high": 2, "medium": 0, "low": 0 },
  "advice": "Do not send this reply as written: it has at least one high-severity finding (see findings).",
  "receipt": "eyJ…",
  "tier": "paid"
}

Findings

typeSeverityRaised when
url_not_allowedhigh with allowed_urls, medium with only source_texta link's host is not in allowed_urls, not a subdomain of one, and not the host of a link in source_text
lookalike_hosthigha host that is not allowed uses the name of an allowed or source host, or of a common brand (PayPal, Apple, Google, Microsoft, Amazon and others), in a subdomain or a hyphenated name (shop-example.net.verify-account.io), with swapped look-alike characters (paypa1.com), or one or two letters off
punycode_hosthighthe host is punycode (xn--) or has non-ASCII letters
ip_hosthighthe link points at a bare IP address
credentials_in_urlhighthe link has a user part before @ (https://paypal.com@evil.example), so it opens the host after the @
link_text_mismatchhigha Markdown or HTML link whose text shows one host while the link opens another
shortener_hostmediumthe link is a URL shortener (bit.ly, tinyurl.com, t.co and others), which hides where it leads
injectionper flagthe reply carries an injection phrase; flag names it and its severity is the one in Detection. Text inside HTML comments counts as hidden (hidden_instructions, high)
invisible_characterslowzero-width or soft-hyphen characters, which can hide or split words
unsupported_pricemediuma price ($19, €10, 25 USD) whose number does not appear anywhere in source_text
unsupported_discountmediuma percentage with a word like off, discount, save, sale or promo in the same clause whose number does not appear anywhere in source_text

Known misses