Getting Started with BlueFox Edge

BlueFox Edge verifies brand claims made by AI agents — and each verification on this page, made with an API key, mints a signed reliance receipt: a portable, tamper-evident record of what was checked, against what, when. Proof of reliance, never proof of truth. Published accuracy: 91.47% match-rate (n=938), financial dimension (SEC EDGAR), computed 2026-10-04; other dimensions not yet validated.

1. Get an API Key

Two ways in — a browser form for people, and a programmatic endpoint for programs. The browser form includes a human check:

  1. Open api.bluefoxedge.ai/get-key and sign up with a name and your email.
  2. Your key is shown once — copy it immediately. It starts out pending.
  3. Click the confirmation link we email you. Your key is now active.

Programs skip the browser. POST https://api.bluefoxedge.ai/v1/api-keys/programmatic is the machine-to-machine twin of the form — same free tier, same terms, no bot challenge, completed unattended in one request. The body carries three fields: name (what this program is called), email (a contact address for the operator — not verified: no message is sent, the response reports email_verified: false, and the key is active immediately), and accept_terms, which must be true — creating a key forms a contract here exactly as it does on the form, and a request that omits the field or sends false is refused with HTTP 422 TERMS_NOT_ACCEPTED, no key created. Keys minted here are marked origin: "programmatic". The door is capped — per client address, per contact address, and across the endpoint as a whole; over a per-caller cap the refusal is HTTP 429 SIGNUP_RATE_LIMITED with Retry-After, and when the endpoint’s own ceiling is reached the refusal is HTTP 503 SIGNUP_UNAVAILABLE, which your own back-off does not clear — the form above is then the way through. Send an Idempotency-Key (at least 32 characters) and a retried request returns the original key rather than minting a second one.

Free tier: 100 API calls per UTC day, of which 10 claim-verification calls per UTC day (an inner meter, counted inside the daily allowance). Send your key as Authorization: Bearer YOUR_API_KEY.

2. Verify a Claim

All examples use the canonical API host api.bluefoxedge.ai. The apex host bluefoxedge.ai serves the same API; the website lives at www.bluefoxedge.ai.

curl -s -X POST https://api.bluefoxedge.ai/v1/brand/check \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"brand": "nike", "claims": ["Nike tagline is Just Do It"], "depth": "auto"}'
{
  "data": {
    "brand": "nike",
    "results": [{
      "claim": "Nike tagline is Just Do It",
      "verdict": "accurate",
      "confidence": 0.95,
      "confidence_tier": "high",
      "evidence": "The brand description explicitly mentions 'Just Do It' as Nike's tagline...",
      "method": "llm_verify",
      "receipt_id": "01KXFM36XG1J15AQYFBPX0D3SK"
    }],
    "depth_used": "auto"
  },
  "meta": { "request_id": "...", "timestamp": "..." }
}

depth: "fast" = rule engine on cached data, "standard" = LLM verification, "auto" = fast first, escalating when uncertain. Every result carries a receipt_id (null for a keyless x402 payer, who receives no receipt), and every success response is a {data, meta} envelope.

Free tier: 1 signed mint per UTC day (resets 00:00 UTC) — a further mint the same day returns HTTP 402 with x402 payment instructions.

Two meters, one bill: your plan sets the API-call allowance (100 API calls per UTC day on the free tier), while signed mints are counted separately — only the free tier is mint-capped, at 1 signed mint per UTC day. A mint spends one call from that same allowance, so the mint cap sits inside it, not beside it, and a third ceiling sits inside the same allowance: 10 claim-verification calls per UTC day. Paid plans include signed mints — your plan's daily call limit is the only meter. Every keyless call has a posted per-request price — the x402 table at /.well-known/x402 is the whole keyless price list, and each door's 402 is the quote of record. With a key, calls draw on your plan; the mint is the only act the free tier meters separately.

3. Read Your Receipt

curl -s https://api.bluefoxedge.ai/v1/receipts/YOUR_RECEIPT_ID \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "data": {
    "receipt_id": "01KXFM36XG1J15AQYFBPX0D3SK",
    "verdict": "accurate",
    "schema_version": "1.0.0",
    "content_digest": "sha256:61f52dcd6c5f90a4...c628e5",
    "chain_prev": "GENESIS",
    "chain_self": "sha256:720364a2dc9e411c...165d70",
    "envelope": {
      "not_an_attestation": true,
      "non_claims": [
        "not an attestation, certification, rating, or screening decision",
        "..."
      ],
      "chain": {
        "key_id": "6d5714a8479aaea7...cc6395",
        "signature": "W2ZrT1vJGteZwpx_..."
      }
    },
    "jwks_url": "https://api.bluefoxedge.ai/.well-known/jwks.json"
  },
  "meta": { "request_id": "...", "timestamp": "..." }
}

Normative — the one pointer never to follow. A verifier MUST NOT follow the jwks_url carried inside a receipt. That field sits outside the signature, so a forged receipt can aim it at the forger's own key set and the forgery verifies against it. Pin the key set out of band at https://api.bluefoxedge.ai/.well-known/jwks.json — the field is a convenience pointer only, and step 4 below pins the address in code for exactly this reason.

Receipts mint asynchronously — allow a few seconds after the verification call before fetching. not_an_attestation: true and the non_claims list ship in every envelope on purpose: a receipt is proof of reliance, never proof of truth. Server-side integrity check: POST /v1/receipts/YOUR_RECEIPT_ID/verify.

4. Check It Yourself — No Trust Required

