lago-client 0.1.8

Lago API client
Documentation

Lago Client

A Rust client library for interacting with the Lago billing API.

Features

  • Async/Await Support: Built with tokio and reqwest for modern async Rust
  • Automatic Retries: Configurable retry logic with exponential backoff
  • Multiple Regions: Support for US, EU, and custom API endpoints
  • Flexible Configuration: Environment variables or programmatic configuration
  • Type Safety: Strongly typed requests and responses using lago-types
  • Authentication: Secure API key-based authentication

Installation

Add this to your Cargo.toml:

[dependencies]
lago-client = "0.1.4"

Quick Start

Using Environment Variables

Set the required environment variables:

export LAGO_API_KEY="your-api-key"
export LAGO_REGION="us"  # or "eu" or custom URL

Then create a client:

use lago_client::LagoClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = LagoClient::from_env()?;
    
    // Use the client to make API calls
    let invoices = client.list_invoices(None).await?;
    println!("Found {} invoices", invoices.invoices.len());
    
    Ok(())
}

Programmatic Configuration

use lago_client::{LagoClient, Config, Credentials, Region};
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = Config::builder()
        .credentials(Credentials::new("your-api-key"))
        .region(Region::Us)
        .timeout(Duration::from_secs(30))
        .build();
    
    let client = LagoClient::new(config);
    
    // Use the client
    let invoices = client.list_invoices(None).await?;
    
    Ok(())
}

Configuration

Regions

The client supports multiple regions:

  • Region::Us - United States (default)
  • Region::Eu - European Union
  • Region::Custom(url) - Custom API endpoint

Retry Configuration

Configure retry behavior for failed requests:

use lago_client::{Config, RetryConfig, RetryMode};
use std::time::Duration;

let retry_config = RetryConfig::builder()
    .mode(RetryMode::Standard)
    .max_attempts(3)
    .initial_delay(Duration::from_millis(100))
    .max_delay(Duration::from_secs(30))
    .backoff_multiplier(2.0)
    .build();

let config = Config::builder()
    .retry_config(retry_config)
    .build();

Retry modes:

  • RetryMode::Off - No retries
  • RetryMode::Standard - Standard exponential backoff
  • RetryMode::Adaptive - Adaptive retry behavior

API Operations

Invoices

use lago_types::requests::invoice::{ListInvoicesRequest, GetInvoiceRequest};

// List invoices with optional filters
let request = ListInvoicesRequest::new();
let invoices = client.list_invoices(Some(request)).await?;

// Get a specific invoice
let request = GetInvoiceRequest::new("invoice-id".to_string());
let invoice = client.get_invoice(request).await?;

Invoice Preview

Preview an invoice before creating it:

use lago_types::requests::invoice::{
    BillingTime, InvoicePreviewInput, InvoicePreviewRequest,
    InvoicePreviewCustomer, InvoicePreviewCoupon, InvoicePreviewSubscriptions,
};

// Preview for an existing customer with a new subscription
let preview_input = InvoicePreviewInput::for_customer("customer_123".to_string())
    .with_plan_code("startup".to_string())
    .with_billing_time(BillingTime::Calendar);

let request = InvoicePreviewRequest::new(preview_input);
let preview = client.preview_invoice(request).await?;
println!("Preview total: {} cents", preview.invoice.total_amount_cents);

// Preview with inline customer details
let customer = InvoicePreviewCustomer::new()
    .with_name("New Customer".to_string())
    .with_currency("USD".to_string());

let preview_input = InvoicePreviewInput::new(customer)
    .with_plan_code("enterprise".to_string())
    .with_subscription_at("2024-01-01T00:00:00Z".to_string());

let request = InvoicePreviewRequest::new(preview_input);
let preview = client.preview_invoice(request).await?;

// Preview with coupons
let coupon = InvoicePreviewCoupon::new("DISCOUNT20".to_string())
    .with_percentage("20".to_string());

let preview_input = InvoicePreviewInput::for_customer("customer_123".to_string())
    .with_plan_code("startup".to_string())
    .with_coupons(vec![coupon]);

let request = InvoicePreviewRequest::new(preview_input);
let preview = client.preview_invoice(request).await?;

// Preview for existing subscriptions with plan upgrade
let subscriptions = InvoicePreviewSubscriptions::new(vec!["sub_123".to_string()])
    .with_plan_code("enterprise".to_string());

let preview_input = InvoicePreviewInput::for_customer("customer_123".to_string())
    .with_subscriptions(subscriptions);

let request = InvoicePreviewRequest::new(preview_input);
let preview = client.preview_invoice(request).await?;

Activity Logs

use lago_types::{
    filters::activity_log::ActivityLogFilters,
    models::ActivitySource,
    requests::activity_log::{GetActivityLogRequest, ListActivityLogsRequest},
};

// List all activity logs
let activity_logs = client.list_activity_logs(None).await?;

