Skip to navigation

Runledger API

Billing for AI agents that charge per outcome.

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. 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 callEndpointWhen
checkout()POST /v1/checkout_sessionsSignup, plan purchase, top-up
check()POST /v1/checkBefore work starts: allow or deny, and optionally hold
track()POST /v1/eventsAfter work: usage, an outcome, or a signal about an earlier outcome
trace()POST /v1/costsOptional, 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

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",
});

What the event names do is set up once, in an outcome definition and a plan. 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, from the API and from your coding agent over 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 describes the document, the dry run and proposals.

Where to go next

Or start from what you want to do:

I want toRead
Charge only for results, and reverse a charge when a result doesn’t standOutcome settlement
Stop work when a customer can’t pay, and stop parallel agents overspendingChecks and holds
Choose prepaid credits or postpaid invoicesPrepaid and postpaid billing
Refill credits weekly, cap a session, or cap spend per teamUsage windows, pools and spend limits
Use more than one payment providerPayment providers
Price from what each model call costs, and keep a margin floorPricing from cost
Show customers their usageUsage meters and the customer view
Carry real billingGoing live
Look up a term, an ID, an error code or an eventGlossary, conventions, errors and webhooks