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

# Create an outcome definition

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

Defines one kind of outcome you charge for: the event that reports it, the criteria you agreed with your customers, the two clocks, the reversal rules and the dispute settings. Plans set its price. The clocks have no silent default: send them, or send a `preset` from `GET /v1/outcome_definition_presets` and the server fills in the values you left out and stores them explicitly. Values outside the recommended ranges are accepted and come back as `warnings`.

Reference: https://docs.runledger.co/api-reference/outcome-definitions/create

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

- `key` (string, required) — Your stable identifier. Can't change.
- `name` (string, required)
- `event_name` (string, required) — The `track()` event that reports this outcome. Unique across outcome definitions.
- `criteria` (string, required) — What counts as this outcome, in the words you agreed with your customers. Stamped on every charge by version.
- `preset` (string, optional) — A preset `key`, such as `support_chat`, that fills in `confirmation_window`, `reversal_horizon` and `dispute_settings` where you don't send them. The stored definition holds explicit values and echoes the preset's key, so changing a preset later never changes it.
- `confirmation_window` (string, optional) — How long a new charge stays pending before it confirms by default, as an ISO 8601 duration from PT0S to P30D. Required unless `preset` is sent. Recommended PT1H to P7D; outside that range the response carries a warning.
- `reversal_horizon` (string, optional) — How long after confirmation a charge can still be reversed, as an ISO 8601 duration from PT0S to P180D. After it passes, the charge locks, unless a dispute is still open. Required unless `preset` is sent. Recommended P7D to P90D; outside that range the response carries a warning.
- `reversal_rules` (list of ReversalRule, optional)
- `dispute_settings` (DisputeSettings, optional)
- `metadata` (map from string to string, optional) — Up to 50 keys of your own, with keys up to 40 characters and values up to 500 characters.

## Response

### 200

The new outcome definition, at version 1.

- `id` (string, required)
- `object` ("outcome_definition", required)
- `key` (string, required)
- `name` (string, required)
- `event_name` (string, required)
- `criteria` (string, required)
- `version` (integer, required) — Starts at 1 and goes up by one with each change to terms.
- `confirmation_window` (string, required)
- `reversal_horizon` (string, required)
- `reversal_rules` (list of ReversalRule, required)
- `dispute_settings` (DisputeSettings, required)
- `metadata` (map from string to string, required) — Up to 50 keys of your own, with keys up to 40 characters and values up to 500 characters.
- `livemode` (boolean, required)
- `created_at` (datetime, required)
- `version_created_at` (datetime, required) — When this version took effect.
- `preset` (string, optional) — The preset used to fill in values when this version was made, if any. The values below are explicit either way.
- `warnings` (list of ConfigIssue, optional) — Only on create and update responses. Values outside the recommended ranges, with the reason.
- `actor` (Actor, optional) — Who made this version.
- `stats` (OutcomeDefinitionStats, optional) — The last 30 days, across all versions.

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

### 409 Conflict Error

The object is in a state that doesn't allow this (`invalid_state`, for example approving a stale config proposal or deleting a price rule a plan rate still uses), or a request with the same idempotency key is still in progress.

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

### 422 Unprocessable Entity Error

The idempotency key was already used with a different request body.

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

### ReversalRule

When a signal event with `event_name` arrives for a charge with the same customer and reference, and the condition holds, take the action. Rules run in order and the first match wins.

- `key` (string, required) — Your stable name for the rule, recorded on the reversals and disputes it creates.
- `event_name` (string, required) — The signal event this rule listens for.
- `action` (enum, required) — `reverse` reverses the charge at once. `open_dispute` opens a dispute for you to decide.
  - Allowed values: `reverse`, `open_dispute`
- `condition` (RuleCondition, optional) — A test on one property of the signal event. Numbers compare numerically.
- `applies_to` (enum, optional, default: any) — Which charges the rule applies to.
  - Allowed values: `pending`, `confirmed`, `any`
- `reason_code` (enum, optional) — Why a charge was reversed. New codes may be added.
  - Allowed values: `not_resolved`, `customer_unhappy`, `escalated_to_human`, `duplicate`, `incorrect_amount`, `other`

### DisputeSettings

- `decision_window` (string, optional) — How long you have to decide a dispute, as an ISO 8601 duration. It has no default: send it with the definition, or send a `preset`, which fills it in (`P7D` in `support_chat`). Minimum PT24H, maximum P30D. The minimum is there because `dispute.decision_due` fires 24 hours before the deadline. Recommended PT24H to P14D.
- `default_decision` (enum, optional, default: reverse) — What happens if nobody decides in time. Default `reverse`, so an ignored complaint doesn't stand.
  - Allowed values: `reverse`, `uphold`

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

### Actor

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

- `type` (enum, required) — `user`: a signed-in person, including a person at Runledger support acting in your account, whose `name` reads `Runledger support`. `agent`: an agent connected through an OAuth session or an agent key. `key`: any other API key. `rule`: a reversal rule. `system`: Runledger itself, such as a clock.
  - Allowed values: `user`, `agent`, `key`, `rule`, `system`