// List activity logs with filters
let request = ListActivityLogsRequest::new().with_filters(
    ActivityLogFilters::new()
        .with_activity_types(vec!["invoice.created".to_string()])
        .with_activity_sources(vec![ActivitySource::Api, ActivitySource::Front])
        .with_user_emails(vec!["admin@example.com".to_string()])
        .with_resource_types(vec!["Invoice".to_string()])
        .with_date_range("2025-01-01".to_string(), "2025-01-31".to_string()),
);
let filtered_logs = client.list_activity_logs(Some(request)).await?;

// Get a specific activity log by activity ID
let request = GetActivityLogRequest::new("activity-id".to_string());
let activity_log = client.get_activity_log(request).await?;
println!("Activity: {} - {:?}",
    activity_log.activity_log.activity_type,
    activity_log.activity_log.activity_source
);

API Logs

use lago_types::{
    filters::api_log::ApiLogFilters,
    models::{HttpMethod, HttpStatus, StatusOutcome},
    requests::api_log::{GetApiLogRequest, ListApiLogsRequest},
};

// List all API logs
let api_logs = client.list_api_logs(None).await?;

// List API logs with filters
let request = ListApiLogsRequest::new().with_filters(
    ApiLogFilters::new()
        .with_http_methods(vec![HttpMethod::Post, HttpMethod::Put])
        .with_http_statuses(vec![HttpStatus::Outcome(StatusOutcome::Failed)])
        .with_api_version("v1".to_string())
        .with_request_paths(vec!["/invoices".to_string(), "/customers".to_string()])
        .with_date_range("2025-01-01".to_string(), "2025-01-31".to_string()),
);
let filtered_logs = client.list_api_logs(Some(request)).await?;

// Get a specific API log by request ID
let request = GetApiLogRequest::new("request-id".to_string());
let api_log = client.get_api_log(request).await?;
println!("Request: {:?} {} - Status {}",
    api_log.api_log.http_method,
    api_log.api_log.request_path,
    api_log.api_log.http_status
);

Billable Metrics

use lago_types::{
    models::{BillableMetricAggregationType, BillableMetricFilter},
    requests::billable_metric::{CreateBillableMetricInput, CreateBillableMetricRequest},
};

// Create a billable metric
let metric = CreateBillableMetricInput::new(
    "Storage Usage".to_string(),
    "storage_gb".to_string(),
    BillableMetricAggregationType::SumAgg,
)
.with_description("Tracks storage usage".to_string())
.with_field_name("gb_used".to_string());

let request = CreateBillableMetricRequest::new(metric);
let created = client.create_billable_metric(request).await?;

// List billable metrics
let metrics = client.list_billable_metrics(None).await?;

// Get specific billable metric
let metric = client.get_billable_metric(
    GetBillableMetricRequest::new("storage_gb".to_string())
).await?;

Customers

use lago_types::{
    models::{CustomerType, CustomerPaymentProvider},
    requests::customer::{CreateCustomerInput, CreateCustomerRequest},
};

// Create or Update a customer
let customer = CreateCustomerInput::new("customer_123".to_string())
    .with_name("Acme Corp".to_string())
    .with_email("billing@acme.com".to_string())
    .with_customer_type(CustomerType::Company)
    .with_currency("USD".to_string());

let request = CreateCustomerRequest::new(customer);
let created = client.create_customer(request).await?;

// List customers
let customers = client.list_customers(None).await?;

// Get specific customer
let customer = client.get_customer(
    GetCustomerRequest::new("customer_123".to_string())
).await?;

## Error Handling

The client uses the `lago-types` error system:

```rust
use lago_types::error::LagoError;

match client.list_invoices(None).await {
    Ok(invoices) => println!("Success: {} invoices", invoices.invoices.len()),
    Err(LagoError::Unauthorized) => println!("Invalid API key"),
    Err(LagoError::RateLimit) => println!("Rate limit exceeded"),
    Err(LagoError::Api { status, message }) => {
        println!("API error {}: {}", status, message);
    }
    Err(e) => println!("Other error: {}", e),
}

Environment Variables

Variable Description Default
LAGO_API_KEY API key for authentication Required
LAGO_REGION API region (us, eu, or custom URL) us
LAGO_API_URL Custom API endpoint URL -

Examples

See the examples/ directory for complete usage examples:

  • basic_usage.rs - Basic client usage
  • custom_configuration.rs - Advanced configuration options
  • activity_log.rs - Activity logs listing and filtering
  • api_log.rs - API logs listing and filtering
  • billable_metric.rs - Billable metrics management
  • customer.rs - Customers management operations
  • invoice.rs - Invoice operations including preview
# Run the basic usage example
cargo run --example basic_usage

# Run the activity logs example
cargo run --example activity_log

# Run the API logs example
cargo run --example api_log

# Run the billable metrics example
cargo run --example billable_metric

# Run the customer management example
cargo run --example customer

# Run the invoice example
cargo run --example invoice

Release

Before publishing a release

cargo check
cargo test
cargo doc --no-deps --open
cargo package

Run the release

cargo login API_KEY
cargo publish

License

This project is licensed under the same license as the parent Lago Rust Client.