> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runledger.co/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runledger.co/_mcp/server.

# Runledger API

Runledger records each outcome charge as pending, confirms it when the result stands, and reverses it when it doesn't, the way card payments authorize, capture and charge back. Your payment providers still collect the money, and Runledger can work with several at once. Runledger decides whether a charge stands.

For example, an AI support agent resolves a ticket and you charge US\$0.95 for it. The charge stays pending for 24 hours, the `support_chat` [preset](/concepts/outcome-settlement#two-clocks). If the customer doesn't come back, it confirms and goes on the invoice. If they reopen the conversation within 30 days, a rule you set reverses it and the invoice is corrected, with the reason recorded.

## The four calls

| SDK call     | Endpoint                     | When                                                                |
| ------------ | ---------------------------- | ------------------------------------------------------------------- |
| `checkout()` | `POST /v1/checkout_sessions` | Signup, plan purchase, top-up                                       |
| `check()`    | `POST /v1/check`             | Before work starts: allow or deny, and optionally hold              |
| `track()`    | `POST /v1/events`            | After work: usage, an outcome, or a signal about an earlier outcome |
| `trace()`    | `POST /v1/costs`             | Optional, around model calls: model, tokens and cost                |

Everything else in the API configures these calls or reads what they did.

## One ticket, start to finish

**`TypeScript`**

```typescript title="TypeScript"
import { RunledgerClient } from "@runledger/sdk";

const runledger = new RunledgerClient(); // reads RUNLEDGER_API_KEY

// Before the agent starts: can this customer pay for one resolution?
const check = await runledger.check({
  external_customer_id: "org_123",
  outcome_definition: "chat_resolution",
  hold: true,
});
if (!check.allowed) throw new Error(`Denied: ${check.reason}`);

// The agent resolved the ticket: a pending charge, linked to the conversation.
await runledger.track({
  idempotency_key: "conv_4821-resolved",
  name: "resolution.chat",
  external_customer_id: "org_123",
  reference: "conv_4821",
  hold: check.hold?.id,
  evidence: { description: "Customer confirmed the refund arrived." },
});

// Two days later the customer reopens the chat. A reversal rule listening for
// this event reverses the charge with the same reference.
await runledger.track({
  idempotency_key: "conv_4821-reopened-1",
  name: "conversation.reopened",
  external_customer_id: "org_123",
  reference: "conv_4821",
});
```

**`Python`**

```python title="Python"
from runledger_sdk import Runledger

runledger = Runledger()  # reads RUNLEDGER_API_KEY

# Before the agent starts: can this customer pay for one resolution?
check = runledger.check(
    external_customer_id="org_123",
    outcome_definition="chat_resolution",
    hold=True,
)
if not check.allowed:
    raise RuntimeError(f"Denied: {check.reason}")

# The agent resolved the ticket: a pending charge, linked to the conversation.
runledger.track(
    idempotency_key="conv_4821-resolved",
    name="resolution.chat",
    external_customer_id="org_123",
    reference="conv_4821",
    hold=check.hold.id if check.hold else None,
    evidence={"description": "Customer confirmed the refund arrived."},
)

# Two days later the customer reopens the chat. A reversal rule listening for
# this event reverses the charge with the same reference.
runledger.track(
    idempotency_key="conv_4821-reopened-1",
    name="conversation.reopened",
    external_customer_id="org_123",
    reference="conv_4821",
)
```

What the event names do is set up once, in an [outcome definition](/concepts/outcome-settlement) and a [plan](/concepts/billing). The integration code doesn't change when you change prices, windows or rules.

## Three ways to set it up

Everything you configure works the same from the [dashboard](/dashboard), from the API and from your coding agent over [MCP](/agents/mcp): the same fields, the same validation, the same result. Agent-led setup is the main path. An agent in your repo reads what exists, validates a configuration, applies it to the sandbox, connects a payment provider's test mode and runs the checks. For live, it proposes the change and a person approves the diff. [Configuration](/api-reference/how-configuration-works) describes the document, the dry run and proposals.

## Where to go next

#### [Quickstart](/quickstart)

Run a resolution, a confirmation and a reversal in the sandbox in a few minutes.

#### [How Runledger fits together](/concepts/overview)

What you configure, what your code calls, what Runledger records, and where each concept is explained.

#### [Set up with an agent](/agents/mcp)

Let a coding agent configure the sandbox, check it, and propose the live changes.

#### [Recipes for AI billing models](/guides/recipes)

Credits that refill, weekly and session caps, tier multipliers, seats with pooled credits, spend limits and auto top-up, as configuration you can apply.

Or start from what you want to do:

| I want to                                                                  | Read                                                                                                                                                               |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Charge only for results, and reverse a charge when a result doesn't stand  | [Outcome settlement](/concepts/outcome-settlement)                                                                                                                 |
| Stop work when a customer can't pay, and stop parallel agents overspending | [Checks and holds](/concepts/checks-and-holds)                                                                                                                     |
| Choose prepaid credits or postpaid invoices                                | [Prepaid and postpaid billing](/concepts/billing)                                                                                                                  |
| Refill credits weekly, cap a session, or cap spend per team                | [Usage windows](/guides/usage-windows), [pools](/guides/pools) and [spend limits](/guides/spend-limits)                                                            |
| Use more than one payment provider                                         | [Payment providers](/concepts/payment-providers)                                                                                                                   |
| Price from what each model call costs, and keep a margin floor             | [Pricing from cost](/concepts/cost-reflective-pricing)                                                                                                             |
| Show customers their usage                                                 | [Usage meters](/guides/usage-summary) and the [customer view](/guides/customer-view)                                                                               |
| Carry real billing                                                         | [Going live](/going-live/overview)                                                                                                                                 |
| Look up a term, an ID, an error code or an event                           | [Glossary](/reference/glossary), [conventions](/reference/conventions), [errors](/reference/idempotency-and-errors) and [webhooks](/api-reference/handle-webhooks) |