Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

sorocharge-x402

x402 protocol v2’s exact scheme on Stellar. Wire types and shapes are copied verbatim from x402-foundation/x402’s specs/schemes/exact/scheme_exact_stellar.md and specs/x402-specification-v2.md.

Client

X402Client

#![allow(unused)]
fn main() {
impl X402Client {
    pub fn new(request_timeout: std::time::Duration) -> Result<Self, X402Error>;

    pub async fn get_with_payment(
        &self,
        url: &str,
        signer: &dyn sorocharge_signer::Signer,
        network_passphrase: &str,
        current_ledger: u32,
    ) -> Result<reqwest::Response, X402Error>;
}
}

See Paying with x402.

Facilitator

Facilitator

#![allow(unused)]
fn main() {
impl<'a> Facilitator<'a> {
    pub fn new(
        rpc: &'a stellar_rpc_client::Client,
        signer: &'a dyn sorocharge_signer::Signer,
        network_passphrase: String,
        config: FacilitatorConfig,
    ) -> Self;

    pub async fn verify(&self, request: &VerifyRequest) -> Result<VerifyResponse, X402Error>;
    pub async fn settle(&self, request: &SettleRequest) -> Result<SettlementResponse, X402Error>;
    pub fn supported(&self) -> SupportedResponse;
}
}
#![allow(unused)]
fn main() {
pub struct FacilitatorConfig {
    pub max_transaction_fee_stroops: i64,  // default 50_000
    pub inclusion_buffer_stroops: i64,     // default 100 (the spec's required minimum)
}
}

SettleRequest is a type alias for VerifyRequest — the spec gives /settle the identical request shape as /verify. See Running an x402 facilitator.

Wire types

All of these derive Serialize/Deserialize with camelCase field names matching the spec exactly.

#![allow(unused)]
fn main() {
pub struct ResourceInfo { pub url: String, pub description: Option<String>, pub mime_type: Option<String> }

pub struct StellarExtra { pub are_fees_sponsored: bool }

pub struct PaymentRequirements {
    pub scheme: String,          // always "exact"
    pub network: String,         // "stellar:pubnet" | "stellar:testnet"
    pub amount: String,          // decimal string, base units
    pub asset: String,           // SEP-41 SAC contract (C...)
    pub pay_to: String,          // recipient account (G...)
    pub max_timeout_seconds: u64,
    pub extra: StellarExtra,
}

pub struct PaymentRequired {
    pub x402_version: u32,       // 2
    pub error: Option<String>,
    pub resource: ResourceInfo,
    pub accepts: Vec<PaymentRequirements>,
    pub extensions: serde_json::Map<String, serde_json::Value>,
}

pub struct StellarPayload { pub transaction: String }  // base64 TransactionEnvelope

pub struct PaymentPayload {
    pub x402_version: u32,
    pub resource: Option<ResourceInfo>,
    pub accepted: PaymentRequirements,
    pub payload: StellarPayload,
    pub extensions: serde_json::Map<String, serde_json::Value>,
}

pub struct VerifyRequest {
    pub x402_version: u32,
    pub payment_payload: PaymentPayload,
    pub payment_requirements: PaymentRequirements,
}

pub struct VerifyResponse {
    pub is_valid: bool,
    pub invalid_reason: Option<String>,
    pub payer: Option<String>,
}

pub struct SettlementResponse {
    pub success: bool,
    pub error_reason: Option<String>,
    pub payer: Option<String>,
    pub transaction: String,     // tx hash, or "" if none broadcast
    pub network: String,
    pub amount: Option<String>,
}

pub struct SupportedKind { pub x402_version: u32, pub scheme: String, pub network: String }
pub struct SupportedResponse {
    pub kinds: Vec<SupportedKind>,
    pub extensions: Vec<String>,
    pub signers: std::collections::BTreeMap<String, Vec<String>>,  // "stellar:*" -> addresses
}
}

Headers

HeaderDirectionContent
PAYMENT-REQUIREDServer → ClientBase64 JSON PaymentRequired
PAYMENT-SIGNATUREClient → ServerBase64 JSON PaymentPayload
PAYMENT-RESPONSEServer → ClientBase64 JSON SettlementResponse

X402Error

VariantMeaning
HttpRequestFailed { reason }The HTTP request itself failed.
UnexpectedStatus { status }Neither 402 nor 200.
MissingPaymentRequiredHeaderA 402 carried no PAYMENT-REQUIRED header.
InvalidPaymentRequired { reason }The header didn’t base64/JSON-decode.
NoAcceptablePaymentRequirementsNo accepts[] entry matches scheme + network.
UnsupportedNetwork { network }No CAIP-2 mapping for this network.
Signing(SorochargeError)sorocharge-signer failed to build or sign.
XdrEncodingFailed { reason } / XdrDecodingFailed { reason }XDR (de)serialization failed.
InvalidPaymentPayload { reason }The credential’s JSON didn’t match the expected shape.
UnexpectedTransactionShape { reason }Not a bare SEP-41 transfer — wrong op count, function, args, or a smuggled sub-invocation.
ForbiddenCredentialTypesorobanCredentialsSourceAccount or sorobanCredentialsAddressWithDelegates — the spec forbids both for this scheme.
FacilitatorAddressConflictThe facilitator’s own address appeared where the safety checks forbid it.
RpcFailed { reason }A Stellar RPC call failed.
FeeExceedsCeiling { fee_stroops, ceiling_stroops }The settlement-derived fee exceeded max_transaction_fee_stroops.
SettlementFailed { reason }Verified, but on-chain submission failed.