Guides

Pay-i Client APIs

Overview

The Pay-i Python SDK provides client classes (Payi for synchronous, AsyncPayi for asynchronous) that serve as your primary interface for interacting programmatically with the Pay-i API.

Use the Pay-i client when you need to:

  • Automate Configuration Management: Create, update, or delete Pay-i entities like categories, resources, limits, and use cases directly from your code, often as part of deployment scripts or operational workflows.
  • Submit Usage Data Manually: Send detailed event data (usage metrics, latency, metadata) to Pay-i using the client.ingest object. This is crucial for tracking custom resources, integrating non-Python applications, or backfilling historical data. See the Ingest API documentation for details.
  • Retrieve Specific Request Details: Fetch information about individual past requests processed by Pay-i using client.requests, useful for debugging or targeted analysis. Note that bulk data export is not a primary function of this client API; real-time event data like cost and limit status is typically obtained from the xproxy_result during runtime operations.
  • Build Custom Tooling: Develop internal applications or scripts that leverage Pay-i's configuration and individual request data for specialized reporting, monitoring, or management tasks.

The client complements Pay-i's automated instrumentation by providing direct, programmatic control over your Pay-i setup and data submission.

Core Functionality: API Resource Objects

Once initialized (client = Payi() or async_client = AsyncPayi()), the client object grants access to different areas of the Pay-i API via dedicated resource properties. These properties align with the major functional areas documented in the Pay-i API Reference:

PropertyDescriptionKey Use CasesDocumentation Link
client.ingestSubmit detailed event data (usage, latency, metadata) after an interaction.Manual event submission, tracking custom resources, historical data backfill.Ingest API
client.categoriesManage AI model categories and the resources within them.Exploring available models, creating/deleting custom resources, managing resource versions (pricing changes).Categories & Resources
client.limitsCreate, retrieve, update, delete, and reset usage limits and budgets.Programmatically managing budgets, setting spending caps, associating limits with requests.[Link TBD]
client.use_casesDefine, manage, and track specific application use cases.Setting up use case tracking, managing use case versions, associating requests with use cases.[Link TBD]
client.requestsRetrieve details about specific past requests processed by Pay-i.Fetching cost, latency, and metadata for individual requests, debugging specific interactions.[Link TBD]
client.experiencesDeprecated. Experience tracking and management.Previously used for tracking user experiences; replaced by the more robust Use Cases system.N/A

Each property (e.g., client.limits) returns an object providing methods for the corresponding API operations (e.g., client.limits.create(), client.categories.list_resources()).

Initialization and Configuration

Now that you understand the client's purpose and the resources it provides access to, let's cover setup.

Basic Initialization

For most applications, the simplest initialization is sufficient:

from payi import Payi

# Create a synchronous client
# API key automatically loaded from PAYI_API_KEY environment variable
client = Payi()

# Create an asynchronous client
# from payi import AsyncPayi
# async_client = AsyncPayi()