Every receipt reproduces from public information: the content digest (RFC 8785 canonical JSON), the hash-chain head, and an ed25519 signature you verify against our published key set. Point the script below at the receipt you hold — python3 verify_receipt.py my-receipt.json — or save it as specimen-receipt.json and run the script with no argument at all. Either way you run it unchanged. It finds the signed envelope wherever your receipt carries it, so one script checks every shape we serve: no edits, no field remapping. Air-gapped, or pinning keys yourself? Save the key set once (curl -sSo pinned-jwks.json https://api.bluefoxedge.ai/.well-known/jwks.json) and add --jwks pinned-jwks.json — the whole check then runs fully offline, fetching nothing.

Nothing to install. The script is Python 3.8+ standard library only — it carries its own RFC 8785 canonicaliser and its own RFC 8032 Ed25519 verifier, so it runs on a locked-down box, in a hardened CI runner, or inside an agent sandbox where pip is not available. If the cryptography package happens to be installed it is used as a faster path to the same answer over the same bytes. Every failure is one sentence and a non-zero exit — never a stack trace.

Paid with x402 and no API key? On the notarize door (POST /v1/notarize/hash) the mint response body IS your receipt, and it is the only copy a keyless payer holds — the signed envelope arrives under data.receipt. The verification doors (step 2, step 7) work differently for a keyless payer: you receive the verdict unsigned and no receipt is made — a receipt on those doors needs an API key. Save a notarize receipt as you receive it: … > specimen-receipt.json. From the step-3 read API the envelope arrives under data.envelope instead; the same script eats both.

No account at all? Fetch a complete published receipt and check that: curl -O https://www.bluefoxedge.ai/specimen-receipt.json — the same script verifies it unchanged.

Pin the bytes before you run them. Fetch the script and check it against its published digest — the checksum is served beside it, in shasum -c format, so it verifies with no hand-editing:

curl -sS -O https://api.bluefoxedge.ai/verify_receipt.py
curl -sS https://api.bluefoxedge.ai/verify_receipt.py.sha256 | shasum -a 256 -c -
import base64, hashlib, json, re, sys, urllib.request

# DEPENDENCIES: none. Python 3.8+ standard library only. If the third-party
# cryptography package happens to be installed, its Ed25519 verifier is used;
# otherwise the self-contained RFC 8032 verifier further down checks the same
# bytes and reaches the same answer. Nothing here needs pip.
#
#     python3 verify_receipt.py                    checks specimen-receipt.json
#     python3 verify_receipt.py my-receipt.json     checks the file you name
#     python3 verify_receipt.py --jwks saved-keys.json my-receipt.json
#                                    checks fully offline against keys you saved
#     python3 verify_receipt.py --jwks saved-keys.json --bind-record my-record.json my-receipt.json
#                                    also checks that the receipt names YOUR record
#
# Exit 0 means the check passed. Any non-zero exit means it did not, and the
# reason is one sentence -- never a stack trace.
#
# TWO KEY FAMILIES, AND THEY NEVER CROSS. Receipts are signed by the receipt
# key. The transparency log signs its checkpoints with a DIFFERENT key. Both are
# published in the same key set, and every entry declares which family it
# belongs to in a bfx:purpose member. DO NOT SELECT A KEY BY POSITION: keys[0]
# is the receipt key, so a checker that indexes the list instead of reading the
# label is one reordering away from checking the wrong thing. This file checks a
# RECEIPT, so it requires a purpose of "receipt" and refuses a receipt that
# names the log's key. Checkpoints are the other script's job, and it makes the
# mirror-image check: https://api.bluefoxedge.ai/verify_inclusion.py
#
# BINDING A RECEIPT TO A RECORD (--bind-record). The record is a JSON object
# you hold -- your own account of one tool call, as you presented it. Its
# RFC 8785 canonical form is hashed, and the receipt's source row must name
# exactly that digest. The retained presentation, when the tier kept one, must
# agree with the record. The receipt's own verdict word is printed from the
# file, never judged here: a pass says the receipt names your record, and the
# record stays the caller's own account of what happened.

# Pin the key set out of band -- never read a jwks_url out of the receipt.
# That field is unsigned: a forger can point it at keys they control, and a
# checker that follows it will bless the forgery. The explicit User-Agent is
# deliberate too: some edge firewalls refuse the default urllib signature.
#
# --jwks moves the pin FURTHER out of band, never less: name a key-set file
# you saved earlier and the whole check runs offline against those pinned
# bytes -- nothing is fetched at all -- or name an https address you trust
# and keys are fetched from there instead of the default below. Either way
# the choice is the operator's hand, never the receipt's: no field in the
# file being judged can pick its own judge.
JWKS_URL = "https://api.bluefoxedge.ai/.well-known/jwks.json"
PURPOSE_CLAIM = "bfx:purpose"
RECEIPT_PURPOSE = "receipt"
# Read-side, both IANA JOSE spellings, forever: "EdDSA" is what the key set
# publishes today and "Ed25519" is its fully-specified successor (RFC 9864).
ACCEPTED_ED25519_ALG_SPELLINGS = ("Ed25519", "EdDSA")


def not_implemented_here(sentence):
    # A refusal about THIS CHECKER, never a result about the receipt: the
    # input names an algorithm this build does not implement. One sentence,
    # exit 3 (the JS twin's NotImplementedHere), so tooling can tell
    # "checked and failed" from "cannot judge here".
    sys.stderr.write(sentence + "\n")
    raise SystemExit(3)

def unb64url(s):
    return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))

def b64url(raw):
    return base64.urlsafe_b64encode(raw).decode("ascii").rstrip("=")

def sha256s(raw):
    return "sha256:" + hashlib.sha256(raw).hexdigest()

# RFC 8785 (JCS) canonical JSON, standard library only.
#
# Reproduced from BRIDIE's construction -- a stranger who, sent at this estate
# on 2026-08-15 under a no-install rule, rebuilt this in 25 lines of stdlib and
# got output BYTE-IDENTICAL to the rfc8785 package on the published specimen
# (1,324 bytes from both). Her point stands and is the reason this file no
# longer asks you to install anything: the spec is complete enough to
# reimplement, so the checker should not need a package to prove it.
#
# Three rules do all the work. Object keys sort by UTF-16 code unit -- which is
# what encoding each key to UTF-16 big-endian and comparing those bytes gives
# you, surrogate pairs included. There is no insignificant whitespace. And a
# number that is integral is spelled without its fraction: JCS spells 0.0 as 0,
# and one character breaks a hash. That trap is live in the flagship artifact --
# the specimen's confidence_score is 0.0.
#
# The number domain this accepts is the one the signer itself enforces before
# hashing (finite floats, integers within the JCS safe-integer range). Outside
# that, and in the narrow band where a shortest-round-trip float would have to
# be spelled with an exponent, this REFUSES rather than guessing -- a wrong
# canonical form is a wrong hash, and a wrong hash silently accuses an honest
# receipt. Reject, never normalise.
def jcs(value):
    if value is True:
        return b"true"
    if value is False:
        return b"false"
    if value is None:
        return b"null"
    if isinstance(value, str):
        try:
            return json.dumps(value, ensure_ascii=False,
                              separators=(",", ":")).encode("utf-8")
        except UnicodeEncodeError:
            raise SystemExit("this receipt carries text that is not encodable as "
                             "UTF-8 (a lone surrogate) -- it cannot be canonicalised")
    if isinstance(value, int):
        if abs(value) > 2 ** 53 - 1:
            raise SystemExit("this receipt carries an integer outside the JCS "
                             "safe-integer range -- refusing rather than hashing a "
                             "value two implementations would spell differently")
        return repr(value).encode("ascii")
    if isinstance(value, float):
        if value != value or value in (float("inf"), float("-inf")):
            raise SystemExit("this receipt carries a non-finite number, which has "
                             "no JSON canonical form")
        text = repr(value)
        if "e" in text or "E" in text:
            raise SystemExit("this receipt carries a number whose canonical "
                             "spelling needs an exponent, which this stdlib "
                             "canonicaliser does not attempt -- refusing rather "
                             "than risking a wrong hash")
        if value.is_integer():
            return repr(int(value)).encode("ascii")
        return text.encode("ascii")
    if isinstance(value, list):
        return b"[" + b",".join(jcs(item) for item in value) + b"]"
    if isinstance(value, dict):
        pairs = []
        for key in sorted(value, key=lambda k: k.encode("utf-16-be")):
            if not isinstance(key, str):
                raise SystemExit("this receipt has a non-text object key -- it is "
                                 "not canonicalisable JSON")
            pairs.append(jcs(key) + b":" + jcs(value[key]))
        return b"{" + b",".join(pairs) + b"}"
    raise SystemExit("this receipt carries a value of a kind JSON has no "
                     "canonical form for -- it is not a receipt this recipe checks")

def copies(node, key):  # every value a receipt's own subtree carries under key
    if isinstance(node, dict):
        for k, v in node.items():
            if k == key:
                yield v
            yield from copies(v, key)
    elif isinstance(node, list):
        for item in node:
            yield from copies(item, key)

# The file to check: the one you name, or the published specimen if you name
# nothing. Every way this can go wrong below is a sentence and a non-zero exit,
# because handing a stranger a traceback for a missing file is not a verdict --
# it is the vendor's stack frames in place of an answer. Flag parsing is spelled
# out rather than imported: argparse prints its own usage paragraphs and exits 2,
# and this file's contract is one sentence and its own exit, every time.
jwks_source = None
record_path = None
names = []
args = list(sys.argv[1:])
while args:
    arg = args.pop(0)
    if arg == "--jwks" or arg.startswith("--jwks="):
        if jwks_source is not None:
            raise SystemExit("--jwks is named twice -- one verdict means one "
                             "pinned key set, so name exactly one")
        if arg == "--jwks":
            value = args.pop(0) if args else ""
        else:
            value = arg[len("--jwks="):]
        if not value:
            raise SystemExit("--jwks needs a value -- the path of a key-set "
                             "file you saved earlier, or an https address to "
                             "fetch the keys from")
        jwks_source = value
    elif arg == "--bind-record" or arg.startswith("--bind-record="):
        if record_path is not None:
            raise SystemExit("--bind-record is named twice -- one verdict means one "
                             "record, so name exactly one")
        if arg == "--bind-record":
            value = args.pop(0) if args else ""
        else:
            value = arg[len("--bind-record="):]
        if not value:
            raise SystemExit("--bind-record needs a value -- the path of the record "
                             "file this receipt is meant to name")
        record_path = value
    else:
        names.append(arg)
