How configuration works
Read it, validate it, dry-run it, apply it in the sandbox, or propose it for live.
Credit types, outcome definitions, plans, webhook endpoints, payment provider routing, notification rules and operator spend limits are all configuration, and so are cost models, price rules and margin guardrails. You can set them from the dashboard, from the API, and from a coding agent over MCP. The three do the same thing: the same fields, the same validation and the same result. Agent-led setup is the main path, because an agent in your repo can configure the sandbox end to end.
Every object has its own endpoints, such as POST /v1/plans. For setting up a whole account, or for an agent, there is also a single document.
The configuration document
GET /v1/config returns everything as one document, with a hash that identifies that exact state:
Each section has the shape of its create request. Leave a section out to leave it alone. Objects with a key are matched by key and webhook endpoints by url. The routing rules and notification rules in a document replace the current lists. POST /v1/config/apply never deletes an object because it is missing from the document. A replace does, as described below. A section holds at most 500 objects, and the notification rules at most 50.
Plans carry their allowances, pools, per_seat flag, default_spend_limit and top-up settings. Two more sections complete the document: spend_limits, the operator’s spend limits, matched by key, and account_settings, which holds grant_expiry_notice, how long before credits expire the warning goes out, and customer_view_branding, the default look of the customer view. A limit your customer sets for themselves is data, not configuration, and isn’t part of the document.
The pricing from cost objects have three more sections, cost_models, price_rules and margin_guardrails, with the same rules: objects are matched by key, a rate card inside a custom cost model adds a version only when its rates differ, and a live change is a proposal. A cost model can take its rates from the provider price catalog (catalog_model) and carry your own overrides; the catalog itself isn’t configuration and can’t be written.
Payment providers are not in the document. Connecting one has its own call, POST /v1/payment_providers, because a person finishes it at the provider; in the sandbox it connects test mode directly, and connecting in live isn’t open yet.
Validate, then apply
- Validate.
POST /v1/config/validatechecks a document and writes nothing. It checks references between objects, clock windows against their bounds, and rates against credit types. A document with problems is a normal200withvalid: falseand theerrors, so an agent can read them and try again. It also returns thechangesthe document would make, each with apath, the valuebeforeand the valueafter, andwarnings. - Apply in the sandbox.
POST /v1/config/applycreates or updates everything in the document, all or none, and returns the created and versioned IDs. It takes anIdempotency-Key, and applying the same document twice changes nothing the second time. It needs a sandbox key. - Live changes are proposals. With a live key,
POST /v1/config/applyis refused withproposal_required. A live change goes through a proposal, below.
PUT /v1/config is the import: it replaces the sections the document carries, in one call. It takes the document and an if_match that must be the hash you read, so a change made in between is never overwritten. A stale if_match, one that no longer matches the current configuration, returns 409 with invalid_state and applies nothing: read GET /v1/config again, merge your change into what is there, and send the new hash. With a sandbox key it applies the change, and with a live key it creates a proposal.
A replace removes what the document leaves out. For every section the document carries, objects that are in the account but missing from that section are removed. A section the document doesn’t carry is left alone. The changes of a dry run of the PUT and the diff of a proposal list each removal, as a change with before and no after, before anything is applied. Read them first. To add or update objects without removing any, use POST /v1/config/apply, which never deletes; the dashboard’s import offers both, as Add and update (the default) and Replace. In live, an import is always a proposal: nothing changes until a signed-in Admin accepts it in the dashboard, and the approval replaces the sections as proposed unless the configuration changed since.
Dry run
Every config write accepts the header Runledger-Dry-Run: true. It returns the normal response body with dry_run: true, changes, warnings and errors added, and writes nothing. Validation runs exactly as it would for a real write. The dashboard’s “Preview changes” button and the MCP validate_config tool use the same checks, so a person and an agent see the same warnings. A dry run is kept in the request logs, tagged Dry run, and the audit event of the real change that follows it has dry_run_preceded: true.
Warnings
Values outside the recommended ranges are accepted and come back as warnings with a code, a message and the path of the field. For example, a confirmation_window under one hour returns confirmation_window_below_recommended: the charge confirms almost at once, so only the reversal horizon protects you. Show warnings to the person who owns the decision. The ranges are on the outcome settlement page.
Proposals for live
A change to live configuration can be proposed by anyone with config:propose, which is what an agent holds in live mode, and decided only by a signed-in Admin. A Collaborator who changes live configuration in the dashboard makes a proposal the same way.
POST /v1/config_proposalstakes adocument, areasonand, optionally, theif_matchhash it was based on. It returns apendingproposal with the diff, the warnings, and areview_urlthat opens the diff in the dashboard.- An Admin reviews it in the dashboard and approves or rejects it. An Admin can approve any proposal, including one for notification or routing rules. The approver and any note are recorded, and the audit events the change creates carry the approver and the time as
approved_by.POST /v1/config_proposals/{id}/approveand/rejectwork only for a signed-in Admin: a key, including an agent key, gets403. - A proposal that nobody decides expires after 7 days.
Proposals show on the dashboard’s Audit log screen as “Pending approval”, and a notification rule on proposal.pending can tell the reviewers.
Notification rules
POST /v1/notification_rules tells your team when something needs them. Webhooks still carry events to your systems; this is for the people on your team.
A rule’s channel says how it is delivered. The set of channels is open, and destinations can be added. The built-in channels are:
Handle a channel you don’t recognize by its name rather than failing on it.
A rule fires once per event: two rules on one event send two notifications, one rule never sends twice. The webhook channel delivers the event itself to the rule’s endpoint, whether or not the endpoint subscribes to that type, so your handler sees the same body a subscription would; an event a rule’s lead time or threshold made says so in reason.notification_rule and goes to that endpoint alone. A dispute.decision_due rule covers the disputes opened after it exists, and a dispute decided before its lead time sends nothing. topup_chargeback.threshold_exceeded is judged when a chargeback lands, over the trailing thirty days, and fires when the figure passes the line, not again while it stays above it.
Notification rules are for your team. Alerts about a customer’s own balance or limits, such as balance.low and the usage and spend-limit thresholds, are webhook events sent to your endpoints. Runledger never emails your end customers; you decide how to reach them.
A threshold has no default. topup_chargeback.threshold_exceeded fires only at the threshold you set.
Outcome clock presets
GET /v1/outcome_definition_presets returns the recommended clocks for common outcomes, with their bounds and rationale, so the dashboard, the API and the MCP server all show the same values. Outcome settlement explains them.
See also
- Access, actors and audit covers who may apply or approve configuration.
- Recipes has complete documents for common billing models.
- Sandbox and test clocks covers testing what you applied.