Submit Payment Proof

Overview

  • Function: Submit a settlement proof after the payer completes X402 payment on the source chain
  • Use Cases: Client-side payment flows, user-initiated payments with wallet signatures
  • Authentication: Not required (public endpoint)

JSON Schema Definition

{
  "name": "submit_payment_proof",
  "description": "Submits a settlement proof after the payer completes X402 payment on the source chain. No authentication required.",
  "input_schema": {
    "type": "object",
    "properties": {
      "intent_id": {
        "type": "string",
        "description": "The intent ID returned from createIntent operation"
      },
      "settle_proof": {
        "type": "string",
        "description": "The settlement proof from X402 payment. This is the signed proof from the user's wallet after completing the payment on the payer chain."
      }
    },
    "required": ["intent_id", "settle_proof"]
  },
  "output_schema": {
    "type": "object",
    "properties": {
      "intent_id": {
        "type": "string",
        "description": "The intent ID"
      },
      "status": {
        "type": "string",
        "enum": ["PENDING", "SOURCE_SETTLED", "TARGET_SETTLING", "TARGET_SETTLED", "VERIFICATION_FAILED", "PARTIAL_SETTLEMENT"],
        "description": "Current status of the intent after proof submission"
      },
      "message": {
        "type": "string",
        "description": "Status message"
      }
    },
    "required": ["intent_id", "status"]
  }
}

Parameters

Parameter Type Required Description
intent_id string Yes The intent ID returned from createIntent operation
settle_proof string Yes The settlement proof from X402 payment (signed by user's wallet)

Return Value

Success Response

{
  "intent_id": "int_abc123xyz",
  "status": "PENDING",
  "message": "Proof submitted successfully"
}

Status Values

  • PENDING: Proof submitted, verification in progress
  • SOURCE_SETTLED: Payment confirmed on the payer chain
  • TARGET_SETTLING: Settlement is being processed on the target chain
  • TARGET_SETTLED: Transfer complete (terminal state)
  • VERIFICATION_FAILED: Proof verification failed (terminal state)
  • PARTIAL_SETTLEMENT: Source settled but target did not complete (terminal state)

Code Examples

TypeScript/JavaScript

import { PublicPayClient } from '@cross402/usdc';

// Use PublicPayClient for client-side operations (no secrets required)
const client = new PublicPayClient({
  baseUrl: 'https://api-pay.agent.tech',
});

// After user signs X402 payment with their wallet
const settleProof = await getUserSignedProof(); // Get proof from wallet

// Submit the proof
const result = await client.submitProof(intentId, settleProof);

console.log(`Intent ID: ${result.intentId}`);
console.log(`Status: ${result.status}`);
console.log(`Message: ${result.message}`);

Go

package main

import (
    "context"
    "log"
    "github.com/cross402/usdc-sdk-go"
)

func main() {
    // Public mode - no authentication required
    client, err := pay.NewClient("https://api-pay.agent.tech")
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()

    // Get settle proof from user's wallet (X402 payment)
    settleProof := getUserSignedProof()

    // Submit the proof
    proof, err := client.SubmitProof(ctx, intentID, settleProof)
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("Intent ID: %s", proof.IntentID)
    log.Printf("Status: %s", proof.Status)
    log.Printf("Message: %s", proof.Message)
}

Payment Flow

X402 Payment Process

  1. Create Intent: The caller initiates a payment with payer_chain and (optionally) target_chain.
  2. User Signs: The payer signs X402 payment off-chain via their wallet (EIP-3009 / Permit2 / Solana partial sign depending on payer chain).
  3. Get Proof: The wallet returns the signed settlement proof.
  4. Submit Proof: Submit the proof to Cross402 using this skill.
  5. Verification: Cross402 verifies the proof and settles on the payer chain.
  6. Target Settlement: Cross402 transfers the stablecoin to the merchant on the target chain.

Example Flow — base → Ethereum

// Step 1: Create intent
const intent = await client.createIntent({
  email: "merchant@example.com",
  amount: "100.50",
  payerChain: "base",
  targetChain: "ethereum",
});

// Step 2: User signs X402 payment (wallet interaction)
const settleProof = await signX402Payment(intent.intentId);

// Step 3: Submit proof
const result = await client.submitProof(intent.intentId, settleProof);

// Step 4: Poll for status (see query-intent-status.md)
// ...

Error Handling

Common Errors

HTTP Status Error Type Description Solution
400 ValidationError Empty intent ID or settle proof Provide valid intent ID and proof
400 ValidationError Invalid settle proof format Verify proof is correctly signed
404 RequestError Intent not found Verify intent ID exists
400 RequestError Proof verification failed Verify proof matches the intent
429 RequestError Rate limited Implement exponential backoff, retry after delay
503 RequestError Service unavailable Retry after delay

For comprehensive error handling patterns and retry strategies, see Error Handling.

Important Notes

  1. No Authentication Required: This is a public endpoint, safe for client-side use. There is no /v2 equivalent — submitProof belongs to the /api flow only. The Go SDK rejects SubmitProof with ErrSubmitProofNotAllowed when the client is configured with WithBearerAuth; the JS SDK does not expose submitProof on PayClient. If you've been driving payments via the authenticated flow, use executeIntent instead.
  2. X402 Payment: The settle proof must come from a valid X402 payment signed by the user's wallet.
  3. Proof Format: The settle proof is a string containing the signed payment data from the wallet (base64-encoded X402 v2 payload).
  4. Verification: Cross402 verifies the proof before processing. Invalid proofs result in VERIFICATION_FAILED status.
  5. Status Progression: PENDINGSOURCE_SETTLEDTARGET_SETTLINGTARGET_SETTLED.
  6. Polling: Use Query Intent Status to poll for status updates after submission.

Best Practices

  1. Client-Side Use: Use PublicPayClient (JavaScript/TypeScript) or public mode (Go) for client-side operations.
  2. Error Handling: Implement proper error handling for proof submission failures.
  3. Status Verification: After submission, poll the intent status to confirm processing.
  4. User Experience: Show loading states while proof is being verified and processed.
  5. Retry Logic: For transient errors (429, 503), implement retry with exponential backoff.