if len(names) > 1:
    raise SystemExit("usage: python3 verify_receipt.py [PATH-TO-RECEIPT.json] -- "
                     "one file at a time, so one verdict means one receipt")
path = names[0] if names else "specimen-receipt.json"
try:
    with open(path, encoding="utf-8") as handle:
        specimen = json.load(handle)
except FileNotFoundError:
    raise SystemExit("there is no file at " + path + " -- name the receipt you "
                     "want checked, or save it as specimen-receipt.json and pass "
                     "nothing")
except IsADirectoryError:
    raise SystemExit(path + " is a directory, not a receipt file")
except PermissionError:
    raise SystemExit(path + " cannot be read (permission denied)")
except UnicodeDecodeError:
    raise SystemExit(path + " is not UTF-8 text, so it is not a receipt this "
                     "recipe can read")
except ValueError as exc:
    raise SystemExit(path + " is not valid JSON, so no receipt can be read "
                     "from it")
except OSError as exc:
    raise SystemExit(path + " could not be read (" + str(exc) + ")")
if not isinstance(specimen, dict):
    raise SystemExit(path + " holds a " + type(specimen).__name__ + ", not a JSON "
                     "object -- a receipt is an object")

# The record to bind (--bind-record): read through the same door as the receipt,
# right behind it, so a record that cannot be read is refused before anything
# in the receipt is looked at. It is checked against the envelope only after
# every signed field has held, further down.
record = None
if record_path is not None:
    try:
        with open(record_path, encoding="utf-8") as handle:
            record = json.load(handle)
    except FileNotFoundError:
        raise SystemExit("there is no record file at " + record_path + " -- name the "
                         "record this receipt is meant to bind")
    except IsADirectoryError:
        raise SystemExit(record_path + " is a directory, not a record file")
    except PermissionError:
        raise SystemExit(record_path + " cannot be read (permission denied)")
    except UnicodeDecodeError:
        raise SystemExit(record_path + " is not UTF-8 text, so it is not a record this "
                         "recipe can read")
    except OSError:
        raise SystemExit(record_path + " could not be read, so no record can be bound")
    except ValueError:
        raise SystemExit(record_path + " is not valid JSON, so no record can be read "
                         "from it")
    if not isinstance(record, dict):
        raise SystemExit(record_path + " holds a " + type(record).__name__ + ", not a "
                         "JSON object -- a record is an object")

# The signed surface is the envelope: the one dict that carries the chain
# block. Its home differs by door -- data.receipt in an x402 mint response,
# data.envelope in a read-API response or the published specimen, one per
# entry of an export bundle -- so this finds it instead of indexing a path.
#
# WHICH envelope, when a file offers more than one, is a security question,
# not a convenience one. Every door here answers with a "data" mapping and
# puts the envelope inside it, so if the file HAS that mapping, ITS slot
# decides and nothing found elsewhere in the file can speak for it. That is
# what stops a doctored receipt at the slot you read from being excused by a
# genuine envelope tucked somewhere else in the same file. Only a file with no
# such mapping -- an export bundle, or something you assembled yourself --
# falls back to searching, and then you are reading whatever the search found:
# run this once per entry and read each answer. Either way a pass is a
# statement about ONE envelope, never about the file. And a file that HAS a
# data block but names no receipt in it is refused outright rather than
# searched, because that is not a shape any of these doors answers with.
#
# Both routes also return the dict CARRYING the envelope -- data, or the entry
# an envelope was found under -- because that is where the unsigned convenience
# copies live, and it is the fence that keeps the copy check inside ONE receipt,
# so a two-receipt bundle never compares entry A's hashes against entry B's.
# An envelope found directly inside a list has no carrier to name, and then the
# envelope fences itself: only its own copies are checked.
def signed(node):
    chain = node.get("chain") if isinstance(node, dict) else None
    return isinstance(chain, dict) and "signature" in chain

def slot_in_data(doc):
    data = doc.get("data") if isinstance(doc, dict) else None
    if not isinstance(data, dict):
        return None                       # no data mapping: search, below
    named = [s for s in ("receipt", "envelope") if s in data]
    if not named:
        # A "data" mapping is how these doors answer, so a file that has one
        # and names no receipt inside it is not a receipt response -- and the
        # rest of the file does not get to volunteer a substitute.
        raise SystemExit("this file has a data block with no receipt in it -- "
                         "refusing to hunt elsewhere for something to check")
    # From here the file HAS named a receipt, so that name binds and the
    # search never runs. Naming one and then failing to be one is a refusal,
    # not a licence to go looking for something else in the file to bless.
    if len(named) > 1:
        raise SystemExit("this file fills both data.receipt and data.envelope "
                         "-- name one receipt, or check them one at a time")
    slot = named[0]
    if not signed(data[slot]):
        raise SystemExit("data." + slot + " is not a signed envelope -- "
                         "refusing to check something else in its place")
    return data, data[slot]               # data is the carrier, as below

def find_envelope(node, parent=None):
    if isinstance(node, dict):
        if signed(node):
            return parent, node
        for child in node.values():
            hit = find_envelope(child, node)
            if hit is not None:
                return hit
    elif isinstance(node, list):
        for child in node:
            hit = find_envelope(child, None)
            if hit is not None:
                return hit
    return None

found = slot_in_data(specimen) or find_envelope(specimen)
if found is None:
    raise SystemExit("no signed envelope found -- not a signed receipt (yet?)")
scope, envelope = found
if scope is None:
    scope = envelope
chain = envelope["chain"]

# Everything the recipe is about to read, present AND of the right kind
# before it is read. A receipt missing one of these -- or carrying null or a
# number where text belongs -- is refused in a sentence, never with a
# traceback: handing a stranger a stack trace is the failure this whole
# recipe was rewritten to stop. (key_id must only be PRESENT: a keyless
# receipt carries it as null and reaches its own honest exit further down.)
def needs(field, home, text=True):
    if field not in home:
        raise SystemExit("this envelope has no " + field + " -- it is not a "
                         "receipt of the shape this recipe checks")
    if text and not isinstance(home[field], str):
        raise SystemExit("this envelope's " + field + " is not text -- it is "
                         "not a receipt of the shape this recipe checks")

needs("chain_prev", chain)
needs("key_id", chain, text=False)
needs("schema_version", envelope)

# 1. content_digest recomputes from the envelope's own bytes: sha256 over the
#    RFC 8785 canonical form of the envelope with the whole chain block
#    removed. JCS, not json.dumps -- JCS spells 0.0 as 0, and one character
#    breaks a hash.
body = {k: v for k, v in envelope.items() if k != "chain"}
digest = sha256s(jcs(body))

# 2. chain_self recomputes: sha256 over digest|chain_prev|schema_version,
#    joined with literal pipes, hashed as UTF-8. chain_prev is the previous
#    receipt's chain_self, or the literal "GENESIS" at a chain head.
head = sha256s("|".join(
    (digest, chain["chain_prev"], body["schema_version"])).encode("utf-8"))

# 3. Every copy of the two hashes in THIS receipt's subtree agrees with the
#    recomputation -- the chain block's and the top-level mirrors' alike.
#    Presence is checked before agreement: all() is True over an empty
#    iterator, so a receipt carrying NO copy of a hash would otherwise sail
#    through this step without it ever being compared to anything. A detected
#    forgery is a verdict, so it exits in a sentence, never a stack trace.
for key, want in (("content_digest", digest), ("chain_self", head)):
    carried = list(copies(scope, key))
    if not carried:
        raise SystemExit(key + " is absent -- there is nothing here to check")
    if not all(got == want for got in carried):
        raise SystemExit(
            key + " does not recompute from the receipt's own bytes")

