> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metrifox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Ruby

> Official **Ruby SDK** for the Metrifox platform. Build and scale usage-based SaaS applications with comprehensive tools for customer management, usage tracking, access control, and billing.

## Installation

Add this line to your application's Gemfile:

```ruby theme={null}
gem 'metrifox-sdk'
```

And then execute:

```bash theme={null}
bundle install
```

Or install it yourself as:

```bash theme={null}
gem install metrifox-sdk
```

***

## Quick Start

### Configuration

```ruby theme={null}
require 'metrifox-sdk'

# Initialize with configuration
METRIFOX_SDK = MetrifoxSDK.init({ api_key: "your-api-key"})

# Or set environment variable
ENV["METRIFOX_API_KEY"] = "your-api-key"
METRIFOX_SDK = MetrifoxSDK.init
```

<Note>
  Get your API key from **Settings → API Keys** in your Metrifox dashboard.
</Note>

***

## Customer Management

### Create a Customer

```ruby theme={null}
# Individual customer
customer_data = {
  customer_key: "customer_123",  # Required - unique identifier
  customer_type: "INDIVIDUAL",   # Required - "INDIVIDUAL" or "BUSINESS"
  primary_email: "customer@example.com",  # Required
  first_name: "John",
  last_name: "Doe",
  primary_phone: "+1234567890",
  currency: "USD"
}

response = METRIFOX_SDK.customers.create(customer_data)

# Business customer
business_data = {
  customer_key: "company_abc123",
  customer_type: "BUSINESS",
  primary_email: "contact@acmecorp.com",
  legal_name: "ACME Corporation LLC",
  display_name: "ACME Corp",
  website_url: "https://acmecorp.com"
}

response = METRIFOX_SDK.customers.create(business_data)
```

### Update a Customer

```ruby theme={null}
# Update customer (customer_key cannot be changed)
update_data = {
  display_name: "ACME Corporation",
  website_url: "https://acme.com"
}

response = METRIFOX_SDK.customers.update("customer_123", update_data)
```

<Note>
  The `customer_key` is immutable and cannot be changed after creation.
</Note>

### Get Customer Data

```ruby theme={null}
# Get customer
response = METRIFOX_SDK.customers.get_customer({ customer_key: "customer_123" })

# Get customer details
response = METRIFOX_SDK.customers.get_details({ customer_key: "customer_123" })

# Check for an active subscription
has_active_subscription = METRIFOX_SDK.customers.has_active_subscription?(customer_key: "customer_123")

# List customers
response = METRIFOX_SDK.customers.list

# List with pagination
response = METRIFOX_SDK.customers.list({ page: 2, per_page: 10 })

# List with filters
response = METRIFOX_SDK.customers.list({
  search_term: "TechStart",
  customer_type: "BUSINESS",
  date_created: "2025-09-01"
})
```

### Delete a Customer

```ruby theme={null}
response = METRIFOX_SDK.customers.delete_customer({ customer_key: "customer_123" })
```

### Archive / Unarchive a Customer

```ruby theme={null}
# Archive a customer (preserves their full history)
response = METRIFOX_SDK.customers.archive("customer_123")
puts response["data"]["archived_at"]

# Restore an archived customer
response = METRIFOX_SDK.customers.unarchive("customer_123")
```

### CSV Upload

```ruby theme={null}
# Upload customers via CSV
response = METRIFOX_SDK.customers.upload_csv("/path/to/customers.csv")

puts response["data"]["total_customers"]
puts response["data"]["successful_upload_count"]
```

***

## Usage Tracking & Access Control

### Check Feature Access

```ruby theme={null}
response = METRIFOX_SDK.usages.check_access({
  feature_key: "premium_feature",
  customer_key: "customer_123"
})

puts response["data"]["can_access"]  # true/false
puts response["data"]["balance"]
```

<Note>
  Access checks are served by the Metrifox Meter service (`https://api-meter.metrifox.com`).
</Note>

**Example response:**

```json theme={null}
{
  "data": {
    "customer_key": "cust-mit7k5v8obzs",
    "feature_key": "feature_seats",
    "requested_quantity": 1,
    "can_access": true,
    "unlimited": false,
    "balance": 4,
    "used_quantity": 0,
    "entitlement_active": true,
    "prepaid": false,
    "wallet_balance": 0,
    "message": "Feature found"
  }
}
```

### Record Usage Events

```ruby theme={null}
# Basic usage recording
response = METRIFOX_SDK.usages.record_usage({
  customer_key: "customer_123",
  event_name: "api_call",
  amount: 1,
  event_id: "evt_12345",  # Required idempotency key
  timestamp: (Time.now.to_f * 1000).to_i  # Recommended (milliseconds)
})

puts response["message"]  # "Event received"
puts response["data"]["quantity"]  # 1
```

<Note>
  You can send either an `event_name` or a `feature_key` when recording usage events.
</Note>

### Advanced Usage Recording

