The Dodo Payments Rust library provides convenient access to the Dodo Payments REST API from applications written in Rust.
The REST API documentation can be found on docs.dodopayments.com. The full API of this library can be found in api.md.
cargo add dodopaymentsOr add it to your Cargo.toml manually:
[dependencies]
dodopayments = "1.109.0"
tokio = { version = "1", features = ["full"] }
serde_json = "1"Rust 1.75 or later.
The client reads your API key from the DODO_PAYMENTS_API_KEY environment variable by default:
use dodopayments::Client;
#[tokio::main]
async fn main() -> dodopayments::Result<()> {
let client = Client::from_env()?;
let result = client
.checkout_sessions()
.create()
.body(dodopayments::models::CheckoutSessionsCreateParams {
product_cart: Some(vec![dodopayments::models::ProductItemReq {
product_id: "product_id".to_string(),
quantity: 0,
addons: None,
amount: None,
credit_entitlements: None,
}]),
..Default::default()
})
.await?;
println!("{result:?}");
Ok(())
}You can also configure the client explicitly. Client::new returns a Result, so unwrap it with ? inside a function that returns dodopayments::Result:
use dodopayments::{Client, ClientConfig};
#[tokio::main]
async fn main() -> dodopayments::Result<()> {
let client = Client::new(ClientConfig::new("https://live.dodopayments.com").with_api_key("My API Key"))?;
println!("{}", client.base_url());
Ok(())
}List endpoints return a typed page whose items field holds the current page of results. Fetch the next page with get_next_page, or stream every item across all pages with into_stream:
use futures::StreamExt;
let mut items = Box::pin(client
.payments()
.list()
.query(serde_json::json!({}))
.await?.into_stream());
while let Some(item) = items.next().await {
let item = item?;
println!("{item:?}");
}Or advance one page at a time:
let mut page = client
.payments()
.list()
.query(serde_json::json!({}))
.await?;
loop {
for item in &page.items {
println!("{item:?}");
}
match page.get_next_page().await? {
Some(next) => page = next,
None => break,
}
}Every method returns a dodopayments::Result<T>. Failures are represented by the dodopayments::Error enum:
let result = client
.checkout_sessions()
.create()
.body(dodopayments::models::CheckoutSessionsCreateParams {
product_cart: Some(vec![dodopayments::models::ProductItemReq {
product_id: "product_id".to_string(),
quantity: 0,
addons: None,
amount: None,
credit_entitlements: None,
}]),
..Default::default()
})
.await;
match result {
Ok(value) => println!("{value:?}"),
Err(dodopayments::Error::Api { status, message }) => {
eprintln!("API returned {status}: {message}");
}
Err(err) => eprintln!("request failed: {err}"),
}The default request timeout is 30 seconds. Override it per client:
use std::time::Duration;
use dodopayments::{Client, ClientConfig};
let client = Client::new(
ClientConfig::new("https://live.dodopayments.com")
.with_api_key("My API Key")
.with_timeout(Duration::from_secs(60)),
)?;| Name | Base URL |
|---|---|
live_mode |
https://live.dodopayments.com |
test_mode |
https://test.dodopayments.com |
The default base URL is https://live.dodopayments.com. Select another environment with the Environment enum instead of hard-coding URLs:
use dodopayments::{Client, ClientConfig, Environment};
let client = Client::new(
ClientConfig::from_environment(Environment::TestMode).with_api_key("My API Key"),
)?;To keep reading the API key from DODO_PAYMENTS_API_KEY via from_env() while targeting a non-default environment, override it on the config:
use dodopayments::{Client, ClientConfig, Environment};
let client = Client::new(ClientConfig::from_env()?.with_environment(Environment::TestMode))?;Alternatively, Client::from_env() uses the default base URL unless you set the DODO_PAYMENTS_BASE_URL environment variable, e.g. DODO_PAYMENTS_BASE_URL=https://test.dodopayments.com to target test_mode.
To call an endpoint not yet exposed as a typed method, use the low-level request builder, which applies authentication and the base URL:
let response = client
.request(reqwest::Method::GET, "/some/path")
.send()
.await?;This package follows SemVer conventions. Breaking changes are released in major versions; minor and patch versions remain backwards compatible.
We take backwards compatibility seriously and work hard to ensure that breaking changes are clearly communicated in the changelog.