> 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.

# Preview an event

POST https://api.runledger.co/v1/events/preview
Content-Type: application/json

Shows what `track()` would do with this event, without recording it: the price, the outcome charge and its clocks, the ledger entries, and any rules that would fire. Nothing is written. Use it to test configuration, and from coding agents before they wire up `track()`.

**Price with a rule.** For a usage event, `pricing` shows how a price rule priced it, line by line. By default that is the rule the customer's plan rate uses. Send `price_rule`, and optionally `price_rule_version`, to price the event with that rule and version instead, even when no plan rate uses it yet. That tests a rule before a plan points at it. The rule's currency must match the customer's plan.

**An upfront estimate.** `price` is what the event would cost, in the customer's balance unit, so a workflow can show "this will use about X credits" before it runs. It is an estimate: `track()` prices the event it receives.

Reference: https://docs.runledger.co/api-reference/events/preview

## Authentication

- `Authorization` header (bearer token, required) — 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.

## Request

### Body (application/json)

This endpoint expects a PreviewEventRequest.

- `name` (string, required)
- `idempotency_key` (string, optional)
- `customer_id` (string, optional)
- `external_customer_id` (string, optional)
- `timestamp` (datetime, optional)
- `quantity` (string, optional)
- `reference` (string, optional)
- `hold` (string, optional)
- `release_remainder` (boolean, optional, default: true)
- `agent_id` (string, optional)
- `member_id` (string, optional)
- `team_id` (string, optional)
- `run_id` (string, optional)
- `properties` (map from string to any, optional)
- `evidence` (Evidence, optional) — What shows an outcome happened, stamped on the outcome charge. Keep it short and factual; it is shown to people deciding disputes. Free text is sanitized before it reaches dashboards or agent tools.
- `price_rule` (string, optional) — The key of the price rule to price the event with, such as `video_cost_plus`. With it, `pricing` is returned even when no plan rate uses the rule. Without it, the event is priced by the rule its plan rate uses, if any. The rule's currency must match the customer's plan. An unknown key returns `404`.
- `price_rule_version` (integer, optional) — The version of `price_rule` to price with. Without it, the version in force at the event's `timestamp`. Needs `price_rule`.

## Response

### 200

The predicted effects.

- `object` ("event_preview", required)
- `kind` (enum, required) — What the event turned out to be. `usage`: charged at once. `outcome`: created a pending outcome charge. `signal`: evaluated against reversal rules. `unpriced`: stored with no effect.
  - Allowed values: `usage`, `outcome`, `signal`, `unpriced`
- `valid` (boolean, required) — Whether `track()` would accept the event.
- `would_create` (EventPreviewWouldCreate, required)
- `warnings` (list of EventWarning, required)
- `price` (string, optional) — What the event would cost, as a decimal string in the customer's balance unit (a credit type or a currency). Use it as an upfront "about X credits" estimate before the work runs.
- `credit_type` (string, optional)
- `currency` (string, optional)
- `pricing` (PricingDetail, optional) — How a price rule would price the event, line by line. Present when the event is priced by a rule: the rule its plan rate uses, or the one named by `price_rule` in the request, whether or not a plan rate uses it.
- `errors` (list of ErrorResponse, optional) — Why `track()` would reject the event.

## Errors

### 400 Bad Request Error

The request was malformed or a parameter was invalid. A configuration that fails validation, such as two equally specific overrides with overlapping dates, returns `config_invalid`.

- `type` (string, required) — A URI for the error type. It links to the error codes table in the docs, where each `code` is listed with its cause. Branch on `code`, not on `type`.
- `title` (string, required) — A short summary of the error type.
- `status` (integer, required) — The HTTP status code.
- `code` (enum, required) — A stable, machine-readable error code. New codes may be added.
  - Allowed values: `invalid_request`, `parameter_missing`, `parameter_invalid`, `parameter_unknown`, `authentication_failed`, `permission_denied`, `insufficient_scope`, `proposal_required`, `config_invalid`, `livemode_mismatch`, `resource_not_found`, `resource_already_exists`, `idempotency_key_in_use`, `idempotency_key_reused`, `invalid_state`, `outcome_charge_locked`, `hold_not_active`, `insufficient_balance`, `credit_limit_exceeded`, `plan_locked`, `test_clock_advancing`, `provider_error`, `rate_limited`, `api_error`, `service_unavailable`
