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

Configuration Reference

The server is configured programmatically – there are no config files. You set up payment rules, database connections, and server parameters in code. All configuration objects provide both Rust functions and Python bindings.

AppState

The shared application state accessible by every request handler. Holds the database connection, payment configuration, and server URL.

FieldTypeDescription
dbArc<dyn Database>Database backend (DuckDB, Postgres, ClickHouse)
payment_configArc<GlobalPaymentConfig>Global payment configuration
server_base_urlUrlServer’s public URL, used for binding and resource URLs in payment requirements

Construction

#![allow(unused)]
fn main() {
// Rust
let state = AppState {
    db: Arc::new(db),
    payment_config: Arc::new(config),
    server_base_url: Url::parse("http://0.0.0.0:4021").unwrap(),
};
}
# Python
state = AppState(database, payment_config, "http://0.0.0.0:4021")

Getters

GetterRustPythonReturns
Server base URLstate.server_base_url (pub field)state.server_base_urlUrl / str

Setters

SetterRustPython
Set server base URLstate.server_base_url = Url::parse("...").unwrap()state.set_server_base_url("http://0.0.0.0:4021")

FacilitatorClient

HTTP client for communicating with a remote x402 facilitator. Wraps a base URL and derives /verify, /settle, and /supported endpoints automatically.

Construction

#![allow(unused)]
fn main() {
// Rust
let facilitator = FacilitatorClient::try_from("https://facilitator.x402.rs")
    .expect("Failed to create facilitator client");
}
# Python
facilitator = FacilitatorClient("https://facilitator.x402.rs")

Getters

GetterRustPythonReturns
Base URLfacilitator.base_url()facilitator.base_url&Url / str
Verify URLfacilitator.verify_url()facilitator.verify_url&Url / str
Settle URLfacilitator.settle_url()facilitator.settle_url&Url / str
Headersfacilitator.headers()&HeaderMap
Timeoutfacilitator.timeout()facilitator.timeout_ms&Option<Duration> / Optional[int] (ms)

Setters

SetterRustPython
Set custom headersfacilitator.with_headers(header_map)facilitator.set_headers({"Authorization": "Bearer ..."})
Set timeoutfacilitator.with_timeout(Duration::from_millis(5000))facilitator.set_timeout(5000)

GlobalPaymentConfig

Central payment configuration shared across all request handlers. Holds the facilitator client, response format, timeout, and per-table pricing rules.

FieldTypeDefaultDescription
facilitatorArc<FacilitatorClient>Client for the x402 facilitator service
mime_typeStringapplication/vnd.apache.arrow.streamResponse MIME type
max_timeout_secondsu64300How long a payment offer remains valid
default_descriptionStringQuery execution paymentFallback description for tables without their own
offers_tablesHashMap<String, TablePaymentOffers>emptyPer-table payment configuration

Construction

All fields except facilitator are optional and fall back to sensible defaults.

#![allow(unused)]
fn main() {
// Rust - with defaults
let config = GlobalPaymentConfig::default(Arc::new(facilitator));

// Rust - with custom values
let config = GlobalPaymentConfig::new(
    Arc::new(facilitator),
    Some("text/csv".to_string()),       // mime_type
    Some(600),                           // max_timeout_seconds
    Some("Custom description".to_string()), // default_description
    None,                                // offers_tables (defaults to empty)
);
}
# Python - with defaults
config = GlobalPaymentConfig(facilitator)

# Python - with custom values
config = GlobalPaymentConfig(
    facilitator,
    mime_type="text/csv",
    max_timeout_seconds=600,
    default_description="Custom description",
)

Getters

GetterRustPythonReturns
MIME typeconfig.mime_type (pub field)config.mime_typeString / str
Max timeoutconfig.max_timeout_seconds (pub field)config.max_timeout_secondsu64 / int
Default descriptionconfig.default_description (pub field)config.default_descriptionString / str
Get table offersconfig.get_offers_table("table")Option<&TablePaymentOffers>
Table requires paymentconfig.table_requires_payment("table")config.table_requires_payment("table")Option<bool>

Setters

SetterRustPython
Set facilitatorconfig.set_facilitator(arc_client)config.set_facilitator(facilitator)
Set MIME typeconfig.set_mime_type("text/csv".to_string())config.set_mime_type("text/csv")
Set max timeoutconfig.set_max_timeout_seconds(600)config.set_max_timeout_seconds(600)
Set default descriptionconfig.set_default_description("...".to_string())config.set_default_description("...")
Add table offersconfig.add_offers_table(offer)config.add_offers_table(offer)

PriceTag

A single pricing tier for a table. Defines who gets paid, how much, and in which token. A table can have multiple price tags for tiered pricing. The pricing model (per-row or fixed) is specified via the pricing field.