if not chain.get("signature"):
    raise SystemExit("keyless receipt: steps 1-3 hold, but with key_id and "
                     "signature null there is no signature to check")

# 4. The signing key is published, and its name is a derived fact:
#    kid = sha256 of the raw 32-byte Ed25519 public key. The key is selected by
#    kid and then checked against its declared family -- selecting by kid alone
#    would let a checkpoint key verify a receipt if the two ever crossed, and
#    the whole reason there are two keys is that they must not.
#
#    With --jwks the same selection runs against the keys YOU pinned. A saved
#    file is read here with no network at all; an https address you named is
#    fetched in place of the default. The kid check below is what makes a
#    pinned file trustworthy to hold: the key's name is derived from the key's
#    own bytes, so a swapped key cannot keep its old name.
key_set_word = "published" if jwks_source is None else "pinned"
if jwks_source is None or jwks_source.startswith("https://"):
    key_set_url = JWKS_URL if jwks_source is None else jwks_source
    req = urllib.request.Request(key_set_url, headers={"User-Agent": "bluefox-verify/1"})
    try:
        jwks = json.load(urllib.request.urlopen(req, timeout=30))
    except Exception as exc:
        raise SystemExit("the " + key_set_word + " key set at " + key_set_url +
                         " could not be "
                         "fetched (" + type(exc).__name__ + ") -- this checker will "
                         "not fall back to any address inside the receipt, so it "
                         "stops here")
elif jwks_source.startswith("http://"):
    raise SystemExit("--jwks " + jwks_source + " is plaintext http -- keys "
                     "fetched without TLS can be swapped in flight, so save the "
                     "key set to a file and name that instead, or use https")
else:
    try:
        with open(jwks_source, encoding="utf-8") as handle:
            jwks = json.load(handle)
    except FileNotFoundError:
        raise SystemExit("there is no key-set file at " + jwks_source + " -- "
                         "save the published keys first (curl -sSo "
                         "pinned-jwks.json " + JWKS_URL + ") and name that file")
    except IsADirectoryError:
        raise SystemExit(jwks_source + " is a directory, not a key-set file")
    except PermissionError:
        raise SystemExit(jwks_source + " cannot be read (permission denied)")
    except UnicodeDecodeError:
        raise SystemExit(jwks_source + " is not UTF-8 text, so it is not a key "
                         "set this recipe can read")
    except ValueError:
        raise SystemExit(jwks_source + " is not valid JSON, so no key can be "
                         "pinned from it")
    except OSError:
        raise SystemExit(jwks_source + " could not be read, so no key can be "
                         "pinned from it")
if not isinstance(jwks, dict) or not isinstance(jwks.get("keys"), list):
    raise SystemExit("the " + key_set_word + " key set has no keys array, so no "
                     "key can be pinned")
key = next((k for k in jwks["keys"]
            if isinstance(k, dict) and k.get("kid") == chain["key_id"]), None)
if key is None:
    if jwks_source is None:
        raise SystemExit("key_id is not in the published key set")
    raise SystemExit("key_id is not in the pinned key set at " + jwks_source +
                     " -- if that copy predates this receipt, refresh it from " +
                     JWKS_URL + " and pin the new file")
purpose = key.get(PURPOSE_CLAIM)
# ABSENT is tolerated on purpose; only a POSITIVE wrong designation refuses.
# The published set gained bfx:purpose at the 2026-08-18 FIRE, so every key-set
# file pinned before that day lacks the member -- and the --jwks door exists
# precisely for files saved earlier. Same philosophy as the settlement lane's
# network guard: refuse a wrong answer, never punish an absent one. (H98 read
# the fail-closed suggestion and refuted it against the repo's own genuine
# 2026-08-08 pinned fixture; a stricter world needs a worded tolerance-sunset.)
if isinstance(purpose, str) and purpose != RECEIPT_PURPOSE:
    raise SystemExit("this receipt names the " + key_set_word + " key " + chain["key_id"] +
                     ", which is designated " + repr(purpose) + " and not a "
                     "receipt signer -- the two key families never cross, so "
                     "this is refused rather than verified")
# The algorithm is READ before it is assumed. An entry that POSITIVELY
# declares something other than Ed25519 (a foreign kty like AKP, a foreign
# crv, or an alg outside the two Ed25519 spellings) is a gap in THIS CHECKER,
# not a defect in the receipt -- absent members stay tolerated, exactly like
# the purpose label above.
entry_alg, entry_kty, entry_crv = key.get("alg"), key.get("kty"), key.get("crv")
foreign_alg = ""
if isinstance(entry_alg, str) and entry_alg not in ACCEPTED_ED25519_ALG_SPELLINGS:
    foreign_alg = entry_alg
elif isinstance(entry_kty, str) and entry_kty != "OKP":
    foreign_alg = "a " + entry_kty + "-family key"
elif isinstance(entry_crv, str) and entry_crv != "Ed25519":
    foreign_alg = "curve " + entry_crv
if foreign_alg:
    not_implemented_here("this receipt names the " + key_set_word + " key " + chain["key_id"] +
                         ", whose key set entry declares " + foreign_alg + " -- an "
                         "algorithm this checker does not implement; refused rather "
                         "than assumed: nothing here says the receipt is bad, only "
                         "that this build cannot judge it, and a checker that "
                         "implements that algorithm can")
# The declared-algorithm cross-binding: an OPTIONAL chain.sig_alg, when
# present, must agree with the resolved key set entry. By here the entry is
# Ed25519-family, so a foreign sig_alg is a DISAGREEMENT in the file -- a
# refusal about the receipt, not a capability gap.
if "sig_alg" in chain and not isinstance(chain["sig_alg"], str):
    raise SystemExit("this envelope's chain.sig_alg is not text -- it is not a "
                     "receipt of the shape this recipe checks")
if isinstance(chain.get("sig_alg"), str) and chain["sig_alg"] not in ACCEPTED_ED25519_ALG_SPELLINGS:
    raise SystemExit("this receipt declares sig_alg " + repr(chain["sig_alg"]) + " but its "
                     "key set entry is an Ed25519 key -- the declared algorithm and the "
                     "published key disagree, so this is refused rather than verified")
raw_key = unb64url(key["x"])
if hashlib.sha256(raw_key).hexdigest() != chain["key_id"]:
    raise SystemExit("kid is not sha256 of the raw public key")
# The length is a declaration too: raw bytes that are not 32 cannot be an
# Ed25519 key, and pushing them into the crypto layer would surface as the
# step-6 tampering sentence -- confidently wrong about a receipt this build
# simply cannot judge.
if len(raw_key) != 32:
    not_implemented_here("the resolved key is " + str(len(raw_key)) + " raw bytes, not a "
                         "32-byte Ed25519 key -- an algorithm this checker does not "
                         "implement; refused rather than assumed: nothing here says "
                         "the receipt is bad, only that this build cannot judge it")

# 5. The carried signature string is the one canonical spelling of its bytes
#    (base64url, padding stripped) -- flip even a slack bit and this fails.
needs("signature", chain)
try:
    sig = unb64url(chain["signature"])
except Exception:
    raise SystemExit("this envelope's signature is not base64url text -- it "
                     "is not a receipt of the shape this recipe checks")
if b64url(sig) != chain["signature"]:
    raise SystemExit("signature encoding is not canonical")

# Ed25519 verification (RFC 8032), self-contained, so this file runs on a bare
# Python. You never need to read this block: it is the arithmetic, not the
# recipe. It is here only so that "no install required" is literally true, and
# it is skipped entirely when the cryptography package is present.
P = 2 ** 255 - 19
L = 2 ** 252 + 27742317777372353535851937790883648493

def inv(x):
    return pow(x, P - 2, P)

