Skip to navigation

Update a margin guardrail

Changes the floor, the action, the scope or whether it is enabled. 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

margin_guardrailstringRequired

The margin guardrail ID (mg_...) 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
applies_toobjectOptional
Every condition you send must match. A guardrail with none covers all work.
basisenumOptionalDefaults to expected

expected: the margin the work should have, from its price and its expected cost at check() time. realized: confirmed revenue minus cost over the trailing window for the work the guardrail covers, as the margin report counts it, so reversals lower it.

Allowed values:
min_margin_percentstringOptional

The lowest margin allowed, as a decimal from 0 to 1 of the price. "0.25" is 25%. Negative values are not accepted.

actionenumOptionalDefaults to warn

warn adds warnings and a webhook. block also denies in check().

Allowed values:
windowstringOptional

An ISO 8601 duration. For realized, the trailing range the margin is read over. For expected, the range the observed average cost is read over when check() has no estimated_usage. Default P7D.

enabledbooleanOptionalDefaults to true

Response

The guardrail.
idstring
object"margin_guardrail"
keystring
namestring
applies_toobject
Every condition you send must match. A guardrail with none covers all work.
basisenumDefaults to expected

expected: the margin the work should have, from its price and its expected cost at check() time. realized: confirmed revenue minus cost over the trailing window for the work the guardrail covers, as the margin report counts it, so reversals lower it.

Allowed values:
min_margin_percentstring
actionenumDefaults to warn

warn adds warnings and a webhook. block also denies in check().

Allowed values:
windowstring
enabledboolean
livemodeboolean
created_atdatetime
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