Skip to main content

Handle the Authorization header

An MPP payment credential is passed in the standard Authorization HTTP header using the Payment scheme. The value is a base64url-encoded JSON object. This page describes the credential format for developers building MPP-compatible agents or integrations.

The credential structure

The Authorization header sent by an MPP agent looks like:
Decoded, the payload is:

Credential fields

Parsing the credential in TypeScript

Building a credential (for agents)

What Prudra verifies

When a request arrives with Authorization: Payment <credential>, Prudra verifies:
  1. Challenge ID — recomputes the HMAC from the echoed challenge parameters and compares with crypto.timingSafeEqual(). The challenge must be valid and unexpired.
  2. Transaction — fetches the receipt for txHash from the Tempo RPC. Receipt must be non-null (transaction confirmed).
  3. ConfirmationscurrentBlock - txBlock >= 1 (Tempo Simplex Consensus, 1 confirmation is sufficient)
  4. Recipient — the to address in the transaction matches the server’s registered wallet address
  5. Amount — the token transfer amount meets or exceeds the required price in USDC.e
  6. Sender — the from address in the credential matches the transaction sender
  7. Replay — the txHash has not been seen before (UNIQUE constraint in Postgres)
If any check fails, Prudra returns 402 with a new challenge (if the request was unauthenticated) or a 402 with no new challenge (if the credential was malformed).

Security note on challenge reuse

A valid challenge ID can only be used once per unique txHash. The combination of (challengeId, txHash) uniqueness is enforced at the DB level. However, the HMAC challenge ID itself is stateless — Prudra doesn’t store challenge IDs. This means:
  • An attacker cannot forge a challenge ID without knowing the MPP_CHALLENGE_SECRET
  • An expired challenge’s ID will fail HMAC verification (expiry is part of the signed input)
  • A valid txHash cannot be reused even with a new, valid challenge ID