flowglad 0.1.0

Rust SDK for FlowGlad - Open source billing infrastructure
Documentation
//! Customer metadata example
//!
//! This example demonstrates how to use metadata to store custom key-value
//! pairs with customers. Metadata is useful for:
//! - Storing your internal identifiers or references
//! - Tracking subscription tiers or plan types
//! - Adding custom tags or categories
//! - Storing any other structured data you need
//!
//! Run this example with:
//! ```bash
//! FLOWGLAD_API_KEY=sk_test_... cargo run --example customer_metadata
//! ```

use flowglad::types::customer::{CreateCustomer, UpdateCustomer};
use flowglad::{Client, Config, Metadata};
use serde_json::json;
use std::env;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Get API key from environment variable
    let api_key =
        env::var("FLOWGLAD_API_KEY").expect("FLOWGLAD_API_KEY environment variable must be set");

    // Create a client
    let config = Config::new(api_key);
    let client = Client::new(config)?;

    println!("🏷️  FlowGlad Metadata Example\n");

    // Generate unique identifier
    let timestamp = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)?
        .as_secs();
    let external_id = format!("metadata_example_{}", timestamp);

    // Example 1: Using the builder pattern to add metadata
    println!("1️⃣  Creating customer with metadata (builder pattern)...");
    let customer = client
        .customers()
        .create(
            CreateCustomer::new(&external_id, "Alice Johnson")
                .email(&format!("alice+{}@example.com", timestamp))
                .metadata("subscription_tier", json!("premium"))
                .metadata("signup_source", json!("web"))
                .metadata("user_type", json!("enterprise"))
                .metadata("max_seats", json!(25))
                .metadata("features", json!(["api_access", "priority_support", "sso"])),
        )
        .await?;

    println!("   ✓ Created customer with metadata:");
    println!("     - ID: {}", customer.id);
    println!("     - Name: {}", customer.name.as_ref().unwrap());
    if let Some(metadata) = &customer.metadata {
        println!("     - Metadata entries: {}", metadata.len());
        for (key, value) in metadata.iter() {
            println!("{}: {}", key, value);
        }
    }
    println!();

    // Example 2: Creating metadata separately then attaching
    println!("2️⃣  Creating customer with pre-built metadata...");
    let mut metadata = Metadata::new();
    metadata.insert("plan_id".to_string(), json!("plan_abc123"));
    metadata.insert("trial_ends_at".to_string(), json!("2025-12-31"));
    metadata.insert("referral_code".to_string(), json!("FRIEND2025"));
    metadata.insert("priority".to_string(), json!(1));

    let external_id2 = format!("metadata_example_2_{}", timestamp);
    let customer2 = client
        .customers()
        .create(
            CreateCustomer::new(&external_id2, "Bob Smith")
                .email(&format!("bob+{}@example.com", timestamp))
                .with_metadata(metadata),
        )
        .await?;

    println!("   ✓ Created customer with pre-built metadata:");
    println!("     - ID: {}", customer2.id);
    if let Some(metadata) = &customer2.metadata {
        println!("     - Metadata entries: {}", metadata.len());
    }
    println!();

    // Example 3: Updating metadata
    println!("3️⃣  Updating customer metadata...");
    let updated = client
        .customers()
        .update(
            &external_id,
            UpdateCustomer::new()
                .metadata("subscription_tier", json!("enterprise"))
                .metadata("max_seats", json!(100))
                .metadata("updated_at", json!(timestamp)),
        )
        .await?;

    println!("   ✓ Updated customer metadata:");
    println!("     - ID: {}", updated.id);
    if let Some(metadata) = &updated.metadata {
        println!("     - Metadata entries: {}", metadata.len());
        for (key, value) in metadata.iter() {
            println!("{}: {}", key, value);
        }
    }
    println!();

    // Example 4: Complex metadata structures
    println!("4️⃣  Creating customer with complex nested metadata...");
    let external_id3 = format!("metadata_example_3_{}", timestamp);
    let customer3 = client
        .customers()
        .create(
            CreateCustomer::new(&external_id3, "Carol Davis")
                .email(&format!("carol+{}@example.com", timestamp))
                .metadata(
                    "company_info",
                    json!({
                        "name": "Acme Corp",
                        "industry": "Technology",
                        "size": "50-100",
                        "founded": 2020
                    }),
                )
                .metadata(
                    "preferences",
                    json!({
                        "email_notifications": true,
                        "sms_notifications": false,
                        "currency": "USD",
                        "timezone": "America/New_York"
                    }),
                )
                .metadata("tags", json!(["vip", "early_adopter", "power_user"])),
        )
        .await?;

    println!("   ✓ Created customer with complex metadata:");
    println!("     - ID: {}", customer3.id);
    if let Some(metadata) = &customer3.metadata {
        println!("     - Metadata entries: {}", metadata.len());
        for (key, value) in metadata.iter() {
            println!("{}: {}", key, serde_json::to_string_pretty(value)?);
        }
    }

    println!("\n✨ Metadata example completed successfully!");
    println!("\n💡 Tips:");
    println!("   - Metadata values can be strings, numbers, booleans, arrays, or objects");
    println!("   - Use metadata to avoid creating custom fields in your own database");
    println!("   - Metadata is returned with customer objects for easy access");
    println!("   - Update metadata without affecting other customer fields");

    Ok(())
}