Skip to main content

ows_pay/
lib.rs

1//! `ows-pay` — payment client for the Open Wallet Standard.
2//!
3//! Chain-agnostic: works with any chain the wallet supports. Payment
4//! scheme dispatch (e.g. EVM "exact" / EIP-3009) is handled internally
5//! based on the x402 `scheme` field.
6//!
7//! ```ignore
8//! let result = ows_pay::pay(&wallet, "https://api.example.com/data", "GET", None).await?;
9//! let services = ows_pay::discover(None, None, None).await?;
10//! ```
11
12pub(crate) mod chains;
13pub(crate) mod discovery;
14pub mod error;
15pub mod fund;
16pub mod types;
17pub mod wallet;
18
19// Protocol implementations (internal).
20mod x402;
21
22pub use error::{PayError, PayErrorCode};
23pub use types::{DiscoverResult, PayResult, PaymentInfo, Protocol, Service};
24pub use wallet::{Account, WalletAccess};
25
26/// Make an HTTP request with automatic payment handling.
27///
28/// Fires the request. If the server returns 402, detects the payment
29/// protocol from the response and handles payment.
30pub async fn pay(
31    wallet: &dyn WalletAccess,
32    url: &str,
33    method: &str,
34    body: Option<&str>,
35) -> Result<PayResult, PayError> {
36    let client = reqwest::Client::new();
37
38    // Step 1: Fire the initial request.
39    let initial = x402::build_request(&client, url, method, body, None)?
40        .send()
41        .await?;
42
43    // Step 2: Not a 402 — return directly.
44    if initial.status().as_u16() != 402 {
45        let status = initial.status().as_u16();
46        let text = initial.text().await.unwrap_or_default();
47        return Ok(PayResult {
48            protocol: Protocol::X402,
49            status,
50            body: text,
51            payment: None,
52        });
53    }
54
55    // Step 3: Got a 402. Extract headers + body.
56    let headers = initial.headers().clone();
57    let body_402 = initial.text().await.unwrap_or_default();
58
59    // Step 4: Handle x402 payment.
60    x402::handle_x402(wallet, url, method, body, &headers, &body_402).await
61}
62
63/// Discover payable services.
64///
65/// Supports pagination via `limit` and `offset`. Returns services and
66/// pagination metadata so callers can page through the full directory.
67pub async fn discover(
68    query: Option<&str>,
69    limit: Option<u64>,
70    offset: Option<u64>,
71) -> Result<DiscoverResult, PayError> {
72    discovery::discover_all(query, limit, offset).await
73}