### Install and Run stripe-mock Directly Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/testing.mdx Install stripe-mock using Go and run it, specifying the HTTP port. ```bash # Or install directly go install github.com/stripe/stripe-mock@latest stripe-mock -http-port 12111 ``` -------------------------------- ### Run Development Server Source: https://github.com/arlyon/async-stripe/blob/master/site/README.md Use these commands to start the Next.js development server. Ensure you have Node.js installed and the project dependencies are set up. ```bash npm run dev # or pnpm dev # or yarn dev ``` -------------------------------- ### Install Project Tools with Mise Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/tooling.mdx Installs the project's pinned tools, such as the Rust toolchain, by reading the mise.toml file. ```bash mise install ``` -------------------------------- ### Create Customer Request (Before Migration) Source: https://github.com/arlyon/async-stripe/blob/master/MIGRATION.md Example of creating a customer using the older async-stripe structure. ```rust use stripe::{Client, CreateCustomer, Customer}; async fn create_customer(client: &Client) -> Result<(), stripe::Error> { let customer = Customer::create( &client, CreateCustomer { email: Some("test@async-stripe.com"), ..Default::default() }, ).await?; Ok(()) } ``` -------------------------------- ### Install Mise (MacOS/Linux) Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/tooling.mdx Installs Mise using a curl command. Follow the official guide for other operating systems. ```bash curl https://mise.run | sh ``` -------------------------------- ### Run stripe-mock with Docker Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/testing.mdx Start the stripe-mock server using Docker. This command maps port 12111 on your host to the container. ```bash # Using Docker (recommended) docker run -p 12111:12111 stripe/stripe-mock ``` -------------------------------- ### Run Stripe Mock and Tests Source: https://github.com/arlyon/async-stripe/blob/master/CONTRIBUTING.md Commands to start the stripe-mock server via Docker and execute tests with the blocking runtime feature. ```bash docker run --rm -d -it -p 12111-12112:12111-12112 stripe/stripe-mock:v0.197.0 cargo test --features runtime-blocking ``` -------------------------------- ### Create a Stripe Customer Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/index.mdx Example of creating a new Stripe Customer using the async-stripe library. It demonstrates the builder pattern for request creation and sending. ```rust use async_stripe::Client; use stripe_core::CreateCustomer; let client = Client::new(secret_key); let customer = CreateCustomer::default().send(&client).await?; println!("Created customer: {}", customer.id); ``` -------------------------------- ### Create Customer Request (After Migration) Source: https://github.com/arlyon/async-stripe/blob/master/MIGRATION.md Example of creating a customer after migrating to the new async-stripe 1.0 Alpha structure, utilizing modular crates. ```rust use stripe::Client; use stripe_core::customer::CreateCustomer; async fn create_customer(client: &Client) -> Result<(), stripe::Error> { let customer = CreateCustomer { email: Some("test@async-stripe.com"), ..Default::default() } .send(client) .await?; Ok(()) } ``` -------------------------------- ### Handle Webhook Event (Before Migration) Source: https://github.com/arlyon/async-stripe/blob/master/MIGRATION.md Example of handling webhook events using the older EventType and EventObject matching. ```rust use stripe::{EventType, EventObject}; fn handle_webhook_event(event: stripe::Event) { match event.type_ { EventType::CheckoutSessionCompleted => { if let EventObject::CheckoutSession(session) = event.data.object { println!("Checkout session completed! {session:?}"); } else { // How should we handle an unexpected object for this event type? println!("Unexpected object for checkout event"); } } _ => {}, } } ``` -------------------------------- ### Configure Stripe Request Strategies (Idempotency, Retries) Source: https://context7.com/arlyon/async-stripe/llms.txt This example shows how to configure request strategies globally on the client or per-request for idempotency and retries. It covers setting up default idempotency with UUIDs, custom idempotency keys, and retry strategies including exponential backoff. ```rust use stripe::{Client, ClientBuilder, IdempotencyKey, RequestStrategy, StripeError, StripeRequest}; use stripe_core::customer::CreateCustomer; use stripe_core::payment_intent::CreatePaymentIntent; use stripe_types::Currency; async fn request_strategy_examples() -> Result<(), StripeError> { let secret_key = std::env::var("STRIPE_SECRET_KEY").unwrap(); // Global strategy: all requests will use idempotency keys let client = ClientBuilder::new(&secret_key) .request_strategy(RequestStrategy::idempotent_with_uuid()) .build()?; // Per-request override: retry up to 5 times let customer = CreateCustomer::new() .name("Retry Customer") .customize() .request_strategy(RequestStrategy::Retry(5)) .send(&client) .await?; // Custom idempotency key (useful for order-based deduplication) let order_id = "order_12345"; let key = IdempotencyKey::new(order_id).unwrap(); let payment = CreatePaymentIntent::new(5000, Currency::USD) .customize() .request_strategy(RequestStrategy::Idempotent(key)) .send(&client) .await?; // Exponential backoff: retries with increasing delays (2s, 4s, 8s...) let payment = CreatePaymentIntent::new(5000, Currency::USD) .customize() .request_strategy(RequestStrategy::ExponentialBackoff(3)) .send(&client) .await?; println!("Created payment with backoff strategy: {}", payment.id); Ok(()) } ``` -------------------------------- ### Add async-stripe Dependencies Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/index.mdx Add the main async-stripe crate and resource-specific crates to your Cargo.toml file. This example includes dependencies for the core client and customer resources. ```toml [dependencies] async-stripe = "0.7.0" stripe-core = { version = "0.7.0", features = ["macros"] } ``` -------------------------------- ### Conventional Commit Message Examples Source: https://github.com/arlyon/async-stripe/blob/master/RELEASE.md Examples of conventional commit messages used for version detection in the release process. Use 'feat:' for minor bumps, 'fix:' for patch bumps, and 'feat!:' or 'BREAKING CHANGE:' for major bumps. ```git feat(types): add cryptocurrency payment methods fix(webhook): resolve signature validation timing feat(client)!: change async API to use new error types ``` -------------------------------- ### GET /v1/invoices/:id/pdf (Binary Download Workaround) Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/index.mdx Workaround for downloading binary data like PDF invoices using a raw HTTP client. ```APIDOC ## GET /v1/invoices/:id/pdf ### Description Downloads a PDF invoice. Since binary response handling is not supported by the generated client, use a raw HTTP client. ### Method GET ### Endpoint https://api.stripe.com/v1/invoices/{invoice_id}/pdf ### Parameters #### Path Parameters - **invoice_id** (string) - Required - The ID of the invoice to download. ``` -------------------------------- ### Handle Webhook Event (After Migration) Source: https://github.com/arlyon/async-stripe/blob/master/MIGRATION.md Example of handling webhook events after migration, leveraging explicit webhook object types for direct destructuring. ```rust use stripe_webhook::{Event, EventObject}; fn handle_webhook_event(event: stripe::Event) { match event.data.object { EventObject::CheckoutSessionCompleted(session) => { println!("Checkout session completed! {session:?}"); } _ => {}, } } ``` -------------------------------- ### Paginate Stripe Resources with a Stream Source: https://github.com/arlyon/async-stripe/blob/master/README.md Use the `.paginate()` method on a `List*` request struct to obtain a stream of results. This example demonstrates iterating through customers. ```rust use stripe_core::customer::ListCustomer; use futures_util::TryStreamExt; async fn run(client: &stripe::Client) -> Result<(), stripe::StripeError> { let mut stream = ListCustomer::new().paginate().stream(client); while let Some(customer) = stream.try_next().await? { println!("Got customer: {}", customer.id); } Ok(()) } ``` -------------------------------- ### Rust Struct for IssuingAuthorization Source: https://github.com/arlyon/async-stripe/blob/master/openapi/README.md Completes the cyclic dependency example by showing a struct that references a type which may eventually lead back to the struct itself, necessitating careful crate organization. ```rust pub struct IssuingAuthorization { // Many fields pub balance_transactions: Vec, // Many fields } ``` -------------------------------- ### Create Stripe Connect Account and Onboarding Link Source: https://context7.com/arlyon/async-stripe/llms.txt This snippet demonstrates creating an Express Connect account and generating an onboarding link. Ensure you have the necessary Stripe SDK dependencies and a valid client. ```rust use stripe::Client; use stripe_connect::account::{ CreateAccount, CreateAccountType, CapabilitiesParam, CapabilityParam, }; use stripe_connect::account_link::{CreateAccountLink, CreateAccountLinkType}; async fn create_connect_account(client: &Client) -> Result<(), stripe::StripeError> { // Create a Connect Express account let account = CreateAccount::new() .type_(CreateAccountType::Express) .capabilities(CapabilitiesParam { card_payments: Some(CapabilityParam { requested: Some(true) }), transfers: Some(CapabilityParam { requested: Some(true) }), ..Default::default() }) .send(client) .await?; println!("Created Connect account: {}", account.id); // Generate onboarding link let link = CreateAccountLink::new(account.id, CreateAccountLinkType::AccountOnboarding) .refresh_url("https://example.com/connect/refresh") .return_url("https://example.com/connect/return") .send(client) .await?; println!("Onboarding URL: {}", link.url); // Output: Onboarding URL: https://connect.stripe.com/setup/e/xxxxx Ok(()) } ``` -------------------------------- ### Workspace Settings for release-plz Source: https://github.com/arlyon/async-stripe/blob/master/RELEASE.md Configure workspace-level settings for release-plz, including enabling semver checks, changelog updates, and dependency updates. ```toml [workspace] semver_check = true # Enable cargo-semver-checks for API analysis changelog_update = true # Single workspace-level changelog dependencies_update = true # Auto-update dependency versions ``` -------------------------------- ### Commit Generated Code Changes Source: https://github.com/arlyon/async-stripe/blob/master/CONTRIBUTING.md Example of a conventional commit message for updating the generated code. ```text feat(codegen): update to latest Stripe OpenAPI spec ``` -------------------------------- ### Create Product and Price in Rust Source: https://context7.com/arlyon/async-stripe/llms.txt This snippet demonstrates how to create a product and then associate both one-time and recurring prices with it. This is useful for setting up items for sale in Stripe. ```rust use stripe::{Client, StripeError}; use stripe_product::product::CreateProduct; use stripe_product::price::{CreatePrice, CreatePriceRecurring, CreatePriceRecurringInterval}; use stripe_types::Currency; async fn create_product_and_price(client: &Client) -> Result<(), StripeError> { // Create a product let product = CreateProduct::new("Premium T-Shirt") .description("A high-quality cotton t-shirt") .metadata([(String::from("category"), String::from("apparel"))]) .send(client) .await?; println!("Created product: {:?}", product.name); // Create a one-time price let one_time_price = CreatePrice::new(Currency::USD) .product(product.id.as_str()) .unit_amount(2500) // $25.00 in cents .send(client) .await?; println!("One-time price: {} cents", one_time_price.unit_amount.unwrap()); // Create a recurring price (for subscriptions) let recurring_price = CreatePrice::new(Currency::USD) .product(product.id.as_str()) .unit_amount(999) // $9.99/month .recurring(CreatePriceRecurring::new(CreatePriceRecurringInterval::Month)) .send(client) .await?; println!("Recurring price: {} cents per {:?}", recurring_price.unit_amount.unwrap(), recurring_price.recurring.as_ref().unwrap().interval ); Ok(()) } ``` -------------------------------- ### Create a Stripe Customer with async-stripe Source: https://github.com/arlyon/async-stripe/blob/master/README.md Initialize the Stripe client with your secret key and use the builder pattern to create a new customer. Ensure the STRIPE_SECRET_KEY environment variable is set. ```rust use stripe::Client; use stripe_core::customer::CreateCustomer; #[tokio::main] async fn main() -> Result<(), Box> { // 1. Initialize the client let secret_key = std::env::var("STRIPE_SECRET_KEY").expect("Missing STRIPE_SECRET_KEY in env"); let client = Client::new(secret_key); // 2. Create a customer using the builder pattern 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?; println!("Successfully created customer: {} ({})", customer.name.unwrap_or_default(), customer.id); Ok(()) } ``` -------------------------------- ### Configure Client with ClientBuilder Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/configuration.mdx Advanced configuration for headers, application information, and Connect account masquerading. ```rust let client = ClientBuilder::new("sk_test_...") .set_app_info(AppInfo { name: "my-app".to_string(), version: Some("1.0.0".to_string()), url: None, partner_id: None, }) .set_connect_account("acct_...") .build(); ``` -------------------------------- ### Initialize Stripe Client Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/configuration.mdx Basic client initialization using a secret key and default settings. ```rust let client = Client::new("sk_test_..."); ``` -------------------------------- ### Create a Checkout Session in Rust Source: https://context7.com/arlyon/async-stripe/llms.txt Uses the async-stripe library to create a customer, product, price, and a checkout session. Demonstrates expanding nested fields like line items and product details. ```rust use stripe::{Client, StripeError}; use stripe_checkout::CheckoutSessionMode; use stripe_checkout::checkout_session::{CreateCheckoutSession, CreateCheckoutSessionLineItems}; use stripe_core::customer::CreateCustomer; use stripe_product::price::CreatePrice; use stripe_product::product::CreateProduct; use stripe_types::{Currency, Expandable}; async fn create_checkout_session(client: &Client) -> Result<(), StripeError> { // Create customer, product, and price let customer = CreateCustomer::new() .email("customer@example.com") .send(client) .await?; let product = CreateProduct::new("T-Shirt") .send(client) .await?; let price = CreatePrice::new(Currency::USD) .product(product.id.as_str()) .unit_amount(1000) // $10.00 .expand([String::from("product")]) .send(client) .await?; // Create checkout session with line items let line_items = vec![CreateCheckoutSessionLineItems { quantity: Some(3), price: Some(price.id.to_string()), ..Default::default() }]; let checkout_session = CreateCheckoutSession::new() .customer(customer.id.as_str()) .mode(CheckoutSessionMode::Payment) .line_items(line_items) .success_url("https://example.com/success?session_id={CHECKOUT_SESSION_ID}") .cancel_url("https://example.com/cancel") .expand([ String::from("line_items"), String::from("line_items.data.price.product") ]) .send(client) .await?; // Access expanded data let line_item = &checkout_session.line_items .expect("line_items expanded") .data[0]; let product_name = match &line_item.price.as_ref().unwrap().product { Expandable::Object(p) => p.name.clone(), Expandable::Id(id) => Some(format!("Product {}", id)), }; println!("Checkout session created for {} x {:?}", line_item.quantity.unwrap(), product_name ); println!("Redirect URL: {}", checkout_session.url.unwrap()); Ok(()) } ``` -------------------------------- ### Paginate List Customers Before Source: https://github.com/arlyon/async-stripe/blob/master/MIGRATION.md Before the migration, obtaining a paginable stream required a separate request for the first page. ```rust let params = ListCustomers::new(); let mut stream = Customer::list(&client, ¶ms).await?.paginate(params); ``` -------------------------------- ### Package-Specific Settings for release-plz Source: https://github.com/arlyon/async-stripe/blob/master/RELEASE.md Define package-specific settings for release-plz, such as publish features for the main async-stripe library. ```toml [[package]] name = "async-stripe" publish_features = ["runtime-tokio-hyper"] # Main library features ``` -------------------------------- ### Get Customer ID from Expandable Field Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/index.mdx This Rust code demonstrates how to always retrieve the customer ID from a `Charge` object, regardless of whether the customer field is expanded or just an ID. ```rust 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); ``` -------------------------------- ### Axum Webhook Handling with Extractor Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/webhooks.mdx Example of handling webhooks in an Axum application using a custom `StripeEvent` extractor for automatic signature verification, body extraction, and event parsing. Returns a 400 Bad Request if verification fails. ```rust use async_stripe::webhook::StripeEvent; use axum::{extract::State, routing::post, Router}; use std::sync::Arc; #[derive(Clone)] struct AppState { /* ... */ } async fn webhook_handler(State(state): State>, StripeEvent(event): StripeEvent) -> impl IntoResponse { // Handle the event match event.data.object { // ... } StatusCode::OK } let app = Router::new() .route("/stripe_webhooks", post(webhook_handler)) .with_state(Arc::new(AppState { /* ... */ })); ``` -------------------------------- ### Manual Customer Pagination Control Source: https://context7.com/arlyon/async-stripe/llms.txt Implements manual cursor-based pagination for listing customers, allowing finer control by explicitly managing the `starting_after` parameter to iterate through pages. ```rust use stripe::Client; use stripe_core::customer::ListCustomer; async fn manual_pagination(client: &Client) -> Result<(), stripe::StripeError> { let mut params = ListCustomer::new().limit(10); loop { let page = params.send(client).await?; if page.data.is_empty() { break; } for customer in &page.data { println!("Customer ID: {}", customer.id); } // Check if there are more pages if !page.has_more { break; } // Set cursor for next page using the last customer's ID if let Some(last) = page.data.last() { params = params.starting_after(last.id.as_str()); } } Ok(()) } ``` -------------------------------- ### Configure Stripe Client with App Info and Account ID Source: https://github.com/arlyon/async-stripe/blob/master/site/snapshots/examples_endpoints_src_client_config.rs_L12-21.txt Initializes the Stripe client using an environment variable for the secret key and configures application metadata and account masquerading. ```rust let secret_key = std::env::var("STRIPE_SECRET_KEY").expect("Missing STRIPE_SECRET_KEY in env"); let client = ClientBuilder::new(secret_key) // Identify your app to Stripe (useful for analytics and support) .app_info("MyApp", Some("1.0.0".to_string()), Some("https://myapp.com".to_string())) // Acts as this connected account (Stripe Connect) .account_id(stripe::AccountId::from("acct_12345")) .build()?; println!("Client configured with app info and account masquerading"); ``` -------------------------------- ### Manual Pagination with Cursors in Rust Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/pagination.mdx Handle pagination manually by passing the starting_after parameter to List request structs. ```rust let mut last_id = None; let mut all_customers = Vec::new(); loop { let mut params = stripe::ListCustomers::new(); if let Some(id) = last_id { params.starting_after = Some(id); } let list = stripe::Customer::list(&client, params).await?; let has_more = list.has_more; if let Some(last) = list.data.last() { last_id = Some(last.id.clone()); } all_customers.extend(list.data); if !has_more { break; } } ``` -------------------------------- ### Create Stripe Subscription with Rust Source: https://context7.com/arlyon/async-stripe/llms.txt Creates a recurring subscription for a customer, including setting up a customer, payment method, product, and price. Requires a Stripe client and necessary imports. ```rust use stripe::{Client, StripeError}; use stripe_billing::subscription::{CreateSubscription, CreateSubscriptionItems}; use stripe_core::customer::CreateCustomer; use stripe_payment::payment_method::{ AttachPaymentMethod, CreatePaymentMethod, CreatePaymentMethodCard, CreatePaymentMethodCardDetailsParams, CreatePaymentMethodType, }; use stripe_product::price::{CreatePrice, CreatePriceRecurring, CreatePriceRecurringInterval}; use stripe_product::product::CreateProduct; use stripe_types::{Currency, Expandable}; async fn create_subscription(client: &Client) -> Result<(), StripeError> { // Create customer with payment method let customer = CreateCustomer::new() .name("Subscriber") .email("subscriber@example.com") .send(client) .await?; let payment_method = CreatePaymentMethod::new() .type_(CreatePaymentMethodType::Card) .card(CreatePaymentMethodCard::CardDetailsParams( CreatePaymentMethodCardDetailsParams { number: String::from("4242424242424242"), exp_year: 2026, exp_month: 12, cvc: Some(String::from("123")), networks: None, } )) .send(client) .await?; AttachPaymentMethod::new(payment_method.id.clone()) .customer(&customer.id) .send(client) .await?; // Create product and recurring price let product = CreateProduct::new("Monthly Subscription Box") .send(client) .await?; let price = CreatePrice::new(Currency::USD) .product(&product.id) .unit_amount(1999) // $19.99/month .recurring(CreatePriceRecurring::new(CreatePriceRecurringInterval::Month)) .send(client) .await?; // Create the subscription let subscription = CreateSubscription::new() .customer(customer.id) .items(vec![CreateSubscriptionItems { price: Some(price.id.to_string()), quantity: Some(1), ..Default::default() }]) .default_payment_method(&payment_method.id) .expand([ String::from("items"), String::from("items.data.price.product"), ]) .send(client) .await?; // Access expanded subscription data let item = &subscription.items.data[0]; let product_name = match &item.price.product { Expandable::Object(p) => &p.name, _ => &None, }; println!("Created subscription: {} - Status: {}", subscription.id, subscription.status ); println!("Product: {:?} at {} cents/{:?}", product_name, item.price.unit_amount.unwrap(), item.price.recurring.as_ref().unwrap().interval ); Ok(()) } ``` -------------------------------- ### Add Async-Stripe with Tokio-Hyper Runtime Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/architecture.mdx Include the main async-stripe client with the tokio-hyper runtime enabled. This is the primary entry point for the HTTP transport, authentication, and configuration. ```toml [dependencies] async-stripe = { version = "1.0.0-rc.0", features = ["runtime-tokio-hyper"] } ``` -------------------------------- ### Initialize Stripe Client in Rust Source: https://github.com/arlyon/async-stripe/blob/master/site/snapshots/examples_pagination_src_main.rs_L7-8.txt Retrieves the STRIPE_SECRET_KEY from environment variables and initializes the client. Ensure the environment variable is set before execution to avoid a panic. ```rust let secret_key = std::env::var("STRIPE_SECRET_KEY").expect("Missing STRIPE_SECRET_KEY in env"); let client = Client::new(secret_key); ``` -------------------------------- ### Create Stripe Customer in Rust Source: https://github.com/arlyon/async-stripe/blob/master/site/snapshots/examples_endpoints_src_customer.rs_L14-20.txt Use this snippet to create a new customer in Stripe asynchronously. Ensure you have an initialized `client` and handle potential errors with `?`. ```rust 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?; ``` -------------------------------- ### Configure Stripe Client with ClientBuilder Source: https://context7.com/arlyon/async-stripe/llms.txt Advanced client configuration using ClientBuilder, including setting request strategies, application information, and targeting specific Connect accounts. ```rust use stripe::{Client, ClientBuilder, RequestStrategy}; use stripe_shared::AccountId; #[tokio::main] async fn main() -> Result<(), stripe::StripeError> { let secret_key = std::env::var("STRIPE_SECRET_KEY") .expect("Missing STRIPE_SECRET_KEY in env"); let client = ClientBuilder::new(secret_key) // Set default retry strategy with idempotency .request_strategy(RequestStrategy::idempotent_with_uuid()) // Identify your application to Stripe .app_info("MyApp", Some("1.0.0".to_string()), Some("https://myapp.com".to_string())) // Target a specific Connect account for all requests .account_id(AccountId::from("acct_123")) .build()?; Ok(()) } ``` -------------------------------- ### Configure Stripe Client with Idempotent Strategy Source: https://github.com/arlyon/async-stripe/blob/master/site/snapshots/examples_endpoints_src_strategy.rs_L10-20.txt Use this to initialize the Stripe client with an idempotent request strategy. Ensure the STRIPE_SECRET_KEY environment variable is set. ```rust let secret_key = std::env::var("STRIPE_SECRET_KEY").expect("Missing STRIPE_SECRET_KEY in env"); let client = ClientBuilder::new(secret_key) .request_strategy(RequestStrategy::idempotent_with_uuid()) .build()?; let first_page = ListCustomer::new().send(&client).await?; println!( "first page of customers: {:#?}", first_page.data.iter().map(|c| c.name.as_ref().unwrap()).collect::>() ); Ok(()) ``` -------------------------------- ### Create and Confirm a Payment Intent in Rust Source: https://context7.com/arlyon/async-stripe/llms.txt This snippet shows the full flow of creating a payment intent, including customer and payment method creation and attachment, followed by confirmation. Ensure the Stripe client is properly initialized before use. ```rust use stripe::{Client, StripeError}; use stripe_core::customer::CreateCustomer; use stripe_core::payment_intent::{CreatePaymentIntent, UpdatePaymentIntent, ConfirmPaymentIntent}; use stripe_payment::payment_method::{ CreatePaymentMethod, CreatePaymentMethodCard, CreatePaymentMethodCardDetailsParams, CreatePaymentMethodType, AttachPaymentMethod, }; use stripe_types::Currency; async fn create_and_confirm_payment(client: &Client) -> Result<(), StripeError> { // 1. Create a customer let customer = CreateCustomer::new() .name("John Doe") .email("john@example.com") .send(client) .await?; // 2. Create a payment intent let payment_intent = CreatePaymentIntent::new(1000, Currency::USD) // Amount in cents .payment_method_types([String::from("card")]) .statement_descriptor("Purchase from MyStore") .metadata([("order_id".to_string(), "order_12345".to_string())]) .send(client) .await?; println!("Created payment intent: {} with status '{}'", payment_intent.id, payment_intent.status ); // 3. Create and attach a payment method (test card) let payment_method = CreatePaymentMethod::new() .type_(CreatePaymentMethodType::Card) .card(CreatePaymentMethodCard::CardDetailsParams( CreatePaymentMethodCardDetailsParams { number: String::from("4242424242424242"), // Test card exp_year: 2026, exp_month: 12, cvc: Some(String::from("123")), networks: None, } )) .send(client) .await?; AttachPaymentMethod::new(payment_method.id.clone()) .customer(&customer.id) .send(client) .await?; // 4. Update the payment intent with customer and payment method let payment_intent = UpdatePaymentIntent::new(payment_intent.id) .payment_method(payment_method.id.as_str()) .customer(customer.id.as_str()) .send(client) .await?; // 5. Confirm the payment let payment_intent = ConfirmPaymentIntent::new(payment_intent.id) .send(client) .await?; println!("Payment completed with status: {}", payment_intent.status); // Output: Payment completed with status: succeeded Ok(()) } ``` -------------------------------- ### Paginate List Customers After Source: https://github.com/arlyon/async-stripe/blob/master/MIGRATION.md After the migration, `paginate` can be called directly on `List*` parameters, and the stream can be obtained more directly. ```rust let mut stream = ListAccount::new().paginate().stream(&client) ``` -------------------------------- ### List All Customers with Automatic Pagination Source: https://context7.com/arlyon/async-stripe/llms.txt Iterates through all customers using the `.paginate().stream()` pattern, which handles pagination internally and yields customers one at a time. Alternatively, all customers can be collected into a `Vec`. ```rust use stripe::Client; use stripe_core::customer::ListCustomer; use futures_util::{StreamExt, TryStreamExt}; async fn list_all_customers(client: &Client) -> Result<(), stripe::StripeError> { // Create a stream that automatically handles pagination let mut stream = ListCustomer::new().paginate().stream(client); // Process customers one at a time while let Some(customer) = stream.try_next().await? { println!("Customer: {} - {}", customer.id, customer.email.unwrap_or_default() ); } // Or collect all customers into a Vec let mut stream = ListCustomer::new().paginate().stream(client); let all_customers: Vec<_> = stream.try_collect().await?; println!("Total customers: {}", all_customers.len()); Ok(()) } ``` -------------------------------- ### Add async-stripe Dependencies to Cargo.toml Source: https://github.com/arlyon/async-stripe/blob/master/README.md Specify the main async-stripe crate and resource crates, along with the tokio runtime, in your Cargo.toml file. ```toml [dependencies] async-stripe = "=1.0.0-rc.5" async-stripe-core = { version = "=1.0.0-rc.5", features = ["customer"] } tokio = { version = "1", features = ["full"] } ``` -------------------------------- ### Run the Generator CLI Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/codegen.mdx Execute the generator from the openapi directory to fetch the latest specification and regenerate the library code. ```bash cd openapi # Fetches the latest spec from GitHub and regenerates code cargo run --release -- --fetch latest ``` -------------------------------- ### Configure Stripe Client with stripe-mock Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/testing.mdx Configure the Stripe client to use stripe-mock for local testing. Ensure stripe-mock is running on the specified port. ```rust use stripe::Client; // Start stripe-mock on port 12111 // docker run -p 12111:12111 stripe/stripe-mock let client = Client::builder("sk_test_123") .url("http://localhost:12111") .build(); // This request will hit stripe-mock instead of the real API let customer = Customer::create(&client, CreateCustomer::new()).send().await?; ``` -------------------------------- ### Paginate Stripe Customers in Rust Source: https://github.com/arlyon/async-stripe/blob/master/site/snapshots/examples_pagination_src_main.rs_L9-18.txt Use the `ListCustomer` builder to create a paginator and stream customer data. This snippet shows how to fetch a single item or collect all items from the stream. ```rust let paginator = ListCustomer::new().paginate(); let mut stream = paginator.stream(&client); // take a value out from the stream if let Some(val) = stream.try_next().await? { println!("GOT = {val:?}"); } // alternatively, you can use stream combinators let _ = stream.try_collect::>().await?; ``` -------------------------------- ### Configure Cargo.toml for async-stripe Source: https://github.com/arlyon/async-stripe/blob/master/site/content/files/MIGRATION.md Update dependencies to reflect the new modular crate structure and feature-gated request objects. ```toml async-stripe = { version = "0.28", features = ["runtime-tokio-hyper", "core"] } ``` ```toml async-stripe = { version = "TBD", features = ["runtime-tokio-hyper"] } # Note the addition of the `customer` feature as well - each object in the Stripe API # now has its related requests feature-gated. stripe-core = { version = "TBD", features = ["runtime-tokio-hyper", "customer"] } ``` -------------------------------- ### Create a Stripe Test Clock Source: https://github.com/arlyon/async-stripe/blob/master/site/snapshots/examples_endpoints_src_test-clocks.rs_L17-25.txt Uses the TestHelpersTestClock::create method to initialize a test clock with a specific frozen time and name. Ensure the client is authenticated and the timestamp is provided as an i64. ```rust let test_clock_1 = stripe::TestHelpersTestClock::create( &client, &CreateTestClock { frozen_time: timestamp as i64, name: "Example test clock 1" }, ) .await .unwrap(); assert_eq!(test_clock_1.status, Some(TestHelpersTestClockStatus::Ready)); println!("created a test clock at https://dashboard.stripe.com/test/billing/subscriptions/test-clocks/{}", test_clock_1.id); ``` -------------------------------- ### Add Stripe Core Resources to Dependencies Source: https://github.com/arlyon/async-stripe/blob/master/README.md Include the `stripe-core` crate in your `Cargo.toml` and enable features for specific resources like 'customer' and 'charge'. ```toml [dependencies] stripe-core = { version = "...", features = ["customer", "charge"] } ``` -------------------------------- ### Download binary files using reqwest Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/index.mdx Use this workaround to fetch binary data like PDF invoices, as the library does not currently generate endpoints for these responses. ```rust 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)?; ``` -------------------------------- ### Create Stripe Payment Link with Rust Source: https://context7.com/arlyon/async-stripe/llms.txt Generates a Stripe payment link for a product, which can be shared for direct payment collection without requiring a pre-existing customer. Requires a Stripe client and necessary imports. ```rust use stripe::{Client, StripeError}; use stripe_payment::payment_link::{CreatePaymentLink, CreatePaymentLinkLineItems}; use stripe_product::price::CreatePrice; use stripe_product::product::CreateProduct; use stripe_types::Currency; async fn create_payment_link(client: &Client) -> Result<(), StripeError> { // Create product and price let product = CreateProduct::new("Digital Course") .send(client) .await?; let price = CreatePrice::new(Currency::USD) .product(product.id.as_str()) .unit_amount(4999) // $49.99 .send(client) .await?; // Create payment link let payment_link = CreatePaymentLink::new(&[CreatePaymentLinkLineItems { price: Some(price.id.to_string()), quantity: 1, adjustable_quantity: None, price_data: None, }]) .send(client) .await?; println!("Payment link created: {}", payment_link.url); // Output: Payment link created: https://buy.stripe.com/xxxxx Ok(()) } ``` -------------------------------- ### Enable Specific Features for Stripe Core Resources Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/architecture.mdx Add the stripe-core crate and enable features for specific objects like 'customer' and 'balance'. This allows for granular control over compiled code. ```toml stripe-core = { version = "1.0.0-rc.0", features = ["customer", "balance"] } ``` -------------------------------- ### POST /v1/files (File Upload Workaround) Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/index.mdx Workaround for uploading files using a raw HTTP client as multipart/form-data is not natively supported. ```APIDOC ## POST /v1/files ### Description Uploads a file to Stripe. Since multipart/form-data is not supported by the generated client, use a raw HTTP client like reqwest. ### Method POST ### Endpoint https://files.stripe.com/v1/files ### Request Example ```rust let form = multipart::Form::new() .text("purpose", "dispute_evidence") .part("file", multipart::Part::bytes(file_data) .file_name("evidence.pdf") .mime_str("application/pdf")?); ``` ``` -------------------------------- ### Create a Test Clock Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/testing.mdx Create a Stripe Test Clock frozen at a specific Unix timestamp. Test clocks are essential for testing time-sensitive subscription logic. ```rust use async_stripe::models::test_clocks::TestClock; use async_stripe::Client; let client = Client::new("sk_test_..."); let clock = TestClock::create( &client, async_stripe::params::CreateTestClock { frozen_time: Some(1678886400), // March 15, 2023 12:00:00 PM GMT nickname: Some("Example test clock 1"), ..Default::default() }, ) .await?; ``` -------------------------------- ### Check Active Mise Version Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/tooling.mdx Displays the currently active tool versions managed by Mise in the current directory. ```bash mise current # Output: rust 1.88 ``` -------------------------------- ### Apply Global Client Strategy Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/request-strategy.mdx Configure a default request strategy for all operations performed by the Stripe client. ```rust let client = Client::new("sk_test_...") .with_strategy(RequestStrategy::ExponentialBackoff(3)); let customer = Customer::create( &client, CreateCustomer { email: Some("test@example.com"), ..Default::default() }, ).await?; ``` -------------------------------- ### Git and Cargo Workflow Commands Source: https://github.com/arlyon/async-stripe/blob/master/CONTRIBUTING.md Standard commands for managing feature branches, testing, and linting during the contribution process. ```bash git checkout -b my-new-feature ``` ```bash cargo test --features runtime-blocking ``` ```bash cargo +1.82.0 clippy --all --all-targets -- -D warnings ``` ```bash git commit -am 'Add some feature' ``` ```bash git push origin my-new-feature ``` -------------------------------- ### Migrate Customer Creation Request Source: https://github.com/arlyon/async-stripe/blob/master/site/content/files/MIGRATION.md Update request patterns from static methods to the new .send() builder pattern. ```rust use stripe::{Client, CreateCustomer, Customer}; async fn create_customer(client: &Client) -> Result<(), stripe::Error> { let customer = Customer::create( &client, CreateCustomer { email: Some("test@async-stripe.com"), ..Default::default() }, ).await?; Ok(()) } ``` ```rust use stripe::Client; use stripe_core::customer::CreateCustomer; async fn create_customer(client: &Client) -> Result<(), stripe::Error> { let customer = CreateCustomer { email: Some("test@async-stripe.com"), ..Default::default() } .send(client) .await?; Ok(()) ``` -------------------------------- ### Mise Configuration for Rust Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/tooling.mdx Defines the pinned Rust version in the mise.toml file to ensure consistent builds. ```toml [tools] # We pin to a specific stable version to ensure consistent behavior # across all developer machines. rust = "1.88" ``` -------------------------------- ### Enable serde deserialization in Cargo.toml Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/performance.mdx Enable the deserialize feature to add serde::Deserialize implementations to Stripe types for database storage or caching. ```toml [dependencies] stripe-core = { version = "1.0.0-rc.0", features = ["customer", "deserialize"] } ``` -------------------------------- ### Execute Command with Mise Environment Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/tooling.mdx Runs a command, such as 'cargo test', within the environment activated by Mise, useful if shell hooks are not enabled. ```bash mise exec -- cargo test ``` -------------------------------- ### Configure Crate Mapping Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/codegen.mdx Define the mapping of Stripe resources to Rust crates using the gen_crates.toml configuration file. ```toml # Example from gen_crates.toml [[crates]] name = "billing" packages = ["test_helpers", "billing_portal", "billing"] paths = [ "credit_note", "tax_id", "invoice", # ... ] description = "This crate provides Rust bindings to the Stripe HTTP API..." ``` -------------------------------- ### Run OpenAPI Code Generation Source: https://github.com/arlyon/async-stripe/blob/master/CONTRIBUTING.md Executes the code generation process by fetching the latest Stripe OpenAPI specification. ```bash cd openapi && cargo run --release -- --fetch latest ``` -------------------------------- ### Manual Pagination in Rust Source: https://github.com/arlyon/async-stripe/blob/master/site/snapshots/examples_pagination_src_main.rs_L22-46.txt Use this pattern to iterate through all Stripe resources when automatic pagination is not sufficient. Ensure you handle the `StripeError` appropriately. ```rust pub async fn manual_pagination_example(client: &Client) -> Result<(), stripe::StripeError> { let mut params = ListCustomer::new().limit(10); loop { let page = params.send(client).await?; if page.data.is_empty() { break; } for customer in &page.data { println!("{}", customer.id); } if !page.has_more { break; } // Set cursor for next loop if let Some(last) = page.data.last() { params = params.starting_after(last.id.as_str()); } } Ok(()) } ``` -------------------------------- ### Paginate with Request Builder in Rust Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/pagination.mdx Use the .paginate() method on List or Search request structs to lazily fetch pages as an asynchronous stream. ```rust let mut stream = stripe::Customer::list(&client, Default::default()).paginate(); while let Some(customer) = stream.try_next().await? { println!("Customer: {:?}", customer.id); } // Or use stream combinators let customers: Vec<_> = stream.try_collect().await?; ``` -------------------------------- ### Upload files using reqwest Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/index.mdx Use this workaround to perform multipart/form-data file uploads, as the library does not currently generate these endpoints. ```rust 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?; ``` -------------------------------- ### Implement basic error handling Source: https://github.com/arlyon/async-stripe/blob/master/site/content/docs/error-handling.mdx A simple pattern for matching on StripeError results. ```rust match customer { Ok(customer) => println!("Created customer: {}", customer.id), Err(StripeError::Stripe(e)) => { println!("Stripe error: {}", e.message.unwrap_or_default()); } Err(e) => { println!("Other error: {:?}", e); } } ```