Skip to main content

Python Reference Verifier

Packaged Python verifier for Allowly Receipt Format wire version 4.

Install

pip install allowly-receipt-format

Only dependency: cryptography for Ed25519 signature verification.

CLI

Verify a single receipt:

allowly-receipt-verify \
  --workspace-id "$ALLOWLY_WORKSPACE_ID" \
  --trusted-key-fingerprint "$ALLOWLY_TRUSTED_KEY_FINGERPRINT" \
  path/to/receipt.json path/to/keys.json

Verify a whole export or audit-package chain in one go (.jsonl or .jsonl.gz):

# Each line is either a bare receipt (audit-package chain.jsonl) or a
# {"receipt_id", ..., "receipt": {...}} export wrapper — both are handled.
allowly-receipt-verify \
  --export chain.jsonl \
  --workspace-id "$ALLOWLY_WORKSPACE_ID" \
  --trusted-key-fingerprint "$ALLOWLY_TRUSTED_KEY_FINGERPRINT" \
  keys.json

If the export includes checkpoint evidence, recompute every listed checkpoint from the already verified receipt lines:

allowly-receipt-verify \
  --export chain.jsonl \
  --checkpoint-evidence checkpoint_evidence.json \
  --workspace-id "$ALLOWLY_WORKSPACE_ID" \
  --trusted-key-fingerprint "$ALLOWLY_TRUSTED_KEY_FINGERPRINT" \
  keys.json

Verify only one authorization's chain and check its structure (exactly one authorization.create, at most one authorization.revoke, well-formed timestamps), printing the timeline:

allowly-receipt-verify \
  --export export.jsonl.gz \
  --authorization-id auth_01HXZ2... \
  --workspace-id "$ALLOWLY_WORKSPACE_ID" \
  --trusted-key-fingerprint "$ALLOWLY_TRUSTED_KEY_FINGERPRINT" \
  keys.json

--workspace-id and at least one --trusted-key-fingerprint are required. Fingerprints use sha256:<64 lowercase hex> over the decoded raw 32-byte Ed25519 public key. Repeat the fingerprint flag for every trusted rotation key that may have signed the selected receipts.

For local development without installing from PyPI:

pip install -e .
python verifier.py \
  --workspace-id "$ALLOWLY_WORKSPACE_ID" \
  --trusted-key-fingerprint "$ALLOWLY_TRUSTED_KEY_FINGERPRINT" \
  path/to/receipt.json path/to/keys.json

Exit codes:

  • 0 — all presented receipts valid (and, with --authorization-id, the presented chain is structurally well-formed)
  • 1 — any receipt invalid, no receipts matched, or a chain anomaly (reason on stderr)

Library

from allowly_receipt_format import verify_receipt, VerificationError, load_keys_from_json
import json
import os

with open("receipt.json") as f:
    receipt = json.load(f)
with open("keys.json") as f:
    keys_doc = json.load(f)
configured_workspace_id = os.environ["ALLOWLY_WORKSPACE_ID"]
trusted_fingerprints = {os.environ["ALLOWLY_TRUSTED_KEY_FINGERPRINT"]}
if keys_doc.get("workspace_id") != configured_workspace_id:
    raise ValueError("key document workspace does not match configuration")
keys = load_keys_from_json(keys_doc)

try:
    verify_receipt(
        receipt,
        keys,
        expected_workspace_id=configured_workspace_id,
        trusted_key_fingerprints=trusted_fingerprints,
    )
    print("valid")
except VerificationError as e:
    print(f"invalid: {e}")

Always pass expected_workspace_id to bind the receipt to a workspace — a key_id alone does not (spec §7, "Workspace binding"). Take that ID from caller-trusted configuration, never from the receipt or key document, and reject a key document that declares a different workspace. The CLI requires that caller-trusted workspace ID plus one or more caller-trusted key fingerprints. It checks the workspace against the key document and receipts, and requires every selected receipt key to be pinned. A workspace ID or fingerprint copied from the same untrusted bundle as the receipts is not an independent trust anchor:

