Skip to main content

Overview

Validates payment proof from client without executing the blockchain transaction. Endpoint: POST https://facilitator.corbits.dev/verify

Purpose

This endpoint is called by resource server middleware to validate a payment attempt before settlement. The facilitator performs all validation checks but does NOT execute the on-chain transaction, making it a safe “dry-run” that confirms payment validity. The validation logic differs based on the blockchain:
  • Solana: Validates transaction structure, signatures, amounts, and fees without submitting to network
  • EVM: Validates EIP-3009 authorization signatures, amounts, addresses, and nonce status without calling the token contract

Request Body

x402Version
integer
required
The x402 protocol version (must be an integer). Currently 1.Note: The x402Version field appears both at the top-level request and inside the payment payload (when using paymentHeader or paymentPayload). Both should be set to 1 and typically match.
paymentHeader
string
Base64-encoded JSON string containing the payment payload from the client’s X-PAYMENT header.Note: Either paymentHeader OR paymentPayload must be provided. The paymentHeader will be automatically decoded to produce the Payment Payload Structure shown below.
paymentPayload
object
Pre-decoded payment payload object. Has the same structure as the decoded paymentHeader (see Payment Payload Structure above).Note: Either paymentHeader OR paymentPayload must be provided. If both are provided, paymentPayload takes precedence and paymentHeader is ignored.
paymentRequirements
object
required
The original payment requirements object (same structure as in /accepts endpoint).

Response

isValid
boolean
required
Whether the payment is valid. true if payment passes all validation checks, false otherwise.
invalidReason
string
Explanation if isValid is false. Omitted when payment is valid.Common reasons:
  • "Invalid transaction" (Solana: transaction structure or validation failed)
  • "Payment authorized to wrong address" (EVM: recipient mismatch)
  • "Incorrect payment amount" (EVM: amount mismatch)
  • "Authorization not yet valid" (EVM: before validAfter timestamp)
  • "Authorization expired" (EVM: after validBefore timestamp)
  • "Invalid from address" (EVM: sender address invalid)
  • "Authorization already used on-chain" (EVM: nonce already consumed)
  • "Invalid signature" (EVM: EIP-712 signature verification failed)

Example Request (Solana)

{
  "x402Version": 1,
  "paymentHeader": "eyJ4NDAyVmVyc2lvbiI6MSwic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoic29sYW5hLWRldm5ldCIsImFzc2V0IjoiNHpNTUM5c3J0NVJpNVgxNEdBZ1hoYUhpaTNHblBBRUVSWVBKZ1pKRG5jRFUiLCJwYXlsb2FkIjp7InRyYW5zYWN0aW9uIjoiQVFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEifX0K",
  "paymentRequirements": {
    "scheme": "exact",
    "network": "solana-devnet",
    "maxAmountRequired": "1000000",
    "resource": "https://api.example.com/data",
    "description": "API access fee",
    "mimeType": "application/json",
    "payTo": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
    "maxTimeoutSeconds": 300,
    "asset": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
    "extra": {
      "feePayer": "DpwuqYQuroELiQbVgocdHKE1JeSaCFH4atxdgiVE1n6M",
      "decimals": 6,
      "recentBlockhash": "7pyreX4HniHn9LQ94DBXfxvksotyZZGBaTGfxSexmGto"
    }
  }
}

Example Response (Valid)

{
  "isValid": true
}

Example Response (Invalid)

{
  "isValid": false,
  "invalidReason": "Incorrect payment amount"
}

Usage in Middleware

The /verify endpoint is used by Hono middleware when verifyBeforeSettle is enabled. This validates the payment before processing the request:
import { hono } from '@faremeter/middleware';

// Create middleware with verify-before-settle option
const middleware = await hono.createMiddleware({
  facilitatorUrl: 'https://facilitator.corbits.dev',
  accepts: [paymentRequirements],
  verifyBeforeSettle: true  // Calls /verify before handler, /settle after
});

// Apply middleware
app.use('/protected', middleware, async (c) => {
  return c.json({ data: protectedData });
});
How it works:
  1. Client sends payment with request
  2. Middleware calls /verify to validate payment
  3. If valid, your handler runs
  4. After handler completes, middleware calls /settle to execute on-chain
  5. Response sent to client
Note: Express middleware does not use /verify - it calls /settle directly. The verify endpoint is primarily for manual validation or the Hono advanced flow.

Handler Behavior