```ruby theme={null}
# With additional fields
response = METRIFOX_SDK.usages.record_usage({
  customer_key: "customer_123",
  event_name: "api_call",  # Or use feature_key
  amount: 1,
  event_id: "event_uuid_123",  # Required idempotency key
  credit_used: 5,
  timestamp: (Time.now.to_f * 1000).to_i,
  metadata: {
    source: "web_app",
    feature: "premium_search"
  }
})

# Using structured request object
usage_request = MetrifoxSDK::Types::UsageEventRequest.new(
  customer_key: "customer_123",
  feature_key: "feat_my_feat_234",  # OR use event_name
  amount: 1,
  credit_used: 5,
  event_id: "event_uuid_123",
  timestamp: (Time.now.to_f * 1000).to_i,
  metadata: { source: "mobile_app" }
)

response = METRIFOX_SDK.usages.record_usage(usage_request)
```

**Sample response:**

```json theme={null}
{
  "data": {
    "customer_key": "cust-mit7k5v8obzs",
    "quantity": 1,
    "feature_key": "feature_job_posts"
  },
  "message": "Event received"
}
```

### List Usage Events

```ruby theme={null}
# List events with optional filters and pagination
response = METRIFOX_SDK.usages.list_events(
  customer_key: "customer_123",   # optional
  feature_key: "feature_seats",   # optional
  page: 1,                        # optional
  per_page: 25                    # optional
)

response["data"].each do |event|
  puts "#{event['feature_key']}: #{event['quantity']} at #{event['timestamp']}"
end

puts "Page #{response['meta']['current_page']} of #{response['meta']['total_pages']}"
```

### Compute Quantity Price

Compute the price for a given quantity of a feature for a customer, based on their plan. Useful for previewing upgrade costs or showing customers the cost of additional usage before they commit.

```ruby theme={null}
response = METRIFOX_SDK.usages.quantity_price(
  customer_key: "customer_123",
  feature_key: "feature_interview_booking",
  quantity: 500
)

puts "#{response['data']['price']} #{response['data']['unit']}"

# For tiered pricing, inspect the per-tier breakdown
response["data"]["applied_tiers"].each do |tier|
  puts "  Tier #{tier['first_unit']}-#{tier['last_unit']}: #{tier['units_consumed']} units -> #{tier['tier_price']}"
end
```

<Note>
  Only available to tenants whose plan includes the finance API feature.
</Note>

***

## Checkout & Billing

### Generate Checkout URL

```ruby theme={null}
# Basic checkout URL generation
checkout_url = METRIFOX_SDK.checkout.url({
  offering_key: "your_offering_key"
})

# With optional billing interval
checkout_url = METRIFOX_SDK.checkout.url({
  offering_key: "your_offering_key",
  billing_interval: "monthly"
})

# With customer key for pre-filled checkout
checkout_url = METRIFOX_SDK.checkout.url({
  offering_key: "your_offering_key",
  billing_interval: "monthly",
  customer_key: "customer_123"
})

# Using structured config object
checkout_config = MetrifoxSDK::Types::CheckoutConfig.new(
  offering_key: "your_offering_key",
  billing_interval: "monthly",
  customer_key: "customer_123"
)

checkout_url = METRIFOX_SDK.checkout.url(checkout_config)
```

### Card Collection URL

Generate a hosted URL for collecting a payment method against an existing subscription or order. Useful for trial-to-paid conversions and re-collecting card details after expiry.

```ruby theme={null}
# For a subscription
url = METRIFOX_SDK.checkout.card_collection_url(subscription_id: "sub_uuid_123")

# For an order
url = METRIFOX_SDK.checkout.card_collection_url(order_id: "order_uuid_456")
```

***

## Wallets & Credit Allocations

```ruby theme={null}
# List a customer's credit wallets
response = METRIFOX_SDK.wallets.list("customer_123")
response["data"].each do |wallet|
  puts "#{wallet['name']}: #{wallet['balance']} #{wallet['credit_unit_plural']}"
end

# List allocations for a wallet (optionally filter by status)
response = METRIFOX_SDK.wallets.list_credit_allocations("wallet_uuid_123")
response = METRIFOX_SDK.wallets.list_credit_allocations("wallet_uuid_123", status: "active")

# Get a single allocation with its transaction history
response = METRIFOX_SDK.wallets.get_credit_allocation("alloc_uuid_123")
response["data"]["transactions"].each do |txn|
  puts "  #{txn['amount']} at #{txn['created_at']}"
end
```

***

## Type Safety with Structs

The SDK exposes lightweight structs for usage and checkout helpers:

```ruby theme={null}
# Usage events (event_id required for idempotency)
usage_request = MetrifoxSDK::Types::UsageEventRequest.new(
  customer_key: "customer_123",
  feature_key: "feature_seats",
  amount: 1,
  event_id: "event_uuid_123",
  timestamp: (Time.now.to_f * 1000).to_i,
  metadata: { source: "mobile_app" }
)

response = METRIFOX_SDK.usages.record_usage(usage_request)

# Checkout configuration
checkout_config = MetrifoxSDK::Types::CheckoutConfig.new(
  offering_key: "premium_plan",
  billing_interval: "monthly",
  customer_key: "customer_123"
)

checkout_url = METRIFOX_SDK.checkout.url(checkout_config)
```

