TypeScript — trust resolution
Browser / public access: fetch GET /api/v1/trust/{publicId}/human (no API key required). API consumer access: fetch GET /api/v1/trust/{publicId}/machine with header Authorization: Bearer <pv_live_xxxx> (trust:read scope). The response type for both is MachineTrustResponse from @/domain/machine-contracts. Validate schema === "pv.machine-trust.v1" before consuming. Check authority.authoritative_state before drawing any conclusions about issued credentials.
TypeScript — reliance receipts
POST /api/v1/reliance-receipts with x-pv-internal-token. Supply only consumer identity fields. Parse the pv-reliance-receipt-v1 response. Verify receipt_digest client-side: sha256(JSON.stringify(snapshot_payload)). The SDK must never construct decision or trust_state_digest on the caller side.
Python — trust resolution
Public access: GET https://{host}/api/v1/trust/{public_id}/human (no API key required). API consumer access: GET https://{host}/api/v1/trust/{public_id}/machine with header Authorization: Bearer <pv_live_xxxx> (trust:read scope required — 401 if omitted). Parse the JSON response and validate schema == "pv.machine-trust.v1". Inspect authority["authoritative_state"] — expected value is NOT_AUTHORIZED. Inspect lifecycle["state"] — expected value is NOT_ISSUED for all current records.
Idempotency
POST /api/v1/reliance-receipts is idempotent by (principal, subject_public_id, purpose_id, requested_action, determination_digest). Repeating the same request with the same effective inputs returns the existing receipt with status 200 and idempotent=true.
State verification
Before relying on any response: verify freshness.state is CURRENT; verify authority.authoritative_state is what you expect (currently always NOT_AUTHORIZED); verify lifecycle.state matches your use case; verify trust_state_digest is stable between requests when you cache results.