verify_receipt(
    receipt,
    keys,
    expected_workspace_id="ws_01HXA1B2C3D4E5F6G7H8J9K0L1",
    trusted_key_fingerprints={"sha256:<64 lowercase hex>"},
)

public_key_fingerprint(key) returns that canonical fingerprint over the decoded raw 32-byte Ed25519 public key. load_keys_from_json validates an advertised public_key_fingerprint, but the advertised value is not itself a trust anchor.

The package exposes typed verifier exceptions:

  • SchemaError
  • UnknownKeyError
  • KeyOutsideActiveWindowError
  • SignatureMismatchError

All inherit from VerificationError.

Verify a daily checkpoint

verify_checkpoint verifies the checkpoint and member signatures, period, count, Merkle root, and optional prior linkage. The workspace id must come from caller-trusted configuration, and key fingerprints should come from an authenticated channel:

from allowly_receipt_format import verify_checkpoint

verify_checkpoint(
    checkpoint,
    member_receipts,
    keys,
    expected_workspace_id=configured_workspace_id,
    trusted_key_fingerprints=trusted_fingerprints,
    previous_checkpoint=previous_checkpoint,
)

Success proves the supplied set matches the signed commitment. Without an external anchor it does not prove the issuer registered or retained every receipt before constructing the checkpoint.

Match a keyed pseudonym reference

matches_ref implements the optional hmac-v1 convention in specification Appendix A. Decode the show-once integration key, then match locally:

import base64
from allowly_receipt_format import matches_ref

encoded_key = "<pseudonym_key_b64url>"
key = base64.urlsafe_b64decode(encoded_key + "=" * (-len(encoded_key) % 4))

assert matches_ref(
    key,
    "record",
    "MRN-48291",
    receipt["context"]["record_ref"],
)

Use the context.ref_key_version recorded in the receipt to select the retained key version. Matching occurs entirely offline; it does not ask Allowly to resolve an identifier.

verify_receipt accepts an already-parsed object, so it cannot detect duplicate raw JSON names that a normal parser has already overwritten. The CLI uses a duplicate-aware parser and rejects them. The verifier also rejects parsed floating-point values, including the results of 1.0 and 1e0; callers using a different parser must preserve that distinction (spec §4.2).

Test vectors

Run against the shared test vectors:

pip install -e .
python test_vectors.py ../../test-vectors.json
python test_exception_types.py ../../test-vectors.json

All should_verify vectors must pass; all should_reject vectors must be rejected with the expected reason.

License

Apache 2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

allowly_receipt_format-4.0.0.tar.gz (18.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

allowly_receipt_format-4.0.0-py3-none-any.whl (16.6 kB view details)

Uploaded Python 3

File details

Details for the file allowly_receipt_format-4.0.0.tar.gz.

File metadata

  • Download URL: allowly_receipt_format-4.0.0.tar.gz
  • Upload date:
  • Size: 18.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for allowly_receipt_format-4.0.0.tar.gz
Algorithm Hash digest
SHA256 27cd96a06edea1a23c340d9015ef1c0434b6dc1d4b2d7b56653d18b3991d6eec
MD5 022c41047aec89da84d0c6f9a7e61fdb
BLAKE2b-256 864dcd30ade1b597ee0ee1bdbfea33fd6f77c294999f4cc42504152690df13e2

See more details on using hashes here.

Provenance

The following attestation bundles were made for allowly_receipt_format-4.0.0.tar.gz:

Publisher: publish-python.yml on Allowly-AI/allowly-receipt-format

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file allowly_receipt_format-4.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for allowly_receipt_format-4.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 18a038b9ffe9be25c63bd2f39b1f26fffbebb89e43622de9d2b479b06ea14b93
MD5 82644124c4427713b300fbdc3772224b
BLAKE2b-256 60d945545ccdda5810e31d907bb5d26d5c4953864425a79b94708b61fccd23fe

See more details on using hashes here.

Provenance

The following attestation bundles were made for allowly_receipt_format-4.0.0-py3-none-any.whl:

Publisher: publish-python.yml on Allowly-AI/allowly-receipt-format

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

4.0.1

2 files

This release

4.0.0 This release

2 files

3.0.0

2 files

1.0.5

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page