When the facilitator receives a /verify request:
  1. Decodes payment header (if needed): Extracts payment payload from base64-encoded header
  2. Tries each handler: Calls handleVerify() on registered handlers
  3. First match wins: Uses the first handler that returns a non-null result
  4. Validates payment: Handler performs blockchain-specific validation
  5. Returns result: Validation status and reason (if invalid)
Notes:
  • Unlike /settle, the /verify endpoint does NOT submit any transactions to the blockchain
  • Handlers may optionally implement handleVerify(). If a handler doesn’t implement verification, it will be skipped and the next handler will be tried
  • If a handler throws an exception during verification, the request will fail with HTTP 500 Internal Server Error

Solana Validation

The facilitator performs the following checks on Solana transactions:
  1. Transaction Structure: Validates transaction has exactly 3 or 4 instructions (3 = no ATA creation needed, 4 = includes ATA creation)
  2. Fee Payer Verification: Ensures the facilitator’s public key is the fee payer
  3. Compute Unit Limit: Validates SetComputeUnitLimit instruction is present and parseable
  4. Compute Unit Price: Validates SetComputeUnitPrice instruction is present and parseable
  5. Transfer Amount: Verifies transfer amount matches maxAmountRequired exactly
  6. Transfer Mint: Verifies token mint matches the required asset
  7. Transfer Destination: Verifies destination matches payTo address (associated token account)
Note: Solana validation returns a generic "Invalid transaction" error message when any check fails, unlike EVM which provides specific error messages for each validation failure. See Solana Payments for detailed validation logic.

EVM Validation

The facilitator performs the following checks on EVM authorizations:
  1. Payload Structure: Validates required fields are present
  2. Address Validation: Ensures from address is valid
  3. Signature Verification: Validates EIP-712 typed data signature
  4. Amount Check: Ensures value matches maxAmountRequired
  5. Recipient Check: Ensures to matches payTo address
  6. Time Validity: Checks current time is between validAfter and validBefore
  7. Nonce Check: Verifies nonce hasn’t been used on-chain
Note: The EVM handler supports both direct token contract interactions and forwarder contracts for signature verification. When a forwarder is configured, the EIP-712 domain and signature verification use the forwarder contract address instead of the token contract. See EVM Payments for detailed validation logic.

Verify vs Settle

Aspect/verify/settle
PurposeValidate paymentValidate AND execute payment
On-chain actionNo transaction (EVM: read-only nonce check; Solana: offline only)Submits transaction
Gas/feesNot consumedConsumed
IdempotentYesNo (EVM: nonce consumed; Solana: blockhash expires, can retry)
Return value{isValid, invalidReason}{success, error, txHash, networkId}
Use casePre-flight checkActual payment
Important: Verify passing doesn’t guarantee settle will succeedEven if /verify returns isValid: true, the subsequent /settle call may still fail due to:
  • Race conditions: Nonce or balance changes between verify and settle calls
  • Solana blockhash expiry: Blockhashes are valid for ~60 seconds. If settle is called after expiry, it will fail
  • Network conditions: Gas prices, congestion, or RPC issues may cause settle to fail
  • EVM nonce consumption: Another transaction may consume the nonce between verify and settle
Best practice: Minimize the time between /verify and /settle calls, especially for Solana payments. The Hono middleware with verifyBeforeSettle: true handles this automatically by calling both endpoints in sequence.

HTTP Status Codes

The /verify endpoint uses the following HTTP status codes: 200 OK:
  • Request was processed successfully
  • Check the isValid field in the response body to determine if payment is valid
  • Both valid (isValid: true) and invalid (isValid: false) payments return 200 status
400 Bad Request:
  • Invalid request format
  • Missing required fields (e.g., x402Version, paymentRequirements)
  • Failed to decode payment header
  • No handler found for the payment scheme/network combination
500 Internal Server Error:
  • Handler threw an exception during verification
  • Unexpected errors during validation
Important: Most validation failures return HTTP 200 with isValid: false in the response body. Only malformed requests return 400, and only unexpected server errors return 500.

When to Use Verify

The /verify endpoint is useful when:
  1. Pre-flight validation: Check if a payment would succeed before committing it
  2. User feedback: Provide immediate feedback to users about payment validity
  3. Testing: Validate payment construction logic without consuming gas/fees
  4. Debugging: Diagnose payment issues without state-changing transactions
Typical flow:
  1. Client constructs payment
  2. Middleware calls /verify to check validity
  3. If valid, middleware calls /settle to execute payment
  4. If invalid, middleware returns 402 Payment Required

See Also