D = (-121665 * inv(121666)) % P
SQRT_M1 = pow(2, (P - 1) // 4, P)

def x_recover(y):
    xx = ((y * y - 1) * inv(D * y * y + 1)) % P
    x = pow(xx, (P + 3) // 8, P)
    if (x * x - xx) % P != 0:
        x = (x * SQRT_M1) % P
    if (x * x - xx) % P != 0:
        return None
    return P - x if x % 2 != 0 else x

def point_add(pt1, pt2):
    x1, y1 = pt1
    x2, y2 = pt2
    prod = (D * x1 * x2 * y1 * y2) % P
    return (((x1 * y2 + x2 * y1) * inv(1 + prod)) % P,
            ((y1 * y2 + x1 * x2) * inv(1 - prod)) % P)

def scalar_mult(pt, scalar):
    acc = (0, 1)
    while scalar > 0:
        if scalar & 1:
            acc = point_add(acc, pt)
        pt = point_add(pt, pt)
        scalar >>= 1
    return acc

BASE_Y = (4 * inv(5)) % P
BASE = (x_recover(BASE_Y), BASE_Y)

def on_curve(pt):
    x, y = pt
    return (-x * x + y * y - 1 - D * x * x * y * y) % P == 0

def decode_point(blob):
    value = int.from_bytes(blob, "little")
    y = value & ((1 << 255) - 1)
    sign = value >> 255
    if y >= P:
        return None
    x = x_recover(y)
    if x is None:
        return None
    if x & 1 != sign:
        x = P - x
    pt = (x, y)
    return pt if on_curve(pt) else None

def ed25519_verify_pure(public_raw, signature, message):
    if len(public_raw) != 32 or len(signature) != 64:
        return False
    point_a = decode_point(public_raw)
    point_r = decode_point(signature[:32])
    if point_a is None or point_r is None:
        return False
    scalar_s = int.from_bytes(signature[32:], "little")
    if scalar_s >= L:
        return False
    challenge = int.from_bytes(
        hashlib.sha512(signature[:32] + public_raw + message).digest(),
        "little") % L
    return scalar_mult(BASE, scalar_s) == point_add(
        point_r, scalar_mult(point_a, challenge))

def ed25519_verify(public_raw, signature, message):
    try:
        from cryptography.hazmat.primitives.asymmetric.ed25519 import (
            Ed25519PublicKey)
    except ImportError:
        return ed25519_verify_pure(public_raw, signature, message)
    try:
        Ed25519PublicKey.from_public_bytes(public_raw).verify(signature, message)
        return True
    except Exception:
        return False

# 6. The Ed25519 signature verifies over the RECOMPUTED chain head -- so the
#    signature commits to every envelope byte hashed in step 1, not merely to
#    a hash string the file happened to carry. A failure HERE is the verdict
#    this whole recipe exists to deliver, so it too is a sentence.
if not ed25519_verify(raw_key, sig, head.encode("utf-8")):
    raise SystemExit("the signature does not verify over the recomputed chain "
                     "head -- these are not the bytes the published key signed")

# 7. Unsigned convenience mirrors: the dict carrying the envelope repeats some
#    signed fields for readers, and nothing above checked those copies -- they
#    sit outside the signature. Mirrors spell the exact bytes of the envelope's
#    values (produced_at included: same Z-form, same instant), so a copy that
#    disagrees is a REFUSAL, not a warning. The signature held -- but the file
#    in your hand is showing a reader different bytes than the ones it signed,
#    and a disagreeing mirror is exactly how a doctored copy rides a check
#    that reads only the envelope. A warning here asked you to notice what
#    this script exists to notice for you, so it stops instead.
if scope is not envelope:
    # chain_prev rides along (2E116, S116 -- ll116's L5): it is the one signed
    # input to the chain head that steps 1-3 never recompute (a link, not a
    # hash), so a top-level copy of it was the one mirror nothing above
    # compared -- a one-byte edit of it passed while item 7 of the README said
    # otherwise. Same rule, same sentence, one more key.
    mirrored = list(body.items()) + [("chain_prev", chain["chain_prev"])]
    for key, value in mirrored:
        if key in scope and scope[key] != value:
            raise SystemExit("unsigned top-level " + key + " does not match the "
                             "signed envelope's " + key + " -- the signature held, "
                             "but this file presents altered bytes where a reader "
                             "reads, and that is a tampered file, not a footnote")

# BINDING (--bind-record). The record is hashed with the same canonicaliser the
# envelope was, and the receipt's first source row must carry that digest --
# that is the bind: a digest the caller presented, named by a signed row. The
# rest reads the receipt's OWN words back: the source row's shape says this was
# a presented digest, the self-disclosure fields say what kind of receipt it
# calls itself, the retained presentation (when the tier kept one) must agree
# with the record, and the verdict word is copied out of the file. Nothing is
# graded here. It runs only when a record was named, after every signed field
# above has held, and each refusal is one sentence.
def scrub(text):  # control characters become "?", every printable character stays
    return "".join("?" if ord(ch) < 32 or ord(ch) == 127 else ch for ch in text)

def show(value):  # a quoted value: text single-quoted (backslash and quote escaped,
    if isinstance(value, str):  # the one spelling both twins use), anything else in JCS form
        backslash = chr(92)
        return ("'" + value.replace(backslash, backslash + backslash)
                .replace("'", backslash + "'") + "'")
    return jcs(value).decode("utf-8")

# The profile's pinned six-key meta, derived from the record -- what a tier
# that keeps meta stored beside the digest. Every key is tested for presence
# before it is read, so a record of another shape is refused in a sentence.
def meta_for(record):
    def lacks(key):
        raise SystemExit("the record at " + record_path + " is not a tool-call record "
                         "this recipe can bind -- it lacks " + key)
    def text(value):  # a count spelled the way both twins spell it: 3 and 3.0 both read 3
        return value if isinstance(value, str) else jcs(value).decode("utf-8")
    if "profile" not in record:
        lacks("profile")
    if "session" not in record:
        lacks("session")
    session = record["session"]
    if not isinstance(session, dict) or "ref" not in session:
        lacks("session.ref")
    if "kind" in record and record["kind"] == "session-close":
        if "final_count" not in session:
            lacks("session.final_count")
        return {"profile": record["profile"], "kind": "session-close", "tool": "-",
                "scheme": "none", "seq": text(session["final_count"]),
                "session": session["ref"]}
    tool = record["tool"] if "tool" in record else None
    if not isinstance(tool, dict) or "name" not in tool:
        lacks("tool.name")
    if "seq" not in session:
        lacks("session.seq")
    ident = record["identity"] if "identity" in record else None
    if isinstance(ident, dict) and "scheme" not in ident:
        lacks("identity.scheme")
    return {"profile": record["profile"], "kind": "tool-call", "tool": tool["name"],
            "scheme": ident["scheme"] if isinstance(ident, dict) else "none",
            "seq": text(session["seq"]), "session": session["ref"]}

if record_path is not None:
    record_digest = hashlib.sha256(jcs(record)).hexdigest()
    sources = envelope.get("sources")
    if not (isinstance(sources, list) and sources and isinstance(sources[0], dict)):
        raise SystemExit("this envelope has no source row -- there is nothing for a "
                         "record to bind to")
    src0 = sources[0]
    if "source_bytes_digest" not in src0 or not isinstance(src0["source_bytes_digest"], str):
        raise SystemExit("the source row binds nothing readable -- source_bytes_digest "
                         "is not text")
    if src0["source_bytes_digest"] != "sha256:" + record_digest:
        raise SystemExit("this receipt does not name the record at " + record_path +
                         " -- the record digests to sha256:" + record_digest +
                         " and the receipt's source row binds " +
                         scrub(src0["source_bytes_digest"]))
    for field, expected in (("hash_alg", "sha256"),
                            ("extraction_method", "client_submission"),
                            ("asserted_by", "as-stated-by-caller")):
        value = src0[field] if field in src0 else None
        if value != expected:
            raise SystemExit("the bound source row's " + field + " is " + show(value) +
                             ", not " + show(expected) + " -- this is not a "
                             "presented-digest receipt for that record")
    if ("relevant_text" in src0 and src0["relevant_text"] is not None
            and src0["relevant_text"] != ""):
        raise SystemExit("the bound source row retains text -- a presented digest "
                         "carries none, so this is not a presented-digest receipt for "
                         "that record")
    for field, expected in (("not_an_attestation", True),
                            ("assertion_type", "reliance"),
                            ("edge_role", "evidence-layer")):
        value = envelope[field] if field in envelope else None
        agrees = value is True if expected is True else value == expected
        if not agrees:
            raise SystemExit("this receipt's self-disclosure does not read as a "
                             "reliance receipt -- " + field + " is " + show(value))
    details = envelope["details"] if "details" in envelope else None
    if not isinstance(details, dict):
        details = {}
    presentation = details["presentation"] if "presentation" in details else None
    presented = isinstance(presentation, dict)
    if not presented:
        presentation = {}
    kept = presentation["value"] if "value" in presentation else None
    if not isinstance(kept, dict):
        kept = {}
    retained = kept["meta"] if "meta" in kept else None
    if not isinstance(retained, dict):
        retained = {}
    expected_meta = meta_for(record)
    if presented:
        kept_hash = kept["hash"] if "hash" in kept else None
        if kept_hash != record_digest:
            raise SystemExit("the retained presentation names a different digest than "
                             "the record -- " + show(kept_hash) + " vs " + record_digest)
        by = presentation["asserted_by"] if "asserted_by" in presentation else None
        if by != "as-stated-by-caller":
            raise SystemExit("the retained presentation is not asserted by the caller "
                             "-- asserted_by is " + show(by))
        if retained and jcs(retained) != jcs(expected_meta):
            raise SystemExit("the retained meta does not agree with the record -- "
                             "retained " + jcs(retained).decode("utf-8") +
                             " vs expected " + jcs(expected_meta).decode("utf-8"))
    produced_at = envelope["produced_at"] if "produced_at" in envelope else None
    if not isinstance(produced_at, str) or not re.fullmatch(
            "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$", produced_at):
        raise SystemExit("this receipt's produced_at is not an RFC 3339 UTC instant -- " +
                         show(produced_at))
    if presented and retained:
        variant = " -- the retained meta agrees with the record"
    elif presented:
        variant = " -- the retained presentation carries no meta, so the digest alone binds"
    else:
        variant = (" -- the retained presentation is absent, so the digest alone binds "
                   "via the source row")
    print("the record binds: " + scrub(record_path) + " digests to sha256:" +
          record_digest + ", the receipt's source row names that digest, and the "
          "receipt's own verdict word is " + show(envelope.get("verdict")) + variant)
    print("the record is the caller's own account of the call: this run shows the "
          "receipt names it, not that the call happened as written")

# WHAT THIS RUN DID NOT CHECK -- printed on every successful run, which is what
# this file's README has always promised and what, until now, only a source
# comment said. One logical line per member, in the order below, always ALL of
# them: the count is the length of this list and is written nowhere as a
# literal, so a slug added here is a slug printed. The source of record is
# RECEIPT_CHECK_UNSUPPORTED_PATHS / RECEIPT_CHECK_DISCLOSURES in app/models.py
# and a test pins this copy against it.
#
# IT PRINTS BEFORE THE VERDICT, deliberately: the verdict lands last where a
# reader looks for it, and a REFUSAL never reaches this point at all -- a file
# that failed to be checked must not emit the vocabulary of a file that was.
NOT_VERIFIED = [
    ("verdict_recompute",
     "It does not re-run any verdict"),
    ("underlying_claim_truth",
     "Proof of reliance, never proof of truth"),
    ("transparency_log_inclusion",
     "It does not check transparency-log inclusion; that check is /verify_inclusion.py, or"
     " /verify_receipt.js handed the inclusion proof (--inclusion)"),
    ("external_witness_or_anchor",
     "no cosignature and no external anchor were checked; trust in the log key"
     " is trust in BlueFox until a witness lifts it"),
    ("source_url_resolution",
     "The source's URL is not part of the durable envelope"),
    ("raw_source_bytes",
     "each receipt names its sources by content digests"),
    ("revocation_status",
     "Dispute/revocation status is not covered"),
    ("key_set_provenance",
     "the key set was {key_set_word}, taken from {key_set_source}; nothing"
     " here proves those keys are BlueFox's current published set"),
    ("split_view_or_equivocation",
     "one file cannot detect a split view; that needs two independently"
     " obtained checkpoints and /verify_consistency.py"),
    ("foreign_signature_relay",
     "a foreign signature BlueFox checked at mint time was checked against a"
     " key outside its published key set, and this run does not re-check it"),
]
key_set_source_raw = JWKS_URL if jwks_source is None else jwks_source
# ONE LINE PER SLUG MEANS ONE LINE, and the key-set path is the only thing in
# this block a stranger chose. A filename may legally carry a newline or an
# escape, and interpolated raw it could ADD a scope line, or spoof the pass
# line, on a run that SUCCEEDED -- the one place this output is read as
# evidence. Control characters become "?"; every printable character, non-ASCII
# included, is shown exactly as given, because a path you cannot recognise is
# not a disclosure.
key_set_source = "".join(
    "?" if ord(ch) < 32 or ord(ch) == 127 else ch for ch in key_set_source_raw)
for slug, sentence in NOT_VERIFIED:
    # ORDER MATTERS: the word first, the SOURCE last. Replacement re-scans what
    # it has written, and the source is the path you named on the command line
    # -- so it goes in last, where nothing can expand anything it contains.
    sentence = sentence.replace("{key_set_word}", key_set_word)
    sentence = sentence.replace("{key_set_source}", key_set_source)
    print("NOT VERIFIED by this run -- " + slug.upper() + ": " + sentence + ".")

# THE OBSERVATION/0 LINE (P117, S117/D015; the listening lane's receipts, U116 spec
# section 13 row 12). When the retained presentation says the presented digest
# names an OBSERVATION RECORD -- meta.profile "observation/<n>" and meta.kind
# "observation", the /0 path's own statement about what the digest names -- one
# more line prints on the pass path, before the register line: the record's
# profile and the receipt's own grade word, both READ from the file and never
# judged here, and where to read what such a receipt does and does not prove:
# the limits register's row for observation/0, rendered verbatim from the spec.
# A receipt without that meta prints nothing new; a refusal never reaches this
# point. Both twins print the identical sentence, byte for byte.
def observation_zero_meta(envelope):
    details = envelope["details"] if "details" in envelope else None
    presentation = (details["presentation"]
                    if isinstance(details, dict) and "presentation" in details else None)
    value = (presentation["value"]
             if isinstance(presentation, dict) and "value" in presentation else None)
    meta = value["meta"] if isinstance(value, dict) and "meta" in value else None
    if not isinstance(meta, dict) or "profile" not in meta or "kind" not in meta:
        return None
    profile = meta["profile"]
    if (isinstance(profile, str) and profile.startswith("observation/")
            and meta["kind"] == "observation"):
        return meta
    return None

zero_meta = observation_zero_meta(envelope)
if zero_meta is not None:
    print("observation/0: the digest presented names an observation record of profile " + show(zero_meta["profile"]) + " and the receipt's own grade word is " + show(envelope.get("verdict")) + " -- its limits register row (What a BlueFox receipt does not prove, observation/0) carries its proves and does_not_prove clauses, lifted verbatim from the spec")

# THE LIMITS REGISTER, IN ONE LINE (ff116, SS116/D006). The scope block above says
# what this RUN did not check; this line says what a PASSING receipt does not
# PROVE, in the words a reader meets -- the not_an_attestation discipline made
# legible where the verdict is read. It prints on the pass path only, right
# before the verdict; a refusal never reaches it. Both published checkers print
# this exact sentence (the parity suite compares them byte for byte), and the
# TS module beside the taught bytes exports it as DOES_NOT_PROVE_LINE so the
# site's register page can quote the same words; a test pins the two equal.
print("does_not_prove: that any claim inside this receipt is true, that the act it describes happened as written, or anything about the content behind a digest -- this check shows only that these bytes were signed under the key set this run used and have not changed since")

print("the check passes: every signed field recomputed from the file's own bytes")

No Python on the machine? Use the JavaScript twin instead. https://api.bluefoxedge.ai/verify_receipt.js (checksum beside it at .sha256, same shasum -c shape) is one file, zero dependencies, no build step, Node 18+ — run it as node verify_receipt.js my-receipt.json, as npx bluefox-verify-receipt my-receipt.json, or by pasting the whole file into any JavaScript runtime. Take the Python one if you have a Python and the JavaScript one if you do not: they are twins, not alternatives — same steps, same order, same verdict, and the same refusal sentences, proven byte-for-byte against each other on this specimen and on a ten-plant tamper battery — online and again fully offline. Both twins take the same --jwks flag, and both run step 5's inclusion check when handed the proof — the Python route as two scripts (verify_receipt.py, then verify_inclusion.py), the JavaScript one as this same file with --inclusion — and either, given --witness-keys and a vkey you saved from the witness's own origin (never from BlueFox), also verifies the witness's cosignature on the checkpoint: one witness today, so a pass reads “witnessed by one witness”.

The signature signs the chain_self string (UTF-8). Receipts are hash-chained per account: your next receipt's chain_prev equals this receipt's chain_self, and the first receipt in an account chains from GENESIS.

The script above verifies offline — keyless, anyone can run it. POST /v1/receipts/YOUR_RECEIPT_ID/verify is the server-side integrity check and requires your API key.

How the signature binds to your receipt bytes (envelope schema_version 1.0.0). content_digest = "sha256:" + sha256(JCS(envelope with the entire "chain" subtree removed)).hexdigest() — JCS is RFC 8785 canonical JSON. chain_self = "sha256:" + sha256((content_digest + "|" + chain_prev + "|" + schema_version).encode("utf-8")).hexdigest() — the three components join as their full literal strings: the "sha256:"-prefixed digest; chain_prev (the literal "GENESIS" for an account's first receipt, else the prior receipt's chain_self); and the envelope's own schema_version. signature is detached Ed25519 over chain_self.encode("utf-8") — the full "sha256:..." string — stored base64url with padding stripped; key_id is sha256 of the raw 32-byte public key (hex) and equals the published JWKS kid. Because chain_self commits to content_digest, and content_digest commits to every envelope byte outside chain, a valid signature over chain_self is a signature over your receipt's content — verifiable offline from the published key set alone, no BlueFox endpoint required.

This construction is frozen for envelope schema_version 1.0.0. The version string is itself hashed into chain_self, so every receipt cryptographically names the recipe it verifies under. If the envelope format changes, the new schema_version will publish its own construction beside this one; receipts already minted keep verifying forever under the recipe their schema_version names.

5. Prove Your Receipt Is in the Log

Signed receipts are admitted to an append-only transparency log as they are minted — free and paid tiers identically, one log, one set of terms. Every receipt minted since 2026-08-14T01:16:43Z is in the log; for the one bounded exception, see What this log covers below. Prove yours is in it, no account required:

curl "https://api.bluefoxedge.ai/v1/transparency/inclusion?log_id=reliance/v1&chain_self=<your receipt's chain.self>"

Nothing of your own to check yet? Run the whole thing on a published receipt, right now, with no account. Two receipts are published, and they do different jobs — worth thirty seconds, because picking the wrong one sends you down a dead end:

Pin the checker, then prove the example's inclusion. Copy all four lines:

curl -sS -O https://api.bluefoxedge.ai/verify_inclusion.py
curl -sS https://api.bluefoxedge.ai/verify_inclusion.py.sha256 | shasum -a 256 -c -
curl -sS "https://api.bluefoxedge.ai/v1/transparency/inclusion?log_id=reliance/v1&chain_self=sha256:05d2133e06c5e642cdd5d558853e3d7d7a543a9a36b141e2e403076173e029da" | python3 verify_inclusion.py

That exits 0 and places the entry at leaf index 991, verified against the log key you pinned yourself — followed, on its own separate line, by what the run did not prove. The checker needs nothing installed: it is standard library only and carries its own Ed25519 verifier.

The tree size you see will be bigger than ours, and that is the point. When this example was published the proof read leaf index 991 of a tree of 1005. Run it today and the leaf index is still 991 while the tree is larger, because entries are only ever appended — a proof does not go stale as the log grows past it. If you want that in writing rather than on trust, /v1/transparency/consistency?from=1005&to=<a later published size> proves the tree you see is an extension of the one this example was proved against, and not a rewrite of it.

The example checks all the way down, if you want it to. The bytes that were notarized are published too, so you can recompute the digest inside the receipt rather than take our word that it matches:

curl -sS -O https://www.bluefoxedge.ai/specimen-inlog-preimage.txt
shasum -a 256 specimen-inlog-preimage.txt

That digest is the source_bytes_digest in the receipt's sources block, and the receipt's own signature is checked by step 4's script — so pre-image, receipt, signature and log position are each verifiable from published bytes alone, by four separate commands, none of which asks you to trust the previous one.

One honest note on retention. A tier-B receipt's stored copy is eligible for purge 90 days after it was minted, so a lookup of this receipt by id will eventually stop returning it. The published file above and its entry in this log are both permanent, and this log is append-only — so the inclusion proof in this example keeps verifying after our stored copy is gone. That is the retention promise stated plainly rather than advertised: a receipt you hold remains verifiable against our published keys after our copy is purged.

Possession of the receipt is the credential — chain.self is a value only your receipt carries. The response returns your leaf index, the audit path, and the signed checkpoint note; check all of it with the runnable script at https://api.bluefoxedge.ai/verify_inclusion.py (pin the bytes with .sha256, same as step 4) — and add --witness-keys with a vkey you saved from the witness's own origin, never from BlueFox, to verify the witness's cosignature on the checkpoint too: one witness today, and a cosignature says the witness saw this exact checkpoint and found it consistent with its history, nothing about your receipt's contents. Two things to know before you run it: the log signs checkpoints with a different key than receipts — both live at /.well-known/jwks.json, and you should pin keys from there, never from a pointer inside the artifact you are checking — and a proof is a statement about a moment: the tree grows on the published cadence, which never stales an old proof; /v1/transparency/consistency ties any two published sizes, so a proof you saved last month still carries. Minted in the last hour? Your entry may be admitted but not yet under a signed checkpoint — the endpoint answers binding: "pending" with a retry interval. For any receipt minted since 2026-08-14T01:16:43Z, admission is permanent and gap-free: a pending entry is never dropped, and retrying resolves it. binding: "pending" means one other thing for receipts from the window described below — there, retrying will not resolve it, because the receipt was never admitted. What this log covers says which is which.

What this log covers

The reliance inclusion log (reliance/v1, origin edge.bluefox.ai/transparency/reliance/v1) is an append-only, signed record of receipt digests. Each entry is added at the moment its receipt is minted, and the log's published checkpoints commit to every entry admitted before them.

Coverage begins 2026-08-10T03:39:45Z, when the log was first signed. From that moment, receipts minted in-request were admitted to the log as they were created.

Full coverage — every receipt, on every lane — begins 2026-08-14T01:16:43Z. Between the two dates above, a configuration defect on the asynchronous minting worker prevented it from offering its receipts to the log. Receipts minted on that lane in that window were signed, chained and stored exactly as specified, and they verify today exactly as they always did — but they were never added to this log, and they will not be. 1,674 receipts produced between 2026-08-10T03:39:45Z and 2026-08-14T01:16:43Z are affected.

What this means if you hold one of them. Your receipt's evidence bundle reports "binding": "pending" for its inclusion entry, with no leaf index and no proof path. That is the honest reading of the field and it was never anything else: the receipt is not in the log. Every other guarantee your receipt carries is unaffected — its signature, its content digest, and its position in your account's hash chain all verify independently of this log (steps 3 and 4 above check all three, offline, with no account).

Receipts produced before 2026-08-10T03:39:45Z predate the log entirely. No claim of inclusion is made or implied for them.

Why we did not add them later. This log's value rests on one property: an entry's position in it reflects when the receipt was made. Adding older receipts to the end of the log today would put a receipt made on the 11th after one made on the 14th, and the log's ordering would stop meaning what it says. We judged a smaller log that means what it says to be worth more than a larger one that needs a footnote. This statement is that footnote, published instead.

The payment count inherits this boundary. /v1/transparency/payments answers one question about a settlement transaction — how many entries in this log are bound to it — and answers only a caller presenting both the transaction hash and a receipt-derived key from their own receipt; the reply is a count plus a membership assertion, never a list of receipts. Its scope is exactly this log: 17,485 receipts (measured 2026-08-24T03:41:11Z; every lane, all time) were never admitted and can never be counted there. That is a wider scope than the window figure above — it additionally counts receipts minted before the log existed at all — and it is a closed set: nothing after 2026-08-14, because every receipt minted since is admitted at mint. A count of 1 means exactly one entry in this log binds your transaction as of the read; re-read it later and the number must never fall.

Bitcoin anchoring

The log’s anchor lane is public: GET https://api.bluefoxedge.ai/v1/transparency/anchors summarises how far each checkpoint root has travelled toward a Bitcoin anchor; /v1/transparency/anchor?log_id=reliance/v1&tree_size=<N> serves one checkpoint’s record, every state carrying a plain-language explanation of exactly what it does and does not assert; and /v1/transparency/anchor/proof serves the raw calendar proof bytes verbatim. Read the confirmation block on the summary first — it states, in the response itself, what the word confirmed rests on here. The raw proof plus the published checkpoint root is everything a standard OpenTimestamps client needs to check the timestamp independently, and if that client disagrees with our anchor record, the client is right. What the word means one surface over: on the per-receipt inclusion proof (/v1/transparency/inclusion), binding "anchored" requires an offline-verifiable EXTERNAL time anchor — an OpenTimestamps-confirmed Bitcoin commitment, or a held qualified timestamp — covering that tree size; it is never an internal marker. The anchor now has its OWN published checker (R9-1): https://api.bluefoxedge.ai/verify_anchor.py (+ .sha256), standard-library-only, carrying no key of ours at all — it fetches no key set and checks no signature, executing the stored timestamp proofs from the checkpoint root and confirming the block through a quorum of independently operated public chain APIs at a depth of 6 blocks pinned in the script's own bytes — deliberately not read from this API, since a bar it fetched from us would be a bar we could lower under it; it is the same figure the summary serves as required_confirmation_depth, and its --depth flag is how a holder holds us to a higher one. One command, filling the same two selectors the record door above takes: curl -sS "https://api.bluefoxedge.ai/v1/transparency/anchor?log_id=&tree_size=" | python3 verify_anchor.py — and its --root flag pins the checkpoint root out of band, so the run refuses unless our record agrees with the note you already hold. The inclusion checker ends on our log signature and says so on every run; that one does not end on anything of ours. An anchored response carries an anchor block pointing at the record and proof doors above, and those bytes plus that checker — or any stock OpenTimestamps client — are how a stranger checks the claim. "included" means committed under a signed checkpoint, claiming NO external anchor.

What confirmed rests on, in the API’s own served words: “This service does not run a Bitcoin node. It checks each claimed block against 4 independently operated public chain APIs and treats a block as observed only when at least 3 of them agree byte-for-byte on its hash and merkle root, across at least 2 independently written implementations. Depth is computed from the lowest tip inside the largest group of operators whose tips agree within 6 blocks (the majority tip); an operator reporting a tip outside that group is recorded as an outlier and neither governs the tip nor blocks the observation, though its block observations still count. When no majority agrees about the tip, when the operators contradict each other about a block, or when too few answer, the result is undetermined and nothing is confirmed. What is trusted here is that those operators are not simultaneously wrong about the same block — not the Bitcoin protocol itself.” The required depth — 6 blocks at this render — is served beside the counts as required_confirmation_depth.

Confirmed anchors exist on this log. The live count is the summary’s to serve — a number printed on this page would only go stale. Once a checkpoint is anchored, rewriting the log's history under it means rewriting Bitcoin: the root sits under public proof-of-work and the proof of its commitment is public, so we could not quietly change what we have already anchored — nobody could, including us. Two honest limits ride that sentence. An anchor covers this log's history up to its checkpoint; newer entries wait for their own checkpoint's anchor. An anchor bounds when a root existed — no later than its block. It does not backdate anything, and history older than the first anchor carries only the first anchor's bound.

curl -sS "https://api.bluefoxedge.ai/v1/transparency/anchor?log_id=reliance/v1&tree_size=1"

Checkpoint 1 is the earliest confirmed anchor at the moment this page rendered. The response reports the observed block height, hash and merkle root, the depth at confirmation, and the same explanation sentence every state carries. To go all the way down, fetch the raw proof (kind=upgraded) from /v1/transparency/anchor/proof and run it with a stock OpenTimestamps client against any view of the Bitcoin chain you trust.

6. Zero-Signup Scan

Scan a GitHub repo, npm package, or MCP server with no account. Fetch the script, verify it against its published checksum, then run it:

curl -sS -O https://api.bluefoxedge.ai/verify.sh
curl -sS https://api.bluefoxedge.ai/verify.sh.sha256 | shasum -a 256 -c - && bash verify.sh github.com/OWNER/REPO

The check prints verify.sh: OK, and the scan runs only if the checksum matches (on Linux, use sha256sum -c -).

The result is a scan report with severity counts — findings labeled passed / info / warnings / errors / critical — not a single verdict.

7. For AI Agents: x402 Pay-Per-Call

Agents can pay per-request with USDC over the x402 protocol — no API key required. Payments settle on Base mainnet (eip155:8453).

curl -s -X POST https://api.bluefoxedge.ai/v1/brand/check \
  -H "Content-Type: application/json" \
  -d '{"brand": "nike", "claims": ["Nike tagline is Just Do It"]}'
{
  "x402Version": 1,
  "error": "Payment required — this response is the quote. Pay the terms in accepts[0] (maxAmountRequired is an integer amount in atomic units of the asset contract) via the x402 protocol, or use an API key from https://api.bluefoxedge.ai/get-key. Keyless-payable endpoints: https://api.bluefoxedge.ai/.well-known/x402",
  "accepts": [{
    "scheme": "exact",
    "network": "base",
    "maxAmountRequired": "1000",
    "payTo": "0x4AAF70307b2DA4cd8E0d1F6381FF373efDf7fa03",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
  }]
}

Pricing varies by endpoint ($0.0005 - $0.12); the 402 body and the X-Payment-* response headers state the exact terms — maxAmountRequired is an integer amount in atomic USDC units and asset is the USDC token contract address; the amount in this example is one rung of that table, not a plan rate. Agent discovery card

8. MCP Discovery

Edge publishes a Model Context Protocol server card at /.well-known/mcp/server.json (42 tools). Client configuration examples will be added here once each has been exercised end-to-end against a released client — every example on this page must survive verbatim copy-paste, so none ship before they run.

Verification Domains

Financial is the validated domain — 91.47% match-rate (n=938), computed 2026-10-04, SEC EDGAR ground truth; the live cell and its methodology pointer are published at /v1/accuracy/financial. The other domains are not yet validated, and every response says so in its labels.

← Back to BlueFox Edge