- `request_id` (string, required) — The ID of the request. Quote it to support, or look it up in request logs.
- `retryable` (boolean, required) — Whether sending the same request again, with the same idempotency key, may succeed.
- `detail` (string, optional) — An explanation of this occurrence. For people; don't parse it.
- `param` (string, optional) — The request parameter at fault, as a dotted path.
- `required_scope` (string, optional) — The scope the call needed, on `insufficient_scope`. Ask a person to widen the key, or reconnect with it.
- `errors` (list of ConfigIssue, optional) — Only with `config_invalid`: each problem the configuration document has, with the path of the part at fault, so an agent can fix the document without a second call.
- `blocked_by` (list of ErrorResponseBlockedByItems, optional) — On an `invalid_state` that names the objects in the way, the objects that must change first. Removing a payment provider lists every routing rule that uses it (`object: routing_rule`) and every customer whose own `payment_provider` names it (`object: customer`), in one list.
- `doc_url` (string, optional) — A link to the error codes table in the docs, where this `code` is listed with its cause.

### 401 Unauthorized Error

The API key is missing, invalid or revoked.

- `type` (string, required) — A URI for the error type. It links to the error codes table in the docs, where each `code` is listed with its cause. Branch on `code`, not on `type`.
- `title` (string, required) — A short summary of the error type.
- `status` (integer, required) — The HTTP status code.
- `code` (enum, required) — A stable, machine-readable error code. New codes may be added.
  - Allowed values: `invalid_request`, `parameter_missing`, `parameter_invalid`, `parameter_unknown`, `authentication_failed`, `permission_denied`, `insufficient_scope`, `proposal_required`, `config_invalid`, `livemode_mismatch`, `resource_not_found`, `resource_already_exists`, `idempotency_key_in_use`, `idempotency_key_reused`, `invalid_state`, `outcome_charge_locked`, `hold_not_active`, `insufficient_balance`, `credit_limit_exceeded`, `plan_locked`, `test_clock_advancing`, `provider_error`, `rate_limited`, `api_error`, `service_unavailable`
- `request_id` (string, required) — The ID of the request. Quote it to support, or look it up in request logs.
- `retryable` (boolean, required) — Whether sending the same request again, with the same idempotency key, may succeed.
- `detail` (string, optional) — An explanation of this occurrence. For people; don't parse it.
- `param` (string, optional) — The request parameter at fault, as a dotted path.
- `required_scope` (string, optional) — The scope the call needed, on `insufficient_scope`. Ask a person to widen the key, or reconnect with it.
- `errors` (list of ConfigIssue, optional) — Only with `config_invalid`: each problem the configuration document has, with the path of the part at fault, so an agent can fix the document without a second call.
- `blocked_by` (list of ErrorResponseBlockedByItems, optional) — On an `invalid_state` that names the objects in the way, the objects that must change first. Removing a payment provider lists every routing rule that uses it (`object: routing_rule`) and every customer whose own `payment_provider` names it (`object: customer`), in one list.
- `doc_url` (string, optional) — A link to the error codes table in the docs, where this `code` is listed with its cause.

### 403 Forbidden Error

The key can't do this. A restricted or agent key lacks the scope (`insufficient_scope`, with `required_scope`), a live key called a sandbox-only endpoint, an agent tried a live config write that needs a proposal (`proposal_required`), or something only a signed-in person can do.

- `type` (string, required) — A URI for the error type. It links to the error codes table in the docs, where each `code` is listed with its cause. Branch on `code`, not on `type`.
- `title` (string, required) — A short summary of the error type.
- `status` (integer, required) — The HTTP status code.
- `code` (enum, required) — A stable, machine-readable error code. New codes may be added.
  - Allowed values: `invalid_request`, `parameter_missing`, `parameter_invalid`, `parameter_unknown`, `authentication_failed`, `permission_denied`, `insufficient_scope`, `proposal_required`, `config_invalid`, `livemode_mismatch`, `resource_not_found`, `resource_already_exists`, `idempotency_key_in_use`, `idempotency_key_reused`, `invalid_state`, `outcome_charge_locked`, `hold_not_active`, `insufficient_balance`, `credit_limit_exceeded`, `plan_locked`, `test_clock_advancing`, `provider_error`, `rate_limited`, `api_error`, `service_unavailable`