This default setup:

  • Reads the API key from the PAYI_API_KEY environment variable.
  • Connects to the standard Pay-i API endpoint (https://api.pay-i.com).
  • Uses default network timeout and retry settings.

Configuration Options

You can customize the client's behavior during initialization. Pay-i strongly recommends using environment variables (PAYI_API_KEY, PAYI_BASE_URL) for configuring the API key and base URL, as shown in the table below, for better security and flexibility across environments.

ParameterDescriptionDefaultEnvironment Variable (Recommended)
api_keyYour Pay-i API keyRequired (no default)PAYI_API_KEY
base_urlThe Pay-i API endpoint URLhttps://api.pay-i.comPAYI_BASE_URL
timeoutRequest timeout (float or Timeout object)60 seconds (request), 5 seconds (connect)-
max_retriesMaximum retry attempts on transient errors2-
default_headersCustom headers to include in all requestsNone-
default_queryCustom query parameters to include in all requestsNone-
http_clientCustom httpx client instanceAuto-created based on sync/async and settings-

Common Configuration Scenarios

Authentication

Recommended: Use the PAYI_API_KEY environment variable. This avoids hardcoding credentials in your source code.

# Set environment variable (e.g., in your .env file or system environment)
export PAYI_API_KEY="your-api-key"
from payi import Payi
# Client automatically picks up the key from the environment
client = Payi()

Alternative: Pass the key directly during initialization (less secure, mainly for quick tests or specific scenarios where environment variables aren't feasible).

from payi import Payi
client = Payi(api_key="your-api-key") # Avoid this in production code

Custom Timeouts

Adjust network timeouts based on expected API response times or network conditions.

from payi import Payi, Timeout
client = Payi(
    # Use the Timeout object for detailed control
    timeout=Timeout(timeout=90.0, connect=10.0) # 90s request, 10s connect
)

Custom Retry Settings

Modify how the client handles temporary network issues or server errors (like 5xx status codes).

from payi import Payi
# Increase retries if operating in an environment with unreliable network connectivity
client = Payi(max_retries=5)

Custom Base URL

Point the client to a different Pay-i API endpoint. This is necessary for:

  • Private Deployments: Connecting to your self-hosted or privately deployed Pay-i instance.
  • Staging/Testing Environments: Using non-production Pay-i environments.

Recommended: Use the PAYI_BASE_URL environment variable.

# Set environment variable for a private deployment
export PAYI_BASE_URL="https://payi.my-company.internal"
from payi import Payi
# Client automatically picks up the URL from the environment
client = Payi()

Alternative: Pass the URL directly during initialization.

from payi import Payi
# Example for a staging environment
client = Payi(base_url="https://api-staging.pay-i.com")
# Example for a private deployment
# client = Payi(base_url="https://payi.my-company.internal")

Default Headers

Send specific headers with every API request made by the client.

from payi import Payi
client = Payi(
    default_headers={
        "X-Internal-Service": "BillingProcessor",
        "X-Request-Source": "BatchJob"
    }
)

Usage Patterns

Synchronous Usage

When using the Payi client, operations are performed synchronously:

from payi import Payi

client = Payi()

# Send telemetry data (synchronous)
response = client.ingest.units(
    category="openai",
    resource="chat",
    units={"input": {"value": 10}, "output": {"value": 50}}
)

# Work with the response directly
request_id = response.xproxy_result.request_id
print(f"Ingested request: {request_id}")

This example shows a basic event submission. For a comprehensive guide on using ingest.units for manual event submission, including all parameters and advanced scenarios, see the SDK Event Submission (Ingest API) documentation.

Asynchronous Usage

When using the AsyncPayi client, operations are performed asynchronously:

import asyncio
from payi import AsyncPayi

async_client = AsyncPayi()

async def ingest_event():
    # Send telemetry data (asynchronous)
    response = await async_client.ingest.units(
        category="openai",
        resource="chat",
        units={"input": {"value": 10}, "output": {"value": 50}}
    )
    
    # Work with the response
    request_id = response.xproxy_result.request_id
    print(f"Ingested request: {request_id}")
    return response

# Run the async function
asyncio.run(ingest_event())

This example shows a basic asynchronous event submission. For a comprehensive guide on using ingest.units for manual event submission, including all parameters and advanced scenarios, see the SDK Event Submission (Ingest API) documentation.

Pagination in List Methods

All resources in the Pay-i SDK provide a list() method that returns collections of objects (e.g., client.limits.list(), client.categories.list()). The SDK handles pagination automatically, so you can write simple code that processes all items regardless of collection size:

# Simple iteration through all items (pagination handled automatically)
for limit in client.limits.list():
    print(f"Limit: {limit.limit_name}")

Behind the scenes, the SDK makes multiple API calls as needed when you iterate through the results. This means your code can process large collections without manually handling pagination tokens or making multiple explicit API calls.

Pagination Parameters

While automatic pagination works for most use cases, all list() methods support these optional pagination parameters:

client.resource_name.list(
    cursor=None,        # Token for fetching a specific page
    limit=None,         # Maximum items per page (default: 25, max: 100)
    sort_ascending=None # Sort order (true for ascending, false for descending)
)

Note: These parameters are inherited from the SDK framework and are primarily for advanced use cases. Most users don't need to specify them. The Pay-i service defaults to returning 25 elements per page when no limit is specified.

Examples with Pagination Parameters

# Get the first 10 items
first_page = client.limits.list(limit=10)

# Get items in ascending order
ascending_items = client.limits.list(sort_ascending=True)

# Advanced: Manual pagination with cursor
first_page = client.limits.list(limit=20)
if first_page.has_more:
    # Get the next page using the cursor from the first page
    second_page = client.limits.list(cursor=first_page.next_cursor, limit=20)

For most applications, we recommend the simple approach of letting the SDK handle pagination automatically through iteration.

Raw and Streaming Responses

Raw Responses

To access the raw HTTP response:

# Synchronous
raw_response = client.with_raw_response.ingest.units(...)

# Access HTTP-level details
status_code = raw_response.status_code
headers = raw_response.headers

Streaming Responses

For efficient handling of large responses:

# Synchronous
streamed_response = client.with_streaming_response.ingest.units(...)

Client Customization

Create a modified client with updated settings:

# Create a new client with different options
new_client = client.with_options(
    timeout=Timeout(timeout=10.0),
    max_retries=3,
    default_headers={"X-Custom-Header": "value"}
)

Integration with Instrumentation

The client classes integrate with the Pay-i instrumentation functionality:

from payi import Payi
from payi.lib.instrument import payi_instrument

# Create a custom client
client = Payi(timeout=Timeout(timeout=60.0))

# Pass to instrumentation system
payi_instrument(payi=client)

For more details on this integration, see the payi_instrument() documentation.

Error Handling

The client provides standardized error handling:

from payi import Payi
from payi.errors import AuthenticationError, RateLimitError, BadRequestError

client = Payi()

try:
    response = client.ingest.units(...)
except AuthenticationError:
    print("Authentication failed - check your API key")
except RateLimitError:
    print("Rate limit exceeded - slow down requests")
except BadRequestError as e:
    print(f"Bad request: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")

Best Practices

  1. Environment Variables: Store API keys in environment variables rather than hardcoding them
  2. Appropriate Timeouts: Configure timeouts based on your application's needs
  3. Error Handling: Implement proper error handling for API interactions
  4. Client Reuse: Create client instances once and reuse them throughout your application
  5. Async When Appropriate: Use AsyncPayi for asynchronous applications or concurrent operations