HTTP 402

Understanding the HTTP 402 Payment Required status code and how Vanta SDK implements it.

History of HTTP 402

HTTP 402 Payment Required was defined in the original HTTP/1.1 specification (RFC 2616) back in 1999. The specification reserved it "for future use" with the expectation that a digital payment mechanism would eventually emerge.

"This code is reserved for future use. The initial aim of creating this code was for using it for some form of digital cash or micropayment scheme, but that has not happened, and this code is not usually used."

— RFC 2616, Section 10.4.3

For over two decades, 402 remained largely unused because there was no standardized way to specify payment details or verify payments programmatically. Blockchain technology changed this by providing a trustless, programmable payment layer.

The x402 Protocol

x402 is a protocol specification that defines how to implement HTTP 402 using blockchain payments. It standardizes:

  • How servers communicate payment requirements
  • How clients prove payment was made
  • How servers verify payments
  • How to handle edge cases and errors

Request Flow

Here's the complete flow of an x402 payment:

Step 1: Initial Request

The client makes a standard HTTP request to a protected resource:

GET /api/premium/data HTTP/1.1
Host: api.example.com
Accept: application/json

Step 2: Payment Challenge

The server responds with 402 and a payment challenge in the WWW-Authenticate header:

HTTP/1.1 402 Payment Required
WWW-Authenticate: x402 price="0.001" 
  currency="ETH" 
  network="base" 
  recipient="0x742d35Cc6634C0532925a3b844Bc4e7595f0aB42" 
  challenge="vnt_ch_abc123..." 
  expires="1704067200"
Content-Type: application/json

{
  "error": "payment_required",
  "message": "Payment of 0.001 ETH required to access this resource",
  "paymentDetails": {
    "price": "0.001",
    "currency": "ETH",
    "network": "base",
    "recipient": "0x742d35Cc6634C0532925a3b844Bc4e7595f0aB42"
  }
}

Step 3: Payment Execution

The client parses the challenge, sends payment on-chain, and waits for confirmation:

// Client-side
const challenge = parseChallenge(response.headers.get('WWW-Authenticate'))

// Send payment transaction
const tx = await wallet.sendTransaction({
  to: challenge.recipient,
  value: ethers.parseEther(challenge.price),
  data: encodePaymentData(challenge.challenge),
})

// Wait for confirmation
const receipt = await tx.wait()

Step 4: Authenticated Request

The client retries the request with payment proof:

GET /api/premium/data HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: x402 challenge="vnt_ch_abc123..."
  txHash="0x1234567890abcdef..."
  signature="0xdeadbeef..."

Step 5: Verification and Response

The server verifies the payment on-chain and returns the resource:

HTTP/1.1 200 OK
X-Vanta-Receipt: eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9...
X-Vanta-Token: vanta_tk_xyz789...
Content-Type: application/json

{
  "data": "This is the premium content you paid for",
  "paidAmount": "0.001 ETH",
  "txHash": "0x1234567890abcdef..."
}

Challenge Format

The WWW-Authenticate header contains all information needed for payment:

FieldDescriptionExample
priceAmount to pay0.001
currencyPayment currencyETH
networkBlockchain networkbase
recipientWallet address0x742d...
challengeUnique challenge IDvnt_ch_abc123
expiresUnix timestamp1704067200
memoOptional descriptionAPI Access

Authorization Format

The Authorization header proves payment:

FieldDescription
challengeThe challenge ID from the 402 response
txHashTransaction hash of the payment
signatureSignature proving ownership of sender address

Payment Verification

The server verifies payments by checking:

  1. Challenge validity: Challenge exists and hasn't expired
  2. Transaction existence: Transaction exists on the specified network
  3. Amount: Payment amount matches or exceeds the challenge price
  4. Recipient: Payment was sent to the correct address
  5. Data: Transaction data contains the challenge ID
  6. Confirmation: Transaction has sufficient confirmations

Performance Note

On-chain verification can take 100-500ms. For high-throughput applications, issue access tokens after the first payment verification to avoid repeated blockchain calls.

Error Codes

ErrorDescriptionClient Action
INVALID_CHALLENGEChallenge expired or not foundRequest new challenge
PAYMENT_NOT_FOUNDTransaction not on chainWait and retry
INSUFFICIENT_PAYMENTAmount too lowSend additional payment
WRONG_RECIPIENTWrong addressSend new payment
INVALID_SIGNATURESignature verification failedRe-sign with correct key

Next Steps