Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.usemandate.io/llms.txt

Use this file to discover all available pages before exploring further.

Mandate uses a cryptographically signed proof-of-payment model. An agent generates a proof asserting its identity, the mandate it is drawing from, and the amount it intends to pay. A merchant verifies that proof and, once valid, the charge is recorded against the mandate’s budget. These two endpoints implement both sides of that handshake in the sandbox environment.

Generate a sandbox proof


POST /v1/payments/proof
Generates a signed payment proof that an agent can present to a merchant. The proof is an HMAC-SHA256 signed payload that binds together the agent identity, mandate, amount, resource URL, a unique nonce, and a timestamp.
This endpoint is sandbox only. Calling it with a production API key returns 400 production_payments_not_supported. Production payment proof generation is handled by the on-chain payment layer.
Request body
agent_id
string
required
The agent generating this proof.
mandate_id
string
required
The mandate the agent is drawing from.
amount
string
required
The payment amount as a decimal string, e.g. "0.10". Must exactly match the expected_amount when the proof is verified.
currency
string
default:"USDC"
The currency for this proof. Currently "USDC" only.
resource_url
string
required
The URL of the resource being purchased.
curl --request POST https://api.kya.dev/v1/payments/proof \
  --header "Authorization: Bearer ky_sand_••••••••••••••••" \
  --header "Content-Type: application/json" \
  --data '{
    "agent_id": "agent_abc123",
    "mandate_id": "mandate_xyz789",
    "amount": "0.10",
    "currency": "USDC",
    "resource_url": "https://api.example.com/data/companies/AAPL"
  }'
Response 201
proof
object
required
Example response
{
  "proof": {
    "scheme": "kya-sandbox",
    "network": "sandbox",
    "agentId": "agent_abc123",
    "mandateId": "mandate_xyz789",
    "amount": "0.10",
    "currency": "USDC",
    "resource": "https://api.example.com/data/companies/AAPL",
    "nonce": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "timestamp": "2024-01-15T10:30:00+00:00",
    "signature": "a1b2c3d4e5f6..."
  }
}
Error responses
StatusDetailCause
400production_payments_not_supportedRequest was made with a production API key.

Verify a payment proof


POST /v1/payments/verify
Verifies a payment proof and, if valid, records the charge against the mandate’s budget. The Mandate middleware (requireKyaPayment()) calls this endpoint automatically when a merchant receives a request with an X-Payment-Proof header. You can also call it directly if you are implementing a custom verification flow. Verification runs in this order:
  1. Proof timestamp within the 5-minute validity window
  2. Amount and currency match the expected values (exact string comparison)
  3. HMAC-SHA256 signature is valid
  4. Nonce has not been used before (replay protection)
  5. Nonce is marked as used in the database
  6. Mandate budget is incremented atomically
  7. Transaction record is created with status: "paid"
  8. Audit log event is written
Proofs are valid for exactly 5 minutes from their timestamp. A proof with a timestamp older than 5 minutes returns verified: false with reason: "proof_expired". Generate a new proof and retry.
A successful verification immediately charges the mandate’s budget. The spent_total on the mandate is incremented atomically. There is no undo or refund path in the current release.
Request body
proof
object
required
The proof object returned by POST /v1/payments/proof. Pass the entire object without modification.
merchant_domain
string
required
The domain of the merchant receiving the payment, e.g. "api.example.com". Used to look up the merchant record on the transaction.
expected_amount
string
required
The amount the merchant expects to receive. Must be an exact string match with proof.amount.
expected_currency
string
default:"USDC"
The currency the merchant expects. Must be an exact string match with proof.currency.
curl --request POST https://api.kya.dev/v1/payments/verify \
  --header "Authorization: Bearer ky_sand_••••••••••••••••" \
  --header "Content-Type: application/json" \
  --data '{
    "proof": {
      "scheme": "kya-sandbox",
      "network": "sandbox",
      "agentId": "agent_abc123",
      "mandateId": "mandate_xyz789",
      "amount": "0.10",
      "currency": "USDC",
      "resource": "https://api.example.com/data/companies/AAPL",
      "nonce": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "timestamp": "2024-01-15T10:30:00+00:00",
      "signature": "a1b2c3d4e5f6..."
    },
    "merchant_domain": "api.example.com",
    "expected_amount": "0.10",
    "expected_currency": "USDC"
  }'
Response — verified
verified
boolean
required
true when verification succeeds and the charge has been recorded.
transaction_id
string
required
The ID of the paid transaction record created for this charge.
Example response — verified
{
  "verified": true,
  "transaction_id": "transaction_ghi789"
}
Response — not verified
verified
boolean
required
false when any verification step fails.
reason
string
required
Machine-readable failure reason. Possible values: proof_expired, amount_mismatch, invalid_signature, nonce_reused.
Example response — not verified
{
  "verified": false,
  "reason": "nonce_reused"
}
ReasonCause
proof_expiredProof timestamp is more than 5 minutes old.
amount_mismatchproof.amount or proof.currency does not match the expected values.
invalid_signatureHMAC-SHA256 signature does not match the recomputed value.
nonce_reusedProof nonce has already been consumed by a previous verification.