Skip to navigation

Update a price rule

Every change makes a new version that applies to events from its effective_from (default now). Earlier events keep the price they were given. Set effective_from in the future to give your customers notice. In live mode an agent’s write is refused with 403 and proposal_required: put the same object in a config proposal. People change live configuration in the dashboard.

Authentication

AuthorizationBearer

A secret key (rl_sk_test_..., rl_sk_live_...) or a restricted key with limited scopes (rl_rk_test_..., rl_rk_live_...). A restricted key can carry agent: true and an expires_at, and is what a coding agent should hold. Keys end in a checksum so secret scanners can recognize them. People create, roll and revoke keys in the dashboard; GET /v1/api_keys lists them, masked.

Path parameters

price_rulestringRequired

The price rule ID (pr_...) or its key.

Headers

Runledger-Dry-RunbooleanOptional

Send true to see what the write would do without doing it. The response is the normal body with dry_run: true, changes (path, before, after), warnings and errors added, and nothing is stored. Validation runs as it would for a real write. The request is kept in request logs, tagged Dry run. When the same change is then made for real, its audit event has dry_run_preceded: true.

Request

This endpoint expects an object.
namestringOptional<=128 characters
descriptionstring or nullOptional<=200 characters

The label on invoices. On a change, null clears it.

currencystringOptional

Lowercase ISO 4217 code. Must match the currency of the rate cards the rule reads and of the plans that use it: Runledger doesn’t convert between currencies, so a rule that mixes them is a validation error.

basisenumOptionalDefaults to catalog

What cost_plus and formula rules take the cost from. catalog: the cost models and the event’s quantity and properties, the same at check() and track(). run_cost: the costs trace() recorded under the event’s run_id, for pass-through pricing after the work. check() can’t know that cost yet, so it prices from estimated_usage or, without it, from the observed average.

Allowed values:
inputslist of objectsOptional

cost_plus and formula rules on the catalog basis.

markup_percentstringOptional

cost_plus. The price is the cost times one plus this, as a decimal string: "0.4" is cost plus 40%. Send this or target_margin_percent.

target_margin_percentstringOptional

cost_plus. The price is the cost over one minus this, so the margin is this share of the price, as a decimal from 0 to 1. "0.3" is a 30% margin.

rowslist of objectsOptional

table rules.

formulastringOptional<=500 characters

formula rules. An expression over cost, quantity and numeric event properties written properties.<name>, with +, -, *, /, brackets, min(), max() and ceil(). It returns minor units of currency.

floor_decimalstring or nullOptional

The lowest price for one event, in minor units. The price is raised to it. On a change, null clears it.

cap_decimalstring or nullOptional

The highest price for one event, in minor units. The price is lowered to it. On a change, null clears it.

credit_value_decimalstringOptional

Prepaid plans. Minor units of currency that one credit is worth, used to turn the price into credits. Defaults to the plan’s top-up price per credit.

on_cost_changeenumOptionalDefaults to hold

What the rule does when a new rate card changes the cost it prices from, whether you added it or Runledger published a new catalog price. hold: it keeps pricing from the versions in force when you last saved it, so the margin moves and a person decides whether to change the price from a later date. follow: the price follows the new card from its effective_from.

Allowed values:
effective_fromdatetimeOptional
When this version starts to price events. Default now.
reasonstringOptional<=500 characters
Why the rule changed. Recorded in the audit log.

Response

The rule, at its new version.
idstring
object"price_rule"
keystring
namestring
versioninteger
Starts at 1. Every update adds one.
methodenum

cost_plus: the cost of the usage plus a markup or a target margin. table: a price looked up by dimension values. formula: an expression.

Allowed values:
currencystring
The rule's currency. It matches its rate cards and the plans that use it. Prices are never converted.
on_cost_changeenumDefaults to hold

What the rule does when a new rate card changes the cost it prices from, whether you added it or Runledger published a new catalog price. hold: it keeps pricing from the versions in force when you last saved it, so the margin moves and a person decides whether to change the price from a later date. follow: the price follows the new card from its effective_from.

Allowed values:
livemodeboolean
created_atdatetime
descriptionstringOptional
effective_fromdatetimeOptional
basisenumOptionalDefaults to catalog

What cost_plus and formula rules take the cost from. catalog: the cost models and the event’s quantity and properties, the same at check() and track(). run_cost: the costs trace() recorded under the event’s run_id, for pass-through pricing after the work. check() can’t know that cost yet, so it prices from estimated_usage or, without it, from the observed average.

Allowed values:
inputslist of objectsOptional
markup_percentstringOptional
target_margin_percentstringOptional
rowslist of objectsOptional
formulastringOptional
floor_decimalstringOptional
cap_decimalstringOptional
credit_value_decimalstringOptional
priced_fromlist of objectsOptional

The rate card versions this version prices from. Under hold, they stay until the rule is saved again.

actorobjectOptional

Who made a change. Runledger fills it in from the credential, so a client can’t claim to be someone else: an API key always acts as itself, the dashboard calls the API as the signed-in person, and the MCP server passes the client’s name and the person it acts for. A request that sends a Runledger-Actor header is refused with 400 parameter_unknown.

Errors

400
Bad Request Error
401
Unauthorized Error
403
Forbidden Error
404
Not Found Error
409
Conflict Error
422
Unprocessable Entity Error
429
Too Many Requests Error
500
Internal Server Error