Configuration Reference
This page covers programmatic configuration via the Rust and Python SDKs. 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, server URL, bind address, and dashboards state.
| Field | Type | Description |
|---|---|---|
db | Arc<dyn Database> | Database backend (DuckDB, Postgres, ClickHouse) |
payment_config | Arc<RwLock<Arc<GlobalPaymentConfig>>> | Global payment configuration (wrapped in RwLock to support hot-reload) |
server_base_url | Url | Server’s public URL, used for building resource URLs in payment requirements (e.g. https://api.tiders.com) |
server_bind_address | String | Address and port the server binds to (e.g. 0.0.0.0:4021) |
dashboards | Arc<ArcSwap<DashboardsState>> | Configured dashboards (root path + per-slug entries). Lock-free swappable so the file watcher can update them without restarting |
dashboard_router | Arc<ArcSwap<Router>> | The currently mounted Axum sub-router for /<slug>/.... Atomically replaced when dashboards: changes |
AppState::new takes a DashboardsState. Pass an empty one if you don’t want dashboards — the API endpoints work the same either way.
Construction
#![allow(unused)]
fn main() {
// Rust
use std::path::PathBuf;
use tiders_x402_server::dashboard::DashboardsState;
let dashboards_state = DashboardsState {
root: PathBuf::new(),
dashboards: vec![],
};
let state = AppState::new(
db,
payment_config,
Url::parse("https://api.tiders.com").unwrap(),
"0.0.0.0:4021".to_string(),
dashboards_state,
);
}
# Python — dashboards configuration via SDK is not yet exposed; use the CLI for that.
state = AppState(database, payment_config, "https://api.tiders.com", "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
| Getter | Rust | Python | Returns |
|---|---|---|---|
| Base URL | facilitator.base_url() | facilitator.base_url | &Url / str |
| Verify URL | facilitator.verify_url() | facilitator.verify_url | &Url / str |
| Settle URL | facilitator.settle_url() | facilitator.settle_url | &Url / str |
| Headers | facilitator.headers() | – | &HeaderMap |
| Timeout | facilitator.timeout() | facilitator.timeout_ms | &Option<Duration> / Optional[int] (ms) |
Setters
| Setter | Rust | Python |
|---|---|---|
| Set custom headers | facilitator.with_headers(header_map) | facilitator.set_headers({"Authorization": "Bearer ..."}) |
| Set timeout | facilitator.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.
| Field | Type | Default | Description |
|---|---|---|---|
facilitator | Arc<FacilitatorClient> | – | Client for the x402 facilitator service |
mime_type | String | application/vnd.apache.arrow.stream | Response MIME type |
max_timeout_seconds | u64 | 300 | How long a payment offer remains valid |
default_description | String | Query execution payment | Fallback description for tables without their own |
offers_tables | HashMap<String, TablePaymentOffers> | empty | Per-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(facilitator);
// Rust - with custom values
let config = GlobalPaymentConfig::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
| Getter | Rust | Python | Returns |
|---|---|---|---|
| MIME type | config.mime_type (pub field) | config.mime_type | String / str |
| Max timeout | config.max_timeout_seconds (pub field) | config.max_timeout_seconds | u64 / int |
| Default description | config.default_description (pub field) | config.default_description | String / str |
| Get table offers | config.get_offers_table("table") | – | Option<&TablePaymentOffers> |
| Table requires payment | config.table_requires_payment("table") | config.table_requires_payment("table") | Option<bool> |
Setters
| Setter | Rust | Python |
|---|---|---|
| Set facilitator | config.set_facilitator(facilitator) | config.set_facilitator(facilitator) |
| Set MIME type | config.set_mime_type("text/csv".to_string()) | config.set_mime_type("text/csv") |
| Set max timeout | config.set_max_timeout_seconds(600) | config.set_max_timeout_seconds(600) |
| Set default description | config.set_default_description("...".to_string()) | config.set_default_description("...") |
| Add table offers | config.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, fixed, or metadata price) is specified via the pricing field.
| Field | Type | Description |
|---|---|---|
pay_to | ChecksummedAddress | Recipient wallet address |
pricing | PricingModel | Per-row or fixed pricing (see below) |
token | Eip155TokenDeployment | ERC-20 token (chain, contract address, transfer method) |
description | Option<String> | Human-readable label for this tier |
is_default | bool | Whether this is the default pricing tier |
PricingModel
| Variant | Fields | Description |
|---|---|---|
PerRow | amount_per_item, min_items, max_items, min_total_amount | Price scales with row count |
Fixed | amount | Flat fee regardless of row count |
MetadataPrice | amount | Flat fee for accessing table metadata via GET /api/table/{name} |
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,
)
Construction (Metadata Price)
#![allow(unused)]
fn main() {
// Rust
let price_tag = PriceTag {
pay_to: ChecksummedAddress::from_str("0x...").unwrap(),
pricing: PricingModel::MetadataPrice {
amount: TokenAmount(usdc.parse("1.00").unwrap().amount),
},
token: usdc.clone(),
description: Some("Metadata access fee".to_string()),
is_default: false,
};
}
# Python — metadata pricing (static method)
price_tag = PriceTag.metadata_price(
pay_to="0x...",
amount="1.00",
token=usdc,
description="Metadata access fee",
)
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.
| Field | Type | Description |
|---|---|---|
table_name | String | The table this configuration applies to |
price_tags | Vec<PriceTag> | Available pricing tiers |
requires_payment | bool | Whether queries require payment (derived from price tags) |
description | Option<String> | Description shown in root endpoint and 402 responses |
schema | Option<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
| Getter | Rust | Python | Returns |
|---|---|---|---|
| Table name | offer.table_name (pub field) | offer.table_name | String / str |
| Requires payment | offer.requires_payment (pub field) | offer.requires_payment | bool |
| Description | offer.description (pub field) | offer.description | Option<String> / Optional[str] |
| Price tag count | offer.price_tags.len() (pub field) | offer.price_tag_count | usize / int |
| Price tag descriptions | iterate offer.price_tags | offer.price_tag_descriptions | – / List[Optional[str]] |
Setters / Mutators
| Method | Rust | Python | Description |
|---|---|---|---|
| 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:
| Network | Rust | Python |
|---|---|---|
| Base Sepolia (testnet) | USDC::base_sepolia() | USDC("base_sepolia") |
| Base | USDC::base() | USDC("base") |
| Avalanche Fuji (testnet) | USDC::avalanche_fuji() | USDC("avalanche_fuji") |
| Avalanche | USDC::avalanche() | USDC("avalanche") |
| Polygon | USDC::polygon() | USDC("polygon") |
| Polygon Amoy (testnet) | USDC::polygon_amoy() | USDC("polygon_amoy") |