- `id` (string, optional) — The user, key or agent session ID. Left out for `rule` and `system`, except a change a customer makes on the customer view, which carries the customer session's ID.
- `name` (string, optional) — A display name, such as a person's name, a key's name or the MCP client.
- `on_behalf_of` (string, optional) — The person an agent acts for, when known.
- `client` (string, optional) — The software that made the call, such as an MCP client or SDK.

### OutcomeDefinitionStats

The last 30 days, across all versions.

- `charges` (integer, required)
- `confirmed` (integer, required)
- `reversed` (integer, required)
- `disputed` (integer, required)
- `reversal_rate` (string, required) — Reversed charges over all settled charges, from 0 to 1.
- `dispute_rate` (string, required)

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

### RuleCondition

A test on one property of the signal event. Numbers compare numerically.

- `property` (string, required) — A key in the signal event's `properties`.
- `operator` (enum, required)
  - Allowed values: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `exists`
- `value` (string, optional) — The value to compare with, as a string. Not used with `exists`.

## Examples

**Request**

```json
{
  "key": "chat_resolution",
  "name": "Chat resolution",
  "event_name": "resolution.chat",
  "criteria": "The customer did not reply within 24 hours and did not ask for a person."
}
```

**Response**

```json
{
  "id": "od_7cV2bN5mXq",
  "object": "string",
  "key": "chat_resolution",
  "name": "Chat resolution",
  "event_name": "resolution.chat",
  "criteria": "string",
  "version": 3,
  "confirmation_window": "PT24H",
  "reversal_horizon": "P30D",
  "reversal_rules": [
    {
      "key": "reopened",
      "event_name": "conversation.reopened",
      "action": "reverse",
      "condition": {
        "property": "csat",
        "operator": "eq",
        "value": "2"
      },
      "applies_to": "any",
      "reason_code": "not_resolved"
    }
  ],
  "dispute_settings": {
    "decision_window": "P7D",
    "default_decision": "reverse"
  },
  "metadata": {},
  "livemode": true,
  "created_at": "2024-01-15T09:30:00Z",
  "version_created_at": "2024-01-15T09:30:00Z",
  "preset": "support_chat",
  "warnings": [
    {
      "code": "confirmation_window_short",
      "message": "The charge confirms almost at once, so only the reversal horizon protects you.",
      "path": "outcome_definitions.0.confirmation_window"
    }
  ],
  "actor": {
    "type": "user",
    "id": "usr_4tN8vB2cXk",
    "name": "Claude Code",
    "on_behalf_of": "usr_4tN8vB2cXk",
    "client": "claude-code"
  },
  "stats": {
    "charges": 4210,
    "confirmed": 3980,
    "reversed": 168,
    "disputed": 31,
    "reversal_rate": "0.0405",
    "dispute_rate": "0.0074"
  }
}
```

**SDK Code**

```python
import requests

url = "https://api.runledger.co/v1/outcome_definitions"

payload = {
    "key": "chat_resolution",
    "name": "Chat resolution",
    "event_name": "resolution.chat",
    "criteria": "The customer did not reply within 24 hours and did not ask for a person."
}
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/outcome_definitions';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <api_key>', 'Content-Type': 'application/json'},
  body: '{"key":"chat_resolution","name":"Chat resolution","event_name":"resolution.chat","criteria":"The customer did not reply within 24 hours and did not ask for a person."}'
};

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/outcome_definitions"

	payload := strings.NewReader("{\n  \"key\": \"chat_resolution\",\n  \"name\": \"Chat resolution\",\n  \"event_name\": \"resolution.chat\",\n  \"criteria\": \"The customer did not reply within 24 hours and did not ask for a person.\"\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/outcome_definitions")

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  \"key\": \"chat_resolution\",\n  \"name\": \"Chat resolution\",\n  \"event_name\": \"resolution.chat\",\n  \"criteria\": \"The customer did not reply within 24 hours and did not ask for a person.\"\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/outcome_definitions")
  .header("Authorization", "Bearer <api_key>")
  .header("Content-Type", "application/json")
  .body("{\n  \"key\": \"chat_resolution\",\n  \"name\": \"Chat resolution\",\n  \"event_name\": \"resolution.chat\",\n  \"criteria\": \"The customer did not reply within 24 hours and did not ask for a person.\"\n}")
  .asString();
```

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

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.runledger.co/v1/outcome_definitions', [
  'body' => '{
  "key": "chat_resolution",
  "name": "Chat resolution",
  "event_name": "resolution.chat",
  "criteria": "The customer did not reply within 24 hours and did not ask for a person."
}',
  'headers' => [
    'Authorization' => 'Bearer <api_key>',
    'Content-Type' => 'application/json',
  ],
]);

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

```csharp
using RestSharp;

var client = new RestClient("https://api.runledger.co/v1/outcome_definitions");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <api_key>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"key\": \"chat_resolution\",\n  \"name\": \"Chat resolution\",\n  \"event_name\": \"resolution.chat\",\n  \"criteria\": \"The customer did not reply within 24 hours and did not ask for a person.\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <api_key>",
  "Content-Type": "application/json"
]
let parameters = [
  "key": "chat_resolution",
  "name": "Chat resolution",
  "event_name": "resolution.chat",
  "criteria": "The customer did not reply within 24 hours and did not ask for a person."
] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://api.runledger.co/v1/outcome_definitions")! 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()
```