- `request_id` (string, required) — The ID of the request. Quote it to support, or look it up in request logs.
- `retryable` (boolean, required) — Whether sending the same request again, with the same idempotency key, may succeed.
- `detail` (string, optional) — An explanation of this occurrence. For people; don't parse it.
- `param` (string, optional) — The request parameter at fault, as a dotted path.
- `required_scope` (string, optional) — The scope the call needed, on `insufficient_scope`. Ask a person to widen the key, or reconnect with it.
- `errors` (list of ConfigIssue, optional) — Only with `config_invalid`: each problem the configuration document has, with the path of the part at fault, so an agent can fix the document without a second call.
- `blocked_by` (list of ErrorResponseBlockedByItems, optional) — On an `invalid_state` that names the objects in the way, the objects that must change first. Removing a payment provider lists every routing rule that uses it (`object: routing_rule`) and every customer whose own `payment_provider` names it (`object: customer`), in one list.
- `doc_url` (string, optional) — A link to the error codes table in the docs, where this `code` is listed with its cause.

### 404 Not Found Error

No object with that ID exists in this environment.

- `type` (string, required) — A URI for the error type. It links to the error codes table in the docs, where each `code` is listed with its cause. Branch on `code`, not on `type`.
- `title` (string, required) — A short summary of the error type.
- `status` (integer, required) — The HTTP status code.
- `code` (enum, required) — A stable, machine-readable error code. New codes may be added.
  - Allowed values: `invalid_request`, `parameter_missing`, `parameter_invalid`, `parameter_unknown`, `authentication_failed`, `permission_denied`, `insufficient_scope`, `proposal_required`, `config_invalid`, `livemode_mismatch`, `resource_not_found`, `resource_already_exists`, `idempotency_key_in_use`, `idempotency_key_reused`, `invalid_state`, `outcome_charge_locked`, `hold_not_active`, `insufficient_balance`, `credit_limit_exceeded`, `plan_locked`, `test_clock_advancing`, `provider_error`, `rate_limited`, `api_error`, `service_unavailable`
- `request_id` (string, required) — The ID of the request. Quote it to support, or look it up in request logs.
- `retryable` (boolean, required) — Whether sending the same request again, with the same idempotency key, may succeed.
- `detail` (string, optional) — An explanation of this occurrence. For people; don't parse it.
- `param` (string, optional) — The request parameter at fault, as a dotted path.
- `required_scope` (string, optional) — The scope the call needed, on `insufficient_scope`. Ask a person to widen the key, or reconnect with it.
- `errors` (list of ConfigIssue, optional) — Only with `config_invalid`: each problem the configuration document has, with the path of the part at fault, so an agent can fix the document without a second call.
- `blocked_by` (list of ErrorResponseBlockedByItems, optional) — On an `invalid_state` that names the objects in the way, the objects that must change first. Removing a payment provider lists every routing rule that uses it (`object: routing_rule`) and every customer whose own `payment_provider` names it (`object: customer`), in one list.
- `doc_url` (string, optional) — A link to the error codes table in the docs, where this `code` is listed with its cause.

### 429 Too Many Requests Error

Too many requests. Wait for the number of seconds in `Retry-After`.

- `type` (string, required) — A URI for the error type. It links to the error codes table in the docs, where each `code` is listed with its cause. Branch on `code`, not on `type`.
- `title` (string, required) — A short summary of the error type.
- `status` (integer, required) — The HTTP status code.
- `code` (enum, required) — A stable, machine-readable error code. New codes may be added.
  - Allowed values: `invalid_request`, `parameter_missing`, `parameter_invalid`, `parameter_unknown`, `authentication_failed`, `permission_denied`, `insufficient_scope`, `proposal_required`, `config_invalid`, `livemode_mismatch`, `resource_not_found`, `resource_already_exists`, `idempotency_key_in_use`, `idempotency_key_reused`, `invalid_state`, `outcome_charge_locked`, `hold_not_active`, `insufficient_balance`, `credit_limit_exceeded`, `plan_locked`, `test_clock_advancing`, `provider_error`, `rate_limited`, `api_error`, `service_unavailable`
- `request_id` (string, required) — The ID of the request. Quote it to support, or look it up in request logs.
- `retryable` (boolean, required) — Whether sending the same request again, with the same idempotency key, may succeed.
- `detail` (string, optional) — An explanation of this occurrence. For people; don't parse it.
- `param` (string, optional) — The request parameter at fault, as a dotted path.
- `required_scope` (string, optional) — The scope the call needed, on `insufficient_scope`. Ask a person to widen the key, or reconnect with it.
- `errors` (list of ConfigIssue, optional) — Only with `config_invalid`: each problem the configuration document has, with the path of the part at fault, so an agent can fix the document without a second call.
- `blocked_by` (list of ErrorResponseBlockedByItems, optional) — On an `invalid_state` that names the objects in the way, the objects that must change first. Removing a payment provider lists every routing rule that uses it (`object: routing_rule`) and every customer whose own `payment_provider` names it (`object: customer`), in one list.
- `doc_url` (string, optional) — A link to the error codes table in the docs, where this `code` is listed with its cause.

