Skip to main content

Tirdad Python SDK

Type-safe Python client for the Tirdad API: billing, metering, and subscription management for SaaS and usage-based products.

Requirements

  • Python 3.10+

Installation

pip install tirdad-sdk

With uv or poetry:

uv add tirdad-sdk
# or
poetry add tirdad-sdk

Runnable samples are in the examples/ directory.

Environment

Variable Required Description
TIRDAD_API_KEY Yes API key
TIRDAD_API_HOST Optional Full base URL including https:// and /v1 (default: https://api.tirdad.ai/v1). No trailing slash.

Integration tests in api/tests/python/test_sdk.py use a different env shape; see api/tests/README.md.

Quick start

Initialize the client, create a customer, ingest an event:

import os
from tirdad_sdk import Tirdad

api_key = os.getenv("TIRDAD_API_KEY", "YOUR_API_KEY")
server_url = os.getenv(
    "TIRDAD_API_HOST", "https://api.tirdad.ai/v1"
)

with Tirdad(server_url=server_url, api_key_auth=api_key) as client:
    external_id = "customer-123"
    client.customers.create_customer(
        external_id=external_id,
        email="user@example.com",
        name="Example Customer",
    )
    result = client.events.ingest_event(
        request={
            "event_name": "Sample Event",
            "external_customer_id": external_id,
            "properties": {"source": "python_app", "environment": "test"},
            "source": "python_app",
        }
    )
    print(result)

Async usage

The same client supports async when used as an async context manager:

import asyncio
import os
from tirdad_sdk import Tirdad

async def main():
    server_url = os.getenv(
        "TIRDAD_API_HOST", "https://api.tirdad.ai/v1"
    )
    async with Tirdad(
        server_url=server_url,
        api_key_auth=os.getenv("TIRDAD_API_KEY", "YOUR_API_KEY"),
    ) as client:
        result = await client.events.ingest_event_async(
            request={
                "event_name": "Sample Event",
                "external_customer_id": "customer-123",
                "properties": {"source": "python_async", "environment": "test"},
                "source": "python_async",
            }
        )
        print(result)

asyncio.run(main())

Authentication

  • Pass your API key as api_key_auth when creating the client. The SDK sends it in the x-api-key header.
  • Set TIRDAD_API_HOST to a full URL (see Environment) or use the default https://api.tirdad.ai/v1.
  • Prefer environment variables; get keys from your Tirdad dashboard or docs.

Error handling

API errors are raised as exceptions. Catch them and inspect the response as needed:

try:
    with Tirdad(server_url="...", api_key_auth="...") as tirdad:
        result = tirdad.events.ingest_event(request={...})
except Exception as e:
    print(f"Error: {e}")
    # Inspect status code and body if available on the exception

See the API docs for error formats and status codes.

Features

  • Full API coverage (customers, plans, events, invoices, payments, entitlements, etc.)
  • Sync and async support
  • Type-safe request/response models (Pydantic)
  • Built-in retries and error handling

For a full list of operations, see the API reference and the examples in this repo.

Troubleshooting

  • Missing or invalid API key: Ensure api_key_auth is set (or set TIRDAD_API_KEY and pass it in). Keys are for server-side use only.
  • Wrong server URL: Use a full URL such as https://api.tirdad.ai/v1 (include /v1; no trailing slash).
  • 4xx/5xx on ingest: Event ingest returns 202 Accepted; for errors, check request fields (event_name, external_customer_id, properties, source) against the API docs.

Handling Webhooks

Tirdad sends webhook events to your server for async updates on payments, invoices, subscriptions, wallets, and more.

Flow:

  1. Register your endpoint URL in the Tirdad dashboard
  2. Receive POST with raw JSON body
  3. Read event_type to route
  4. Parse payload into typed model
  5. Handle business logic idempotently
  6. Return 200 quickly
import json
from tirdad_sdk.models import (
    WebhookDtoPaymentWebhookPayload,
    WebhookDtoSubscriptionWebhookPayload,
    WebhookDtoInvoiceWebhookPayload,
)

def handle_webhook(raw_body: str) -> None:
    event = json.loads(raw_body)

    match event.get("event_type"):
        case "payment.success" | "payment.failed" | "payment.updated":
            payload = WebhookDtoPaymentWebhookPayload.model_validate(event)
            if payload.payment:
                print(f"payment {payload.payment.id}")
                # TODO: update payment record

        case "subscription.activated" | "subscription.cancelled" | "subscription.updated":
            payload = WebhookDtoSubscriptionWebhookPayload.model_validate(event)
            if payload.subscription:
                print(f"subscription {payload.subscription.id}")

        case "invoice.update.finalized" | "invoice.payment.overdue":
            payload = WebhookDtoInvoiceWebhookPayload.model_validate(event)
            if payload.invoice:
                print(f"invoice {payload.invoice.id}")

        case _:
            print(f"unhandled event: {event.get('event_type')}")

Event types

Category Events
Payment payment.created · payment.updated · payment.success · payment.failed · payment.pending
Invoice invoice.create.drafted · invoice.update · invoice.update.finalized · invoice.update.payment · invoice.update.voided · invoice.payment.overdue · invoice.communication.triggered
Subscription subscription.created · subscription.draft.created · subscription.activated · subscription.updated · subscription.paused · subscription.resumed · subscription.cancelled · subscription.renewal.due
Subscription Phase subscription.phase.created · subscription.phase.updated · subscription.phase.deleted
Customer customer.created · customer.updated · customer.deleted
Wallet wallet.created · wallet.updated · wallet.terminated · wallet.transaction.created · wallet.transaction.updated · wallet.credit_balance.dropped · wallet.credit_balance.recovered · wallet.ongoing_balance.dropped · wallet.ongoing_balance.recovered · wallet.ongoing_balance.updated
Feature / Entitlement feature.created · feature.updated · feature.deleted · feature.wallet_balance.alert · entitlement.created · entitlement.updated · entitlement.deleted
Credit Note credit_note.created · credit_note.updated

Production rules:

  • Keep handlers idempotent — Tirdad retries on non-2xx
  • Return 200 for unknown event types — prevents unnecessary retries
  • Do heavy processing async — respond fast, queue the work

Documentation

Metadata

Release files for tirdad-sdk 2.1.38

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tirdad-sdk 2.1.38
File Size Uploaded Provenance
tirdad_sdk-2.1.38.tar.gz 344.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for tirdad-sdk 2.1.38
File Interpreter ABI Platform
tirdad_sdk-2.1.38-py3-none-any.whl Python 3 none any Details

Total release size: 1.1 MB

Release files / tirdad_sdk-2.1.38.tar.gz

Download URL tirdad_sdk-2.1.38.tar.gz
Size 344.4 kB
Tags Source
SHA-256 checksum
How to use checksums
57f6bbea74e7f6d341f67a82c60dd02630fcb2acf99cb488f77b68b9520e5ce3
BLAKE2b-256 checksum
How to use checksums
dce387bcc926668c5e22da8e9edbab46b27a62dace96c3ebc7b0e195270a08f4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / tirdad_sdk-2.1.38-py3-none-any.whl

Download URL tirdad_sdk-2.1.38-py3-none-any.whl
Size 790.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
49111a2cd0a12f6579c93e2d32bbe53a1a0f8bfedf1021240bba4f542cb762c3
BLAKE2b-256 checksum
How to use checksums
eb185438bd9ed15f89d96fd6ccbf664aa972b95a645d91f99f65bd4406509a98
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Security for tirdad-sdk 2.1.38

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

2.1.38 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page