***

## Error Handling

```ruby theme={null}
begin
  response = METRIFOX_SDK.usages.check_access({
    feature_key: "premium_feature",
    customer_key: "customer_123"
  })
rescue MetrifoxSDK::APIError => e
  puts "API Error: #{e.message}"
rescue MetrifoxSDK::ConfigurationError => e
  puts "Configuration Error: #{e.message}"
end
```

***

## Framework Integration

### Rails

```ruby theme={null}
# config/initializers/metrifox.rb
METRIFOX_SDK = MetrifoxSDK.init({
  api_key: ENV['METRIFOX_API_KEY']
})

# app/controllers/premium_features_controller.rb
class PremiumFeaturesController < ApplicationController
  def use_feature
    access = METRIFOX_SDK.usages.check_access({
      feature_key: "premium_feature",
      customer_key: current_user.customer_key
    })

    unless access["data"]["can_access"]
      return render json: { error: "Access denied" }, status: :forbidden
    end

    # Process feature...

    METRIFOX_SDK.usages.record_usage({
      customer_key: current_user.customer_key,
      event_name: "premium_feature_used",
      event_id: SecureRandom.uuid
    })

    render json: { success: true }
  end
end
```

### Sinatra

```ruby theme={null}
require 'sinatra'
require 'metrifox-sdk'

METRIFOX_SDK = MetrifoxSDK.init({ api_key: ENV['METRIFOX_API_KEY'] })

get '/api/premium/:customer_id' do
  access = METRIFOX_SDK.usages.check_access({
    feature_key: "premium_api",
    customer_key: params[:customer_id]
  })

  halt 403, { error: "Access denied" }.to_json unless access["data"]["can_access"]

  # Process request...

  METRIFOX_SDK.usages.record_usage({
    customer_key: params[:customer_id],
    event_name: "premium_api_call",
    event_id: request.env['HTTP_X_REQUEST_ID']
  })

  { data: "premium content" }.to_json
end
```

***

## API Reference

### Available Methods

**Customers:**

* `create(data)` - Create a customer
* `update(customer_key, data)` - Update a customer
* `get_customer(params)` - Get a customer
* `get_details(params)` - Get detailed customer information
* `list(params)` - List customers with pagination and filters
* `delete_customer(params)` - Delete a customer
* `archive(customer_key)` - Archive a customer
* `unarchive(customer_key)` - Restore an archived customer
* `has_active_subscription?(params)` - Check for active subscription
* `upload_csv(file_path)` - Upload customers via CSV
* `bulk_create(params)` - Create multiple customers in one call

**Usages:**

* `check_access(params)` - Check feature access
* `record_usage(params)` - Record a usage event
* `list_events(...)` - List recorded usage events with optional filters and pagination
* `quantity_price(customer_key:, feature_key:, quantity:)` - Compute the price of a usage quantity (requires finance API feature)

**Checkout:**

* `url(params)` - Generate a checkout URL
* `card_collection_url(subscription_id:, order_id:)` - Generate a hosted card-collection URL

**Wallets:**

* `list(customer_key)` - List a customer's credit wallets
* `list_credit_allocations(wallet_id, status:)` - List credit allocations for a wallet
* `get_credit_allocation(allocation_id)` - Get a single allocation with transaction history

### Type Structs

```ruby theme={null}
MetrifoxSDK::Types::UsageEventRequest
MetrifoxSDK::Types::CheckoutConfig
```

***

## Configuration

### Environment Variables

```bash theme={null}
export METRIFOX_API_KEY=your_api_key_here
```

### Custom URLs

```ruby theme={null}
METRIFOX_SDK = MetrifoxSDK.init({
  api_key: "your_api_key",
  base_url: "https://custom-api.metrifox.com/api/v1/",
  web_app_base_url: "https://custom-app.metrifox.com",
  meter_service_base_url: "https://custom-meter.metrifox.com/"
})

# The meter service URL can also be set via env var
ENV["METRIFOX_METER_SERVICE_BASE_URL"] = "https://custom-meter.metrifox.com/"
```

### Default URLs

* **Production API:** `https://api.metrifox.com/api/v1/`
* **Meter Service:** `https://api-meter.metrifox.com/`
* **Web App:** `https://app.metrifox.com`

***

## Requirements

* Ruby 2.7+

***

## Support

* **Email:** [support@metrifox.com](mailto:support@metrifox.com)
* **Documentation:** [https://docs.metrifox.com](https://docs.metrifox.com)
* **GitHub:** [https://github.com/metrifox/metrifox-ruby](https://github.com/metrifox/metrifox-ruby)
* **Discord** [https://discord.gg/GGMHDDBdw](https://discord.gg/GGMHDDBdw)

<Note>
  The Ruby SDK follows Ruby conventions and integrates seamlessly with Rails, Sinatra, and other Ruby frameworks.
</Note>