### 500 Internal Server Error

Something went wrong on Runledger's side. Safe to retry with the same idempotency key.

- `type` (string, required) — A URI for the error type. It links to the error codes table in the docs, where each `code` is listed with its cause. Branch on `code`, not on `type`.
- `title` (string, required) — A short summary of the error type.
- `status` (integer, required) — The HTTP status code.
- `code` (enum, required) — A stable, machine-readable error code. New codes may be added.
  - Allowed values: `invalid_request`, `parameter_missing`, `parameter_invalid`, `parameter_unknown`, `authentication_failed`, `permission_denied`, `insufficient_scope`, `proposal_required`, `config_invalid`, `livemode_mismatch`, `resource_not_found`, `resource_already_exists`, `idempotency_key_in_use`, `idempotency_key_reused`, `invalid_state`, `outcome_charge_locked`, `hold_not_active`, `insufficient_balance`, `credit_limit_exceeded`, `plan_locked`, `test_clock_advancing`, `provider_error`, `rate_limited`, `api_error`, `service_unavailable`
- `request_id` (string, required) — The ID of the request. Quote it to support, or look it up in request logs.
- `retryable` (boolean, required) — Whether sending the same request again, with the same idempotency key, may succeed.
- `detail` (string, optional) — An explanation of this occurrence. For people; don't parse it.
- `param` (string, optional) — The request parameter at fault, as a dotted path.
- `required_scope` (string, optional) — The scope the call needed, on `insufficient_scope`. Ask a person to widen the key, or reconnect with it.
- `errors` (list of ConfigIssue, optional) — Only with `config_invalid`: each problem the configuration document has, with the path of the part at fault, so an agent can fix the document without a second call.
- `blocked_by` (list of ErrorResponseBlockedByItems, optional) — On an `invalid_state` that names the objects in the way, the objects that must change first. Removing a payment provider lists every routing rule that uses it (`object: routing_rule`) and every customer whose own `payment_provider` names it (`object: customer`), in one list.
- `doc_url` (string, optional) — A link to the error codes table in the docs, where this `code` is listed with its cause.

## Types

### Evidence

What shows an outcome happened, stamped on the outcome charge. Keep it short and factual; it is shown to people deciding disputes. Free text is sanitized before it reaches dashboards or agent tools.

- `description` (string, optional) — A plain-language summary.
- `url` (string, optional) — A link to the record in your system, such as the conversation transcript.
- `properties` (map from string to any, optional) — Up to 50 flat key-value pairs, such as a satisfaction score or the agent's confidence.

### EventPreviewWouldCreate

- `ledger_entries` (list of EventPreviewWouldCreateLedgerEntriesItems, required)
- `reversals` (list of EventPreviewWouldCreateReversalsItems, required) — Outcome charges a reversal rule would reverse, and the rule.
- `disputes` (list of EventPreviewWouldCreateDisputesItems, required) — Outcome charges a rule would open a dispute on, and the rule.
- `outcome_charge` (EventPreviewWouldCreateOutcomeCharge, optional) — The outcome charge that would be created.

### EventWarning

- `code` (enum, required) — A stable warning code. New codes may be added. `margin_below_guardrail` is the warning for a margin guardrail whose action is `warn`, and for any breach seen by `track()`; the denial from a `block` guardrail is `margin_below_floor`. `spend_limit_exceeded` and `allowance_exhausted` are what `track()` reports when work that already happened took a limit or window past its amount.
  - Allowed values: `no_rate_for_event`, `no_active_subscription`, `reference_not_found`, `reversal_horizon_passed`, `outcome_charge_already_reversed`, `duplicate_outcome_for_reference`, `capture_exceeded_hold`, `balance_overdrawn`, `rate_not_found`, `margin_below_guardrail`, `no_cost_estimate`, `catalog_model_available`, `spend_limit_exceeded`, `allowance_exhausted`
- `message` (string, required)

### PricingDetail

How a price rule priced a usage event.

