Request Strategies
Handle network failures gracefully with automatic retries and idempotency keys to prevent duplicate charges and ensure reliable payment processing.
Network requests fail. async-stripe provides a robust RequestStrategy API to handle idempotency keys and retries automatically, ensuring your application handles transient failures gracefully without double-charging customers.
Strategy Options
The library implements the "Full Jitter" exponential backoff algorithm recommended by Stripe engineering to prevent thundering herd problems.
| Strategy | Description | Use Case |
|---|---|---|
Once | Fire and forget. No retries. | You are handling retries manually |
Idempotent(key) | Fire once with a specific, user-provided Idempotency Key | Critical payment creation flows where you need control over the idempotency key |
Retry(n) | Retry n times with a random UUID idempotency key | General retry logic without backoff |
ExponentialBackoff(n) | Retry n times with exponential backoff (0.5s base, up to 8s max) and randomized jitter | Recommended for production to handle transient failures gracefully |
Usage
You can apply a strategy globally to the client (for all requests) or override it on a per-request basis.
Global Client Strategy
pub async fn run_strategy_example() -> Result<(), StripeError> {
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::<Vec<_>>()
);
Ok(())
}Per-Request Strategy
);
Ok(())
}
pub async fn per_request_strategy_example(client: &Client) -> Result<(), StripeError> {
let params = CreateCustomer::new();
let customer = params
.customize() // Enter builder mode
.request_strategy(RequestStrategy::Retry(5)) // Override strategy for this call only
.send(client)
.await?;Custom Idempotency Keys
For critical operations where you need precise control over deduplication (e.g., linking payment creation to your own order IDs), you can provide your own idempotency key instead of using an auto-generated UUID.
The IdempotencyKey type validates that your key:
- Is not empty
- Does not exceed 255 characters (Stripe's limit)
use stripe::{Client, CreatePaymentIntent, Currency, RequestStrategy, IdempotencyKey};
let client = Client::new(secret_key);
// Use your own unique identifier (e.g., from your database)
let key = IdempotencyKey::new("order_12345_attempt_1").unwrap();
CreatePaymentIntent::new(1000, Currency::USD)
.request_strategy(RequestStrategy::Idempotent(key))
.send(&client)
.await?;This ensures that even if your application retries the request due to a network failure, Stripe will recognize it as the same operation and not create duplicate charges.
Idempotency keys are valid for 24 hours. After that, Stripe will treat a request with the same key as a new operation.
When to Use Custom Keys
- Order processing: Use
order_{id}_paymentto tie payment creation to order IDs - Subscription operations: Use
subscription_{id}_cancel_{timestamp}for cancellations - Multi-step flows: Maintain idempotency across application restarts by persisting keys
When to Use Auto-Generated Keys
For most operations, the auto-generated UUID keys from RequestStrategy::Retry(n) or RequestStrategy::ExponentialBackoff(n) are sufficient and more convenient.