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

# SDKs

> The integrateledger packages for TypeScript and Python.

Ledger has official server-side SDKs for TypeScript and Python, both named `integrateledger`. They cover every endpoint in the API reference except deleting a customer, which you can call over HTTP. Use them from your backend only: they need your secret API key.

| Language | Package | Requires |
| - | - | - |
| TypeScript and JavaScript | [`integrateledger` on npm](https://www.npmjs.com/package/integrateledger) | A Node.js LTS release, Bun 1+ or Deno |
| Python | [`integrateledger` on PyPI](https://pypi.org/project/integrateledger/) | Python 3.9+ |

## Install and configure

```bash TypeScript theme={"system"}
npm install integrateledger
```

```bash Python theme={"system"}
pip install integrateledger
```

Create one client with your API key and reuse it. The key decides the environment, Sandbox or Live.

```typescript TypeScript theme={"system"}
import ledger from "integrateledger";

const client = new ledger({ apiKey: process.env.LEDGER_API_KEY ?? "" });

const plans = await client.listPlans();
console.log(plans.items.length);
```

```python Python theme={"system"}
import os
from integrateledger import ledger

client = ledger(api_key=os.environ["LEDGER_API_KEY"])

plans = client.list_plans()
print(len(plans["items"]))
```

| Option | TypeScript | Python | Default |
| - | - | - | - |
| API key | `apiKey` | `api_key` | Required |
| API URL | `serverURL` | `base_url` | `https://api.integrateledger.com` |
| Timeout | `timeoutMs` | `timeout` (seconds) | None in TypeScript; 30 seconds in Python |

## Responses

Both SDKs return the API's JSON. Python returns it as a `dict`, unchanged. TypeScript returns typed objects with two differences from the raw JSON:

* Timestamps such as `createdAt` are `Date` objects.
* `request_id` on `track` is `requestId`, in both the request and the response.

## Errors

A response with a 4xx or 5xx status raises an error that carries the status and Ledger's error code. [Errors](https://docs.integrateledger.com/errors.md) lists every code.

```typescript TypeScript theme={"system"}
import { LedgerError } from "integrateledger/models/errors";

try {
  await client.getCustomer({ customerId: "user_unknown" });
} catch (error) {
  if (error instanceof LedgerError) {
    console.log(error.statusCode, error.body); // 404 {"error":"customer_not_found"}
  } else {
    throw error; // A network failure or timeout.
  }
}
```

```python Python theme={"system"}
from integrateledger import LedgerAPIError, LedgerConnectionError

try:
    client.get_customer(customer_id="user_unknown")
except LedgerAPIError as error:
    print(error.status, error.code)  # 404 customer_not_found
except LedgerConnectionError:
    pass  # Ledger couldn't be reached. Retry later.
```

In TypeScript, each method also has its own error class with the parsed body in `data$`, such as `TrackError` with `error.data$.error` set to `"insufficient_credits"`. In Python, `error.body` holds the parsed body.

## Methods

| Endpoint | TypeScript | Python |
| - | - | - |
| `POST /v1/check` | `checkCredits` | `check_credits` |
| `POST /v1/track` | `trackUsage` | `track_usage` |
| `POST /v1/customers` | `createOrGetCustomer` | `create_or_get_customer` |
| `GET /v1/customers` | `getCustomer` | `get_customer` |
| `DELETE /v1/customers` | Not in the SDK yet | Not in the SDK yet |
| `GET /v1/customers/subscriptions` | `listCustomerSubscriptions` | `list_customer_subscriptions` |
| `GET /v1/customers/purchases` | `listCustomerPurchases` | `list_customer_purchases` |
| `POST /v1/customers/subscriptions/{id}/cancellation` | `setSubscriptionCancellation` | `set_subscription_cancellation` |
| `POST /v1/customers/overage-cap` | `setCustomerOverageCap` | `set_customer_overage_cap` |
| `POST /v1/customers/overage-override` | `setCustomerOverageOverride` | `set_customer_overage_override` |
| `POST /v1/billing/attach` | `attach` | `attach` |
| `POST /v1/billing/upgrade` | `upgradePaidPlan` | `upgrade_paid_plan` |
| `POST /v1/billing/downgrade` | `downgradePaidPlan` | `downgrade_paid_plan` |
| `GET /v1/billing/downgrade` | `getScheduledDowngrade` | `get_scheduled_downgrade` |
| `POST /v1/billing/downgrade/{id}/cancel` | `cancelScheduledDowngrade` | `cancel_scheduled_downgrade` |
| `GET /v1/plans` | `listPlans` | `list_plans` |
| `POST /v1/plans` | `createPlan` | `create_plan` |
| `GET /v1/plans/{id}` | `getPlan` | `get_plan` |
| `POST /v1/plans/{id}` | `updatePlan` | `update_plan` |
| `DELETE /v1/plans/{id}` | `archivePlan` | `archive_plan` |
| `GET`, `POST`, `DELETE` `/v1/features…` | `listFeatures`, `createFeature`, `getFeature`, `updateFeature`, `archiveFeature` | `list_features`, `create_feature`, `get_feature`, `update_feature`, `archive_feature` |
| `GET`, `POST`, `DELETE` `/v1/add-ons…` | `listAddOns`, `createAddOn`, `getAddOn`, `updateAddOn`, `archiveAddOn` | `list_add_ons`, `create_add_on`, `get_add_on`, `update_add_on`, `archive_add_on` |
| `POST /v1/catalog` | `publishCatalog` | `publish_catalog` |

TypeScript methods take one object. Path and query values sit at its top level, and a request body goes under `body` when the method also has path or query values, as in `updatePlan({ id, body })`. Python methods take keyword arguments in snake case.

## Next steps

> [card] [Setup](https://docs.integrateledger.com/getting-started/setup.md)
>
> Install the SDK and CLI, publish a catalog, start a customer.

> [card] [API reference](https://docs.integrateledger.com/api-reference/introduction.md)
>
> The endpoints the SDKs call.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.