- `price_rule` (string, required) — The rule's key.
- `price_rule_version` (integer, required)
- `method` (enum, required) — `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: `cost_plus`, `table`, `formula`
- `price` (string, required) — Decimal minor units, after the floor and the cap.
- `basis` (enum, optional, default: 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: `catalog`, `run_cost`
- `lines` (list of CostLine, optional) — The cost lines the price was built from, for `cost_plus` and `formula` rules on the `catalog` basis.
- `cost` (string, optional) — Decimal minor units. The summed cost of `lines`.
- `floor_applied` (boolean, optional)
- `cap_applied` (boolean, optional)

### ErrorResponse

An RFC 9457 problem details object with Runledger's extension members.

- `type` (string, required) — A URI for the error type. It links to the error codes table in the docs, where each `code` is listed with its cause. Branch on `code`, not on `type`.
- `title` (string, required) — A short summary of the error type.
- `status` (integer, required) — The HTTP status code.
- `code` (enum, required) — A stable, machine-readable error code. New codes may be added.
  - Allowed values: `invalid_request`, `parameter_missing`, `parameter_invalid`, `parameter_unknown`, `authentication_failed`, `permission_denied`, `insufficient_scope`, `proposal_required`, `config_invalid`, `livemode_mismatch`, `resource_not_found`, `resource_already_exists`, `idempotency_key_in_use`, `idempotency_key_reused`, `invalid_state`, `outcome_charge_locked`, `hold_not_active`, `insufficient_balance`, `credit_limit_exceeded`, `plan_locked`, `test_clock_advancing`, `provider_error`, `rate_limited`, `api_error`, `service_unavailable`
- `request_id` (string, required) — The ID of the request. Quote it to support, or look it up in request logs.
- `retryable` (boolean, required) — Whether sending the same request again, with the same idempotency key, may succeed.
- `detail` (string, optional) — An explanation of this occurrence. For people; don't parse it.
- `param` (string, optional) — The request parameter at fault, as a dotted path.
- `required_scope` (string, optional) — The scope the call needed, on `insufficient_scope`. Ask a person to widen the key, or reconnect with it.
- `errors` (list of ConfigIssue, optional) — Only with `config_invalid`: each problem the configuration document has, with the path of the part at fault, so an agent can fix the document without a second call.
- `blocked_by` (list of ErrorResponseBlockedByItems, optional) — On an `invalid_state` that names the objects in the way, the objects that must change first. Removing a payment provider lists every routing rule that uses it (`object: routing_rule`) and every customer whose own `payment_provider` names it (`object: customer`), in one list.
- `doc_url` (string, optional) — A link to the error codes table in the docs, where this `code` is listed with its cause.

### ConfigIssue

A problem or warning about a part of a configuration document.

- `code` (string, required) — A stable code. New codes may be added.
- `message` (string, required)
- `path` (string, optional) — Where in the document, as a dotted path.

### ErrorResponseBlockedByItems

- `object` (enum, required) — The kind of object in the way: a routing rule, or a customer with a `payment_provider` override.
  - Allowed values: `routing_rule`, `customer`
- `id` (string, required) — The object's ID, `rr_...` for a routing rule and `cus_...` for a customer.

### EventPreviewWouldCreateLedgerEntriesItems

- `type` (enum, required) — `grant`, `grant_expired` and `grant_voided` move credits in and out. `hold` reserves. `usage` and `outcome` charge. `outcome_reversed` gives back. `invoiced` moves a postpaid period's charges onto its invoice.
  - Allowed values: `grant`, `grant_expired`, `grant_voided`, `hold`, `usage`, `outcome`, `outcome_reversed`, `invoiced`
- `status` (enum, required) — `pending` counts as held. `posted` is final. `archived` is a pending entry that was released and never posted.
  - Allowed values: `pending`, `posted`, `archived`
- `amount` (string, required)

### EventPreviewWouldCreateReversalsItems

- `outcome_charge` (string, required)
- `rule` (string, required)

### EventPreviewWouldCreateDisputesItems

- `outcome_charge` (string, required)
- `rule` (string, required)

### EventPreviewWouldCreateOutcomeCharge

The outcome charge that would be created.

- `outcome_definition` (string, required)
- `outcome_definition_version` (integer, required)
- `amount` (string, required)
- `confirmation_due_at` (datetime, required)

### CostLine

How one usage line was priced.

- `unit` (string, required)
- `quantity` (string, required)
- `dimensions` (map from string to string, optional)
- `cost_model` (string, optional) — The cost model ID.
- `rate_card` (string, optional) — The rate card that priced the line.
- `rate_card_version` (integer, optional)
- `rate_source` (enum, optional) — Which rate priced the line. `catalog`: the provider price catalog, unchanged. `override`: one of the cost model's overrides, named in `override`. `custom`: a rate card you entered.
  - Allowed values: `catalog`, `override`, `custom`
- `override` (string, optional) — The key of the override that priced the line. Only when `rate_source` is `override`.
- `catalog_price` (string, optional) — The catalog price version behind the rate, for `catalog` and `override` lines.
- `cost` (DecimalMoney, optional) — Left out when no rate matched; the warning `rate_not_found` says so.

### DecimalMoney

An amount of money that can hold fractions of a minor unit, such as a per-token cost.

- `amount_decimal` (string, required) — Minor units as a decimal string. "0.042" is 0.042 US cents.
- `currency` (string, required)

## Examples

**Request**

```json
{
  "name": "resolution.chat"
}
```

**Response**

```json
{
  "object": "string",
  "kind": "usage",
  "valid": true,
  "would_create": {
    "ledger_entries": [
      {
        "type": "grant",
        "status": "pending",
        "amount": "string"
      }
    ],
    "reversals": [
      {
        "outcome_charge": "string",
        "rule": "string"
      }
    ],
    "disputes": [
      {
        "outcome_charge": "string",
        "rule": "string"
      }
    ],
    "outcome_charge": {
      "outcome_definition": "string",
      "outcome_definition_version": 1,
      "amount": "string",
      "confirmation_due_at": "2024-01-15T09:30:00Z"
    }
  },
  "warnings": [
    {
      "code": "no_rate_for_event",
      "message": "string"
    }
  ],
  "price": "string",
  "credit_type": "string",
  "currency": "string",
  "pricing": {
    "price_rule": "video_cost_plus",
    "price_rule_version": 1,
    "method": "cost_plus",
    "price": "134.4",
    "basis": "catalog",
    "lines": [
      {
        "unit": "string",
        "quantity": "string",
        "dimensions": {},
        "cost_model": "cm_6bR3xN8vQe",
        "rate_card": "rc_4tG9wK2nPd",
        "rate_card_version": 1,
        "rate_source": "catalog",
        "override": "textco_negotiated",
        "catalog_price": "catp_9cW4hL6rBv",
        "cost": {
          "amount_decimal": "0.042",
          "currency": "usd"
        }
      }
    ],
    "cost": "96",
    "floor_applied": true,
    "cap_applied": true
  },
  "errors": [
    {
      "type": "https://docs.runledger.co/reference/idempotency-and-errors#error-codes",
      "title": "Insufficient balance",
      "status": 402,
      "code": "invalid_request",
      "request_id": "req_7Hc2Lq0vTz8d",
      "retryable": true,
      "detail": "The hold needs 400 ai_credits but 120 are available.",
      "param": "events.3.timestamp",
      "required_scope": "config:write",
      "errors": [
        {
          "code": "confirmation_window_short",
          "message": "The charge confirms almost at once, so only the reversal horizon protects you.",
          "path": "outcome_definitions.0.confirmation_window"
        }
      ],
      "blocked_by": [
        {
          "object": "routing_rule",
          "id": "rr_3vT8nK2xWa"
        }
      ],
      "doc_url": "https://docs.runledger.co/reference/idempotency-and-errors#error-codes"
    }
  ]
}
```

**SDK Code**

```python
import requests

url = "https://api.runledger.co/v1/events/preview"

payload = { "name": "resolution.chat" }
headers = {
    "Authorization": "Bearer <api_key>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.runledger.co/v1/events/preview';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <api_key>', 'Content-Type': 'application/json'},
  body: '{"name":"resolution.chat"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.runledger.co/v1/events/preview"

	payload := strings.NewReader("{\n  \"name\": \"resolution.chat\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <api_key>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.runledger.co/v1/events/preview")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <api_key>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"name\": \"resolution.chat\"\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.runledger.co/v1/events/preview")
  .header("Authorization", "Bearer <api_key>")
  .header("Content-Type", "application/json")
  .body("{\n  \"name\": \"resolution.chat\"\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.runledger.co/v1/events/preview', [
  'body' => '{
  "name": "resolution.chat"
}',
  'headers' => [
    'Authorization' => 'Bearer <api_key>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.runledger.co/v1/events/preview");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <api_key>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"name\": \"resolution.chat\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <api_key>",
  "Content-Type": "application/json"
]
let parameters = ["name": "resolution.chat"] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.runledger.co/v1/events/preview")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```