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
Return Value
Success Response
{
"intent_id": "int_abc123xyz",
"status": "PENDING",
"message": "Proof submitted successfully"
}
Status Values
PENDING: Proof submitted, verification in progressSOURCE_SETTLED: Payment confirmed on the payer chainTARGET_SETTLING: Settlement is being processed on the target chainTARGET_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
- Create Intent: The caller initiates a payment with
payer_chainand (optionally)target_chain. - User Signs: The payer signs X402 payment off-chain via their wallet (EIP-3009 / Permit2 / Solana partial sign depending on payer chain).
- Get Proof: The wallet returns the signed settlement proof.
- Submit Proof: Submit the proof to Cross402 using this skill.
- Verification: Cross402 verifies the proof and settles on the payer chain.
- 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
For comprehensive error handling patterns and retry strategies, see Error Handling.
Important Notes
- No Authentication Required: This is a public endpoint, safe for client-side use. There is no
/v2equivalent —submitProofbelongs to the/apiflow only. The Go SDK rejectsSubmitProofwithErrSubmitProofNotAllowedwhen the client is configured withWithBearerAuth; the JS SDK does not exposesubmitProofonPayClient. If you've been driving payments via the authenticated flow, useexecuteIntentinstead. - X402 Payment: The settle proof must come from a valid X402 payment signed by the user's wallet.
- Proof Format: The settle proof is a string containing the signed payment data from the wallet (base64-encoded X402 v2 payload).
- Verification: Cross402 verifies the proof before processing. Invalid proofs result in
VERIFICATION_FAILEDstatus. - Status Progression:
PENDING→SOURCE_SETTLED→TARGET_SETTLING→TARGET_SETTLED. - Polling: Use Query Intent Status to poll for status updates after submission.
Best Practices
- Client-Side Use: Use
PublicPayClient(JavaScript/TypeScript) or public mode (Go) for client-side operations. - Error Handling: Implement proper error handling for proof submission failures.
- Status Verification: After submission, poll the intent status to confirm processing.
- User Experience: Show loading states while proof is being verified and processed.
- Retry Logic: For transient errors (429, 503), implement retry with exponential backoff.