# Rulesets - developer preview

Create and manage resolution rulesets and their child rules.

**Base URL:** `https://api.chargebackstop.com/v1/rulesets/`

**Authentication:** Bearer token via API key.

Required abilities:

* `rulesets:read` for GET endpoints
* `rulesets:write` for POST, PATCH, and DELETE endpoints

**Access scope model:**

* Organisation-level keys can access rulesets for their own organisation only.
* Admin partner-group keys can access rulesets across all organisations for their partner.
* Non-admin partner-group keys can access rulesets only for organisations assigned to their group.

***

## Rule types

A rule is defined by its `type` and a `parameters` object whose shape depends on the type. Each ruleset can contain at most one rule of each type. The same rule types apply to embedded rules on `POST /v1/rulesets` and to the nested `POST` / `PATCH` rule endpoints.

### AMOUNT

Matches the transaction amount against a threshold.

| Field             | Type    | Description                                                                                         |
| ----------------- | ------- | --------------------------------------------------------------------------------------------------- |
| `operator`        | string  | `GREATER_THAN`, `GREATER_THAN_OR_EQUAL`, `LESS_THAN`, `LESS_THAN_OR_EQUAL`, `EQUAL`, or `NOT_EQUAL` |
| `currency_code`   | string  | Three-letter currency code. Must be `USD`.                                                          |
| `amount_in_cents` | integer | Non-negative amount in cents.                                                                       |

{% hint style="info" %}
Only `USD` is accepted as the rule currency. If a transaction is in a different currency, its amount is automatically converted to USD before the rule is evaluated, so the rule still applies to non-USD transactions.
{% endhint %}

Example `parameters`:

```json
{
  "operator": "GREATER_THAN",
  "currency_code": "USD",
  "amount_in_cents": 5000
}
```

### DESCRIPTOR

Matches the transaction's statement descriptor against one or more entries.

| Field         | Type           | Description                    |
| ------------- | -------------- | ------------------------------ |
| `descriptors` | array\[object] | One or more descriptor entries |

Each descriptor entry:

| Field        | Type   | Description                         |
| ------------ | ------ | ----------------------------------- |
| `value`      | string | Descriptor string to match against. |
| `match_type` | string | `STARTS_WITH` or `EXACT_MATCH`      |

Example `parameters`:

```json
{
  "descriptors": [
    {"value": "NETFLIX", "match_type": "STARTS_WITH"},
    {"value": "SPOTIFY", "match_type": "EXACT_MATCH"}
  ]
}
```

***

## POST /v1/rulesets - create ruleset

Creates one ruleset and optionally creates child rules within the same request.

**API level:** Organisation-level and partner-level\
**Authentication:** `rulesets:write`

### Request body

| Field             | Type           | Description                                                                                     |
| ----------------- | -------------- | ----------------------------------------------------------------------------------------------- |
| `organisation_id` | string         | Organisation ID                                                                                 |
| `enrolment_ids`   | array\[string] | One or more enrolment IDs                                                                       |
| `outcome`         | string         | `REFUND`, `CANCEL`, `REFUND_AND_CANCEL`, or `ACCEPT_DISPUTE`                                    |
| `join_operator`   | string         | `AND` or `OR`                                                                                   |
| `is_enabled`      | boolean        | Optional, defaults to `true`                                                                    |
| `rules`           | array\[object] | Optional initial rules. Each entry has `type` and `parameters` — see [Rule types](#rule-types). |

{% hint style="info" %}
All selected enrolments must be accessible and must share the same enrolment type. For example, you cannot combine Ethoca and Verifi RDR enrolments in the same ruleset. If you need the same rules to apply to both, create one ruleset per enrolment type.

Only one rule of each type is allowed per ruleset.

Amount rules must use `USD`.

If any embedded rule fails validation, the entire ruleset creation is rolled back.
{% endhint %}

### Example 1 request

```bash
curl -X POST "https://api.chargebackstop.com/v1/rulesets/" \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "organisation_id": "org_xyz456",
    "enrolment_ids": ["enrl_abc123", "enrl_def456"],
    "outcome": "REFUND",
    "join_operator": "AND",
    "is_enabled": true,
    "rules": [
      {
        "type": "DESCRIPTOR",
        "parameters": {
          "descriptors": [
            {"value": "NETFLIX", "match_type": "STARTS_WITH"},
            {"value": "SPOTIFY", "match_type": "STARTS_WITH"}
          ]
        }
      },
      {
        "type": "AMOUNT",
        "parameters": {
          "operator": "GREATER_THAN",
          "currency_code": "USD",
          "amount_in_cents": 5000
        }
      }
    ]
  }'
```

### Example 1 response

```json
{
  "id": "rset_abc123",
  "organisation_id": "org_xyz456",
  "enrolment_ids": ["enrl_abc123", "enrl_def456"],
  "outcome": "REFUND",
  "join_operator": "AND",
  "is_enabled": true,
  "rules": [
    {
      "id": "resrule_desc123",
      "type": "DESCRIPTOR",
      "parameters": {
        "descriptors": [
          {"value": "NETFLIX", "match_type": "STARTS_WITH"},
          {"value": "SPOTIFY", "match_type": "STARTS_WITH"}
        ]
      },
      "created_at": "2026-05-05T10:00:00Z",
      "updated_at": "2026-05-05T10:00:00Z"
    },
    {
      "id": "resrule_amt123",
      "type": "AMOUNT",
      "parameters": {
        "operator": "GREATER_THAN",
        "currency_code": "USD",
        "amount_in_cents": 5000
      },
      "created_at": "2026-05-05T10:00:00Z",
      "updated_at": "2026-05-05T10:00:00Z"
    }
  ],
  "created_at": "2026-05-05T10:00:00Z",
  "updated_at": "2026-05-05T10:00:00Z"
}
```

***

## GET /v1/rulesets - list rulesets

Returns a paginated list of accessible rulesets.

**API level:** Organisation-level and partner-level\
**Authentication:** `rulesets:read`

### Query parameters

| Parameter         | Type    | Description                                                           |
| ----------------- | ------- | --------------------------------------------------------------------- |
| `organisation_id` | string  | Filter by organisation ID                                             |
| `sort`            | string  | `-created_at` (default), `created_at`, `-updated_at`, or `updated_at` |
| `limit`           | integer | Number of results per page                                            |
| `offset`          | integer | Number of results to skip                                             |

### Example 2 request

```bash
curl -X GET "https://api.chargebackstop.com/v1/rulesets/?organisation_id=org_xyz456&sort=-created_at&limit=20&offset=0" \
  -H "Authorization: Bearer <api_key>"
```

### Example 2 response

```json
{
  "items": [
    {
      "id": "rset_def456",
      "organisation_id": "org_xyz456",
      "enrolment_ids": ["enrl_abc123", "enrl_def456"],
      "outcome": "REFUND",
      "join_operator": "AND",
      "is_enabled": true,
      "rules": [],
      "created_at": "2026-05-05T10:00:00Z",
      "updated_at": "2026-05-05T10:00:00Z"
    }
  ],
  "count": 1
}
```

***

## GET /v1/rulesets/{ruleset\_id} - get ruleset by ID

Returns one accessible ruleset.

**API level:** Organisation-level and partner-level\
**Authentication:** `rulesets:read`

### Example 3 request

```bash
curl -X GET "https://api.chargebackstop.com/v1/rulesets/rset_abc123" \
  -H "Authorization: Bearer <api_key>"
```

### Example 3 response

```json
{
  "id": "rset_abc123",
  "organisation_id": "org_xyz456",
  "enrolment_ids": ["enrl_abc123"],
  "outcome": "ACCEPT_DISPUTE",
  "join_operator": "AND",
  "is_enabled": true,
  "rules": [
    {
      "id": "resrule_amt123",
      "type": "AMOUNT",
      "parameters": {
        "operator": "GREATER_THAN",
        "currency_code": "USD",
        "amount_in_cents": 5000
      },
      "created_at": "2026-05-05T10:00:00Z",
      "updated_at": "2026-05-05T10:00:00Z"
    }
  ],
  "created_at": "2026-05-05T10:00:00Z",
  "updated_at": "2026-05-05T10:00:00Z"
}
```

***

## PATCH /v1/rulesets/{ruleset\_id} - update ruleset

Updates one accessible ruleset.

**API level:** Organisation-level and partner-level\
**Authentication:** `rulesets:write`

### Request body

| Field           | Type           | Description                                                            |
| --------------- | -------------- | ---------------------------------------------------------------------- |
| `enrolment_ids` | array\[string] | Optional. One or more enrolment IDs                                    |
| `outcome`       | string         | Optional. `REFUND`, `CANCEL`, `REFUND_AND_CANCEL`, or `ACCEPT_DISPUTE` |
| `join_operator` | string         | Optional. `AND` or `OR`                                                |
| `is_enabled`    | boolean        | Optional. Whether the ruleset is enabled                               |

{% hint style="info" %}
Send only the mutable fields you want to change. Omitted fields keep their existing values.

`rules` is not accepted on this endpoint. Update child rules through the nested rule endpoints instead.

All selected enrolments must be accessible and must share the same enrolment type. For example, you cannot combine Ethoca and Verifi RDR enrolments in the same ruleset.
{% endhint %}

### Example 4 request

```bash
curl -X PATCH "https://api.chargebackstop.com/v1/rulesets/rset_abc123" \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "enrolment_ids": ["enrl_abc123", "enrl_def456"],
    "outcome": "CANCEL",
    "join_operator": "OR",
    "is_enabled": false
  }'
```

### Example 4 response

```json
{
  "id": "rset_abc123",
  "organisation_id": "org_xyz456",
  "enrolment_ids": ["enrl_abc123", "enrl_def456"],
  "outcome": "CANCEL",
  "join_operator": "OR",
  "is_enabled": false,
  "rules": [],
  "created_at": "2026-05-05T10:00:00Z",
  "updated_at": "2026-05-05T10:00:00Z"
}
```

***

## DELETE /v1/rulesets/{ruleset\_id} - delete ruleset

Deletes one accessible ruleset and its child rules.

**API level:** Organisation-level and partner-level\
**Authentication:** `rulesets:write`

{% hint style="info" %}
The response body is empty on success.
{% endhint %}

### Example 5 request

```bash
curl -X DELETE "https://api.chargebackstop.com/v1/rulesets/rset_abc123" \
  -H "Authorization: Bearer <api_key>"
```

### Example 5 response

```http
204 No Content
```

***

## POST /v1/rulesets/{ruleset\_id}/rules - add rule

Adds one rule to an existing accessible ruleset.

**API level:** Organisation-level and partner-level\
**Authentication:** `rulesets:write`

### Request body

| Field        | Type   | Description                                                           |
| ------------ | ------ | --------------------------------------------------------------------- |
| `type`       | string | `AMOUNT` or `DESCRIPTOR`. See [Rule types](#rule-types).              |
| `parameters` | object | Parameters for the selected rule type. See [Rule types](#rule-types). |

{% hint style="info" %}
Only one rule of each type is allowed per ruleset.

Amount rules must use `USD`.
{% endhint %}

### Example 6 request

```bash
curl -X POST "https://api.chargebackstop.com/v1/rulesets/rset_abc123/rules" \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "AMOUNT",
    "parameters": {
      "operator": "GREATER_THAN",
      "currency_code": "USD",
      "amount_in_cents": 5000
    }
  }'
```

### Example 6 response

```json
{
  "id": "resrule_amt123",
  "type": "AMOUNT",
  "parameters": {
    "operator": "GREATER_THAN",
    "currency_code": "USD",
    "amount_in_cents": 5000
  },
  "created_at": "2026-05-05T10:00:00Z",
  "updated_at": "2026-05-05T10:00:00Z"
}
```

***

## GET /v1/rulesets/{ruleset\_id}/rules/{rule\_id} - get rule by ID

Returns one accessible rule from an accessible ruleset.

**API level:** Organisation-level and partner-level\
**Authentication:** `rulesets:read`

### Example 7 request

```bash
curl -X GET "https://api.chargebackstop.com/v1/rulesets/rset_abc123/rules/resrule_amt123" \
  -H "Authorization: Bearer <api_key>"
```

### Example 7 response

```json
{
  "id": "resrule_amt123",
  "type": "AMOUNT",
  "parameters": {
    "operator": "GREATER_THAN",
    "currency_code": "USD",
    "amount_in_cents": 5000
  },
  "created_at": "2026-05-05T10:00:00Z",
  "updated_at": "2026-05-05T10:00:00Z"
}
```

***

## PATCH /v1/rulesets/{ruleset\_id}/rules/{rule\_id} - update rule

Updates one accessible rule within an accessible ruleset.

**API level:** Organisation-level and partner-level\
**Authentication:** `rulesets:write`

### Request body

| Field        | Type   | Description                                                           |
| ------------ | ------ | --------------------------------------------------------------------- |
| `type`       | string | Must match the existing rule type. See [Rule types](#rule-types).     |
| `parameters` | object | Parameters for the selected rule type. See [Rule types](#rule-types). |

{% hint style="info" %}
Rule type cannot be changed.

Amount rules must use `USD`.
{% endhint %}

### Example 8 request

```bash
curl -X PATCH "https://api.chargebackstop.com/v1/rulesets/rset_abc123/rules/resrule_amt123" \
  -H "Authorization: Bearer <api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "AMOUNT",
    "parameters": {
      "operator": "GREATER_THAN",
      "currency_code": "USD",
      "amount_in_cents": 7500
    }
  }'
```

### Example 8 response

```json
{
  "id": "resrule_amt123",
  "type": "AMOUNT",
  "parameters": {
    "operator": "GREATER_THAN",
    "currency_code": "USD",
    "amount_in_cents": 7500
  },
  "created_at": "2026-05-05T10:00:00Z",
  "updated_at": "2026-05-05T10:00:00Z"
}
```

***

## DELETE /v1/rulesets/{ruleset\_id}/rules/{rule\_id} - delete rule

Deletes one accessible rule from an accessible ruleset.

**API level:** Organisation-level and partner-level\
**Authentication:** `rulesets:write`

{% hint style="info" %}
The response body is empty on success.
{% endhint %}

### Example 9 request

```bash
curl -X DELETE "https://api.chargebackstop.com/v1/rulesets/rset_abc123/rules/resrule_amt123" \
  -H "Authorization: Bearer <api_key>"
```

### Example 9 response

```http
204 No Content
```

***

## Error examples

### Example 10: forbidden

```json
{
  "errors": [
    {
      "code": "FORBIDDEN",
      "message": "Forbidden"
    }
  ]
}
```

### Example 11: not found

```json
{
  "errors": [
    {
      "code": "NOT_FOUND",
      "message": "Not found"
    }
  ]
}
```

### Example 12: invalid currency

```json
{
  "errors": [
    {
      "code": "INVALID_CURRENCY_CODE",
      "message": "Only USD is allowed.",
      "field": "currency_code"
    }
  ]
}
```

### Example 13: rules not allowed on ruleset update

```json
{
  "errors": [
    {
      "code": "RULES_NOT_ALLOWED_ON_RULESET_UPDATE",
      "message": "Rules cannot be updated via this endpoint. Use PATCH /v1/rulesets/{ruleset_id}/rules/{rule_id} instead.",
      "field": "rules"
    }
  ]
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.chargebackstop.com/developer/api-documentation/rulesets-developer-preview.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
