Validate the mandate before the contract.
Run the published @reapp-sdk/ap2 validator against a fresh signed mandate. The server returns only public keys and hashes; ephemeral signing keys never leave the request.
AP2 validation console
Select one boundary or run the complete visual suite. Every rejection must return its exact typed code.
Complete AP2 test matrix
The console above runs six representative checks live. The published package gate runs every named case below.
Binding & canonicalization
12 cases- 01canonical JSON is independent of object key insertion order
- 02binds the supported AP2 v0.2.0 intent to a 32-byte REAPP vc_hash
- 03pins a canonical AP2 hash vector
- 04provided nonce makes the full binding reproducible across key order
- 05secure default nonces keep identical intents distinct
- 06fails closed for AP2 constraints MandateRegistry cannot enforce
- 07rejects ambiguous expiry and invalid Stellar authorization
- 08fails closed on unknown intent and Stellar authorization fields
- 09rejects impossible calendar expiries instead of normalizing them
- 10signer and validator share the same canonical UTC year range
- 11signer and validator share the same decimal range
- 12agent authorization requires an Ed25519 G-address
Credential, signature & identity
27 cases- 13valid signed AP2 mandate succeeds
- 14returned mandate hash equals the recomputed REAPP id
- 15fixed seed and nonce produce a deterministic signature digest and signature
- 16exact signed maximum amount succeeds
- 17one-stroop positive amount succeeds
- 18signing key must match the payload user
- 19trusted expected user mismatch is rejected
- 20tampered natural-language intent is rejected by binding
- 21tampered merchant is rejected by binding
- 22tampered maximum amount is rejected by binding
- 23tampered decimals are rejected by the full-payload signature
- 24tampered expiry is rejected by binding
- 25tampered agent is rejected by binding
- 26tampered asset is rejected before signature verification
- 27malformed base64 signature is rejected
- 28non-canonical base64 signature is rejected
- 29signature with the wrong decoded length is rejected
- 30signature created by another Ed25519 key is rejected
- 31unsupported signature algorithm is rejected
- 32unsupported credential version is rejected
- 33unsupported AP2 version is rejected
- 34unsupported REAPP binding version is rejected
- 35wrong AP2 data key is rejected
- 36envelope mandate hash mismatch is rejected
- 37unknown top-level credential field fails closed
- 38unknown intent field fails closed
- 59invalid user, agent, and asset identities fail closed
Scope & amount
7 cases- 39trusted merchant outside signed scope is rejected
- 40zero amount is rejected
- 41negative amount is rejected
- 42scientific-notation amount is rejected
- 43excess fractional precision is rejected
- 44one stroop over the signed maximum is rejected as overspend
- 45amount beyond contract i128 is rejected
Expiry & trusted clock
4 cases- 46expired signed mandate is rejected
- 47expiry exactly equal to the trusted clock is rejected
- 48future expiry succeeds under the injected clock
- 49impossible calendar expiry fails closed
Replay & storage isolation
9 cases- 50replayed mandate hash is rejected on second admission
- 51100 concurrent admissions yield exactly one success
- 52replay store exception fails closed
- 53unsupported replay store result fails closed
- 54bad signature does not poison the replay store
- 55wrong merchant does not poison the replay store
- 56overspend does not poison the replay store
- 57expired credential does not poison the replay store
- 58explicit replay namespaces isolate independent registries
Valid mandates, tampering, scope, amount, expiry, replay, and concurrency.
Installable, typed, documented, and verified from a clean project.
The validator is an adapter. Contract enforcement remains the money boundary.
Admission replay is consumed once here. Multi-purchase budget and payment replay remain atomically enforced by MandateRegistry.execute_payment on every spend.