client.attest()
The headline call. Runs a payload through the orchestrator's nine stages and returns a sealed receipt containing the manifest hash.
Signature
client.attest(
payload: str | bytes,
program_id: str,
route_id: str,
registry_record_hash: str,
) -> AttestationReceipt
| Argument | Type | HTTP wire format | Notes |
|---|---|---|---|
payload | str or bytes | payload_text (string) or payload (string) | Strings sent as payload_text; bytes sent as payload (UTF-8 if possible, base64 otherwise). The wire format is always a string. |
program_id | str | program_id | 64-char lowercase hex |
route_id | str | route_id | Non-empty |
registry_record_hash | str | registry_record_hash | 64-char lowercase hex |
Payload encoding
The HTTP request body sends payload as a JSON string, not as bytes. The SDK's handling:
- String input: Sent as
payload_textin the JSON request. The orchestrator canonicalizes it with the prefixpayload.v1before hashing. - Bytes input (UTF-8 decodable): Decoded to string, then sent as
payload_text(same as string case). - Bytes input (non-UTF-8): Encoded as base64, then sent as
payloadfield (string, not bytes). The orchestrator canonicalizes it with the prefixpayload.b64.v1before hashing.
This means the bytes that get hashed depend on your input type. To ensure determinism across language implementations, always pass strings if your content is text.
Return value
AttestationReceipt. See AttestationReceipt for full field reference. Most callers just want receipt.manifest_hash.
Raises
| Exception | When |
|---|---|
ValidationError | Client-side validation failed (bad hex, empty route, wrong type) |
StageError | A specific pipeline stage rejected the run; check .stage |
APIError | API returned a non-2xx response that wasn't a stage error |
ConnectionError | Couldn't reach the API |
All four inherit from VerdifaxError for single-except handling.
Example
from verdifax import VerdifaxClient
with VerdifaxClient() as client:
receipt = client.attest(
payload="hello verdifax",
program_id="a" * 64,
route_id="route-test",
registry_record_hash="b" * 64,
)
print(receipt.manifest_hash)
Determinism
Identical inputs produce identical receipts. The SDK enforces this by canonicalizing the request body, payload_text always wins over payload when the input is a UTF-8 string.
Module-level shortcut
For one-shot scripts, verdifax.attest(...) is a convenience that constructs a client from env vars, runs the call, and closes the client:
import verdifax
receipt = verdifax.attest(
payload="hi", program_id="a"*64, route_id="r", registry_record_hash="b"*64,
)
For high-throughput use, instantiate VerdifaxClient yourself and reuse.