FieldTypeDescription
pay_toChecksummedAddressRecipient wallet address
pricingPricingModelPer-row or fixed pricing (see below)
tokenEip155TokenDeploymentERC-20 token (chain, contract address, transfer method)
descriptionOption<String>Human-readable label for this tier
is_defaultboolWhether this is the default pricing tier

PricingModel

VariantFieldsDescription
PerRowamount_per_item, min_items, max_items, min_total_amountPrice scales with row count
FixedamountFlat fee regardless of row count

Construction (Per-Row)

#![allow(unused)]
fn main() {
// Rust
let price_tag = PriceTag {
    pay_to: ChecksummedAddress::from_str("0x...").unwrap(),
    pricing: PricingModel::PerRow {
        amount_per_item: TokenAmount(usdc.parse("0.002").unwrap().amount),
        min_total_amount: None,
        min_items: None,
        max_items: None,
    },
    token: usdc.clone(),
    description: None,
    is_default: true,
};
}
# Python — per-row pricing (constructor)
# amount_per_item accepts a string ("0.002") or int (2000) for smallest token units
price_tag = PriceTag(
    pay_to="0x...",
    amount_per_item="0.002",
    token=usdc,
    is_default=True,
)

Construction (Fixed)

#![allow(unused)]
fn main() {
// Rust
let price_tag = PriceTag {
    pay_to: ChecksummedAddress::from_str("0x...").unwrap(),
    pricing: PricingModel::Fixed {
        amount: TokenAmount(usdc.parse("1.00").unwrap().amount),
    },
    token: usdc.clone(),
    description: Some("Fixed price query".to_string()),
    is_default: true,
};
}
# Python — fixed pricing (static method)
price_tag = PriceTag.fixed(
    pay_to="0x...",
    fixed_amount="1.00",
    token=usdc,
    description="Fixed price query",
    is_default=True,
)

PriceTag is immutable after creation – create a new one to change values.


TablePaymentOffers

Groups the payment configuration for a single table: its pricing tiers, whether payment is required, and metadata shown to clients.

FieldTypeDescription
table_nameStringThe table this configuration applies to
price_tagsVec<PriceTag>Available pricing tiers
requires_paymentboolWhether queries require payment (derived from price tags)
descriptionOption<String>Description shown in root endpoint and 402 responses
schemaOption<Schema>Arrow schema for client discovery

Construction

#![allow(unused)]
fn main() {
// Rust - paid table
let offer = TablePaymentOffers::new("my_table".to_string(), vec![price_tag], Some(schema))
    .with_description("My dataset".to_string());

// Rust - free table
let free = TablePaymentOffers::new_free_table("public_table".to_string(), Some(schema));
}
# Python - paid table (description can be set at creation)
offer = TablePaymentOffers("my_table", [price_tag], schema=schema, description="My dataset")

# Python - free table
free = TablePaymentOffers.new_free_table("public_table", schema=schema, description="Public data")

Getters

GetterRustPythonReturns
Table nameoffer.table_name (pub field)offer.table_nameString / str
Requires paymentoffer.requires_payment (pub field)offer.requires_paymentbool
Descriptionoffer.description (pub field)offer.descriptionOption<String> / Optional[str]
Price tag countoffer.price_tags.len() (pub field)offer.price_tag_countusize / int
Price tag descriptionsiterate offer.price_tagsoffer.price_tag_descriptions– / List[Optional[str]]

Setters / Mutators

MethodRustPythonDescription
Set description.with_description(desc).with_description(desc)Set or replace the description
Add price tag.add_payment_offer(tag).add_payment_offer(tag)Add a pricing tier, sets requires_payment = true
Remove price tag.remove_price_tag(index).remove_price_tag(index)Remove by index, returns bool, updates requires_payment
Make free.make_free().make_free()Remove all price tags and set requires_payment = false

Tiered Pricing Example

Charge less per row for larger queries (per-row pricing):

#![allow(unused)]
fn main() {
// Default: $0.002/row for any query
let default_tier = PriceTag {...}

// Bulk: $0.001/row for queries returning 100+ rows
let bulk_tier = PriceTag {...}

let offer = TablePaymentOffers::new("my_table".to_string(), vec![default_tier], Some(schema))
    .add_payment_offer(bulk_tier);
}

The client receives both options in the 402 response and can choose the cheaper one.


Supported Networks

Currently supported USDC deployments:

NetworkRustPython
Base Sepolia (testnet)USDC::base_sepolia()USDC("base_sepolia")
BaseUSDC::base()USDC("base")
Avalanche Fuji (testnet)USDC::avalanche_fuji()USDC("avalanche_fuji")
AvalancheUSDC::avalanche()USDC("avalanche")
PolygonUSDC::polygon()USDC("polygon")
Polygon Amoy (testnet)USDC::polygon_amoy()USDC("polygon_amoy")