Async Stripe

Quick Start

Get up and running as quickly as possible.

Welcome to the async-stripe documentation. This library provides strongly-typed, safe, and performant Rust bindings for the Stripe API. It is designed to be modular, allowing you to pull in only the specific Stripe resources you need for your application.

Using an LLM? See llms-full.txt.

API Version

The current API version for async-stripe v1.0.0-alpha.8 is:

pub const VERSION: crate::ApiVersion = crate::ApiVersion::V2025_11_17_clover;

This means all API requests will use this version regardless of your Stripe account's default API version. This ensures consistent behavior and prevents breaking changes from affecting your application unexpectedly.

Compatibility

async-stripe is pinned to a specific Stripe API version. Each week, we sync against the official APIs and bump our types to match. It is critically important that you understand which version you're using, as mismatches between the library version and your expectations can lead to unexpected behavior, missing features, or parsing errors. As a result, you should when possible be regularly updating the both this library, and your Stripe account's api, to the latest available version.

We do not currently have the resources to backport fixes to older APIs.

Any webhooks received that to not match this version will publish a warning via tracing.

Quick Start

Here's a quick example of how to create a new Stripe Customer.

1. Add dependencies to your Cargo.toml

You'll need the main async-stripe crate for the client and a resource crate for the APIs you want to use (e.g., stripe-core for customers).


Here's a quick example of how to create a new Stripe Customer.

**1. Add dependencies to your `Cargo.toml`:**

2. Create a Customer

The new API uses a builder pattern that flows naturally from request creation to sending.

let customer = CreateCustomer::new()
    .name("Alexander Lyon")
    .email("test@async-stripe.com")
    .description("A fake customer that is used to illustrate the examples in async-stripe.")
    .metadata([(String::from("async-stripe"), String::from("true"))])
    .send(client)
    .await?;

Working with Expandable Fields

Many Stripe API responses contain related objects that are returned as IDs by default. You can use the expand parameter to request the full object instead. The library represents these fields using the Expandable<T> type.

Always Get the ID

Regardless of whether a field is expanded or not, you can always safely extract the ID:

use stripe::{Client, Charge};

let client = Client::new(secret_key);
let charge = Charge::retrieve(&client, &charge_id, &[]).await?;

// Works whether customer is an ID or expanded object
let customer_id = charge.customer.id();
println!("Customer ID: {}", customer_id);

Accessing the Expanded Object

When you expand a field, you can access the full object:

use stripe::{Client, Charge};

let client = Client::new(secret_key);

// Request the customer object to be expanded
let charge = Charge::retrieve(&client, &charge_id, &["customer"]).await?;

// Check if we got the full object
if let Some(customer) = charge.customer.as_object() {
    println!("Customer email: {:?}", customer.email);
} else {
    println!("Customer was not expanded");
}

Available Methods

The Expandable<T> enum provides several convenience methods:

  • .id() - Get the ID (always works, whether expanded or not)
  • .is_object() - Check if the field contains the full object
  • .as_object() - Get a reference to the object if available
  • .into_object() - Take ownership of the object if available
  • .into_id() - Take ownership of the ID

For more details on object expansion in the Stripe API, see the official documentation.

Known Limitations

Due to the current architecture of the OpenAPI generator, the following Stripe features are not yet supported by async-stripe:

File Uploads

Endpoints requiring multipart/form-data (e.g., uploading Identity verification documents or Dispute evidence) are not currently generated.

Workaround: Use a raw HTTP client like reqwest to upload files directly:

use reqwest::multipart;

let form = multipart::Form::new()
    .text("purpose", "dispute_evidence")
    .part("file", multipart::Part::bytes(file_data)
        .file_name("evidence.pdf")
        .mime_str("application/pdf")?);

let response = reqwest::Client::new()
    .post("https://files.stripe.com/v1/files")
    .bearer_auth(&secret_key)
    .multipart(form)
    .send()
    .await?;

Binary Downloads

Endpoints returning binary data (e.g., PDF invoices via /v1/invoices/:id/pdf) are not currently generated.

Workaround: Use a raw HTTP client to download binary content:

let response = reqwest::Client::new()
    .get(format!("https://api.stripe.com/v1/invoices/{}/pdf", invoice_id))
    .bearer_auth(&secret_key)
    .send()
    .await?;

let pdf_bytes = response.bytes().await?;
std::fs::write("invoice.pdf", pdf_bytes)?;

We're tracking these limitations and plan to add support in future releases. You can use async-stripe for the vast majority of Stripe operations alongside a raw HTTP client for these specific cases.

Have feedback? Let us know here