# Update queue rule

> PUT /v1/routing/queue-rules/{id} · Queues and routing API

Source: https://developer.kustomer.com/api/queues-and-routing/update-queue-rule

```http
PUT https://{orgname}.api.kustomerapp.com/v1/routing/queue-rules/{id}
Authorization: Bearer <API key>
```

## Authorization

Requires any one of these roles: `org.permission.queue_rule.update`, `org.permission.routing.update`; or legacy `org.admin.routing.write`. The API key or user must hold at least one of them. Legacy roles predate permission sets and still work.

Updates a queue rule based on its unique ID.

## About Queue rules

Queue rules decide which queue a new conversation goes to. They are an ordered list of conditions on the conversation, its customer and its latest message; the first enabled rule that matches picks the queue.

Admins build queue rules in Kustomer's routing settings, as one ordered list for the whole org. Routing runs the list when a conversation needs an agent and has no queue yet: no queue or external queue has been set, and no user is assigned. It checks the enabled rules from top to bottom and stops at the first match, so a specific rule such as "VIP customers" must sit above a broad one such as "All email". If no rule matches, the conversation goes to the org's default [queue](https://developer.kustomer.com/api/queues-and-routing#queues). A conversation that already has a queue, for example one set by a workflow or a transfer, skips the rules.

#### Criteria

`criteria` holds two lists of conditions. A rule matches when every condition in `and` is true and, if `or` has any conditions, at least one of those is true. A rule needs at least one condition in either list.

```json
{
  "and": [
    { "conversation_channel": { "operator": "equals", "value": "email" } },
    { "customer_custom_isVipBool": { "operator": "equals", "value": true } }
  ],
  "or": []
}
```

Each condition is keyed by a field name prefixed with the object it reads: `conversation_`, `customer_` or `message_` (the conversation's latest message). Custom attributes use `_custom_`, as in `customer_custom_isVipBool`. [`GET /v1/routing/queue-rules-criteria`](https://developer.kustomer.com/api/queues-and-routing/get-queue-criteria) lists the fields you can use and the operators each field type supports; strings take `equals`, `not_equals` and `contains`, and numbers take `equals`, `gte` and `lte`. Every condition needs a `value`, except those using `is_set` or `not_set`.

#### Choosing the queue

A rule points at its queue in one of two ways:

| Field | Use |
| --- | --- |
| `queue` | A fixed queue ID. It can't be the default queue; that fails with `409 Conflict`. |
| `queueKey` | A Handlebars template that is filled in from the conversation, customer and latest message, then matched against queue `key` values. One rule can route to many queues, such as one per region. If the result matches no queue, the conversation goes to the default queue. |

#### Which endpoint to use

| To | Call |
| --- | --- |
| List rules in the order routing checks them | [`GET /v1/routing/queue-rules`](https://developer.kustomer.com/api/queues-and-routing/get-queue-rules), with `enabled=true` for active rules only |
| Read one rule | [`GET /v1/routing/queue-rules/{id}`](https://developer.kustomer.com/api/queues-and-routing/get-queue-rule) |
| Add a rule to the end of the list | [`POST /v1/routing/queue-rules`](https://developer.kustomer.com/api/queues-and-routing/create-queue-rule) |
| Change or remove a rule | [`PUT`](https://developer.kustomer.com/api/queues-and-routing/update-queue-rule) or [`DELETE /v1/routing/queue-rules/{id}`](https://developer.kustomer.com/api/queues-and-routing/delete-queue-rule) |
| Reorder the rules | [`PUT /v1/routing/queue-rules/order`](https://developer.kustomer.com/api/queues-and-routing/update-queue-rule-order) |
| See which fields and operators rules can use | [`GET /v1/routing/queue-rules-criteria`](https://developer.kustomer.com/api/queues-and-routing/get-queue-criteria) |

Create and update both need `name`, `criteria`, and either `queue` or `queueKey`; send the whole rule on update, because leaving out `queue` clears it. Rules are enabled unless you send `enabled: false`. The order request must list every rule ID exactly once, or it fails with `400`. The number of rules per org is capped by your subscription, and creating one past the cap fails with `409 Conflict`. Rule changes apply to conversations routed after the change; conversations already in a queue stay where they are.

Related: [Queues](https://developer.kustomer.com/api/queues-and-routing#queues), [Work items](https://developer.kustomer.com/api/queues-and-routing#work-items), [Conditions and expressions](https://developer.kustomer.com/docs/workflows/conditions-and-expressions)

### Recipes

#### 1. Add a rule that routes VIP customers first

Send conversations from VIP customers to their own queue, placing the new rule at the top so broader rules don't catch them first.

**Step 1.** [`GET /v1/routing/queue-rules-criteria`](https://developer.kustomer.com/api/queues-and-routing/get-queue-criteria.md). Check which operators a field supports. Each entry in `fields.properties` names an operator group, and `fields.definitions` lists that group's operators. This list covers standard fields only; custom attributes follow the `<object>_custom_<name>` pattern, such as `customer_custom_isVipBool`, and take the operators for their type.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/routing/queue-rules-criteria" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/routing/queue-rules-criteria \
  | jq '.data.attributes.fields | .definitions[.properties.conversation_channel.operator].enum'
```

**Step 2.** [`POST /v1/routing/queue-rules`](https://developer.kustomer.com/api/queues-and-routing/create-queue-rule.md). Create the rule with `name`, `criteria` and the target `queue` ID. New rules go to the end of the order, and the response's `id` is what you'll move.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/routing/queue-rules" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"name\": \"VIP customers\", \"queue\": \"$VIP_QUEUE_ID\", \"criteria\": {\"and\": [{\"customer_custom_isVipBool\": {\"operator\": \"equals\", \"value\": true}}], \"or\": []}}"
```

```bash title="kusty"
kusty api POST /v1/routing/queue-rules --field name="VIP customers" --field queue=$VIP_QUEUE_ID \
  --field criteria:='{"and": [{"customer_custom_isVipBool": {"operator": "equals", "value": true}}], "or": []}' \
  | jq -r '.data.id'
```

**Step 3.** [`GET /v1/routing/queue-rules`](https://developer.kustomer.com/api/queues-and-routing/get-queue-rules.md). Read the current order. Rules come back in the order routing checks them.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/routing/queue-rules" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/routing/queue-rules \
  | jq --arg new "$RULE_ID" '{rules: ([$new] + [.data[].id | select(. != $new)])}' > order.json
```

**Step 4.** [`PUT /v1/routing/queue-rules/order`](https://developer.kustomer.com/api/queues-and-routing/update-queue-rule-order.md). Send every rule ID, with the new one first. The list must contain each rule exactly once, or the request fails with `400`.

```bash title="cURL"
curl --request PUT "https://api.kustomerapp.com/v1/routing/queue-rules/order" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data @order.json
```

```bash title="kusty"
kusty api PUT /v1/routing/queue-rules/order --data @order.json
```

> The rule applies to conversations routed after it's saved. Conversations already waiting in a queue stay where they are.

#### 2. Turn a rule off without losing it

Pause a rule, for example while a team is out, and keep its conditions so you can turn it back on later.

**Step 1.** [`GET /v1/routing/queue-rules/{id}`](https://developer.kustomer.com/api/queues-and-routing/get-queue-rule.md). Read the rule and rebuild the body from it. An update needs `name`, `criteria` and the rule's target, and leaving out `queue` (or `queueKey`) clears it, so carry over whichever of the two the rule uses.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/routing/queue-rules/$RULE_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/routing/queue-rules/$RULE_ID \
  | jq '.data | {name: .attributes.name, description: .attributes.description, criteria: .attributes.criteria,
      queue: .relationships.queue.data.id, queueKey: .attributes.queueKey, enabled: false}
      | with_entries(select(.value != null))' > rule.json
```

**Step 2.** [`PUT /v1/routing/queue-rules/{id}`](https://developer.kustomer.com/api/queues-and-routing/update-queue-rule.md). Send the rebuilt rule with `enabled: false`. It keeps its place in the order, and routing skips it until you send it again with `enabled: true`.

```bash title="cURL"
curl --request PUT "https://api.kustomerapp.com/v1/routing/queue-rules/$RULE_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data @rule.json
```

```bash title="kusty"
kusty api PUT /v1/routing/queue-rules/$RULE_ID --data @rule.json
```

#### 3. Export the rules in routing order for review

List every rule with its position, status and target queue name, for an audit or before a reorganization.

**Step 1.** [`GET /v1/routing/queues`](https://developer.kustomer.com/api/queues-and-routing/get-queues.md). Build a map of queue IDs to names. Pass `all=true` so a rule that still points at a deleted queue resolves to a name.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/routing/queues?all=true&pageSize=100" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/routing/queues --query all=true --all \
  | jq -s 'map({(.data.id): .data.attributes.name}) | add' > queue-names.json
```

**Step 2.** [`GET /v1/routing/queue-rules`](https://developer.kustomer.com/api/queues-and-routing/get-queue-rules.md). List the rules, which come back in routing order, and print each one's position, `enabled` flag and queue. Rules without a `queue` relationship choose their queue with a `queueKey` template.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/routing/queue-rules" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/routing/queue-rules \
  | jq -r --slurpfile q queue-names.json '.data | to_entries[]
      | [.key + 1, .value.attributes.name, .value.attributes.enabled,
         ($q[0][.value.relationships.queue.data.id // ""] // ("key: " + (.value.attributes.queueKey // "")))]
      | @tsv'
```

> Pass `enabled=true` to list only the rules routing checks. Conversations that match no enabled rule go to the default queue.

### Example object

A real record from [`GET /v1/routing/queue-rules/{id}`](https://developer.kustomer.com/api/queues-and-routing/get-queue-rule.md):

```json
{
  "id": "5de885a9e0cddd001a8f9fa2",
  "type": "queue_rule",
  "attributes": {
    "name": "VIP Customer",
    "criteria": {
      "and": [],
      "or": []
    },
    "enabled": false,
    "description": "VIP Customer",
    "updatedAt": "2019-12-05T04:20:57.572Z",
    "modifiedAt": "2019-12-05T04:20:57.566Z",
    "createdAt": "2019-12-05T04:20:57.566Z"
  },
  "relationships": {
    "org": {
      "data": {
        "type": "org",
        "id": "57504f64d76808100089eb44"
      },
      "links": {
        "self": "/v1/orgs/57504f64d76808100089eb44"
      }
    },
    "queue": {
      "data": {
        "type": "queue",
        "id": "5de87b2969498a001ace7904"
      },
      "links": {
        "self": "/v1/routing/queues/5de87b2969498a001ace7904"
      }
    },
    "modifiedBy": {
      "data": {
        "type": "user",
        "id": "57504f644c80120f00f3c378"
      },
      "links": {
        "self": "/v1/users/57504f644c80120f00f3c378"
      }
    }
  },
  "links": {
    "self": "/v1/routing/queue-rules/5de885a9e0cddd001a8f9fa2"
  }
}
```

Fields:

- `attributes.name` (string): The rule's name, required on create and update. Up to 256 characters.
- `attributes.criteria` (object): The conditions a conversation must meet. A rule matches when every condition in `and` holds and, if `or` has any, at least one of those does.
- `attributes.criteria.and` (array): Conditions that must all be true, each shaped `{ "<field>": { "operator": "…", "value": … } }`, such as `conversation_channel` equals `email`.
- `attributes.criteria.or` (array): Conditions of which at least one must be true. Leave it empty when every condition belongs in `and`.
- `attributes.enabled` (boolean): Disabled rules stay in the order but are skipped. Rules are enabled unless you send `enabled: false`.
- `attributes.description` (string): Free text for admins, up to 1,024 characters.
- `relationships.queue` (object): The queue matching conversations go to. Rules that choose a queue with a `queueKey` template have no `queue`.

### Relationships

- Points to **Queues** via `relationships.queue`: The queue a queue rule sends matching conversations to. A rule can't point at the default queue, and rules that choose a queue by `queueKey` have no fixed queue.

### Permissions

Fewest roles for a read-only integration: `org.permission.queue_rule.read`. For every endpoint: `org.permission.queue_rule.read`, `org.permission.queue_rule.update`, `org.permission.queue_rule.create`, `org.permission.queue_rule.delete`.

## Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Queue Rule ID |

## Request body

Content type: `application/json` (required)

- Any of:
  - any
  - any
- `name` (string): (min length 1; max length 256)
- `description` (string): (max length 1024)
- `queueKey` (string, nullable): (min length 1; max length 1024)
- `queue` (string<object-id>, nullable)
- `criteria` (object)
  - `and` (array<rules>): (unique items)
  - `or` (array<rules>): (unique items)
- `enabled` (boolean)

Example:

```json
null
```

## Responses

### 200

OK

- `data` (object, required)
  - `id` (string, required)
  - `type` (string, required)
  - `attributes` (object, required)
    - `name` (string, required)
    - `criteria` (object, required)
    - `enabled` (boolean, required)
    - `description` (string, required)
    - `updatedAt` (string, required)
    - `modifiedAt` (string, required)
    - `createdAt` (string, required)
  - `relationships` (object, required)
    - `org` (object, required)
    - `queue` (object, required)
    - `modifiedBy` (object, required)
  - `links` (object, required)
    - `self` (string, required)

```json
{
  "data": {
    "id": "5de885a9e0cddd001a8f9fa2",
    "type": "queue_rule",
    "attributes": {
      "name": "VIP Customer",
      "criteria": {
        "and": [
          {
            "customer_custom_isVipBool": {
              "value": true,
              "operator": "equals"
            }
          }
        ],
        "or": []
      },
      "enabled": false,
      "description": "VIP Customer",
      "updatedAt": "2019-12-05T04:30:32.183Z",
      "modifiedAt": "2019-12-05T04:30:32.183Z",
      "createdAt": "2019-12-05T04:20:57.566Z"
    },
    "relationships": {
      "org": {
        "data": {
          "type": "org",
          "id": "57504f64d76808100089eb44"
        },
        "links": {
          "self": "/v1/orgs/57504f64d76808100089eb44"
        }
      },
      "queue": {
        "data": {
          "type": "queue",
          "id": "5de87b2969498a001ace7904"
        },
        "links": {
          "self": "/v1/routing/queues/5de87b2969498a001ace7904"
        }
      },
      "modifiedBy": {
        "data": {
          "type": "user",
          "id": "57504f644c80120f00f3c378"
        },
        "links": {
          "self": "/v1/users/57504f644c80120f00f3c378"
        }
      }
    },
    "links": {
      "self": "/v1/routing/queue-rules/5de885a9e0cddd001a8f9fa2"
    }
  }
}
```

### 400

Bad Request

### 401

Unauthorized

### 403

Forbidden

### 404

Not Found

## Example request

```bash
curl --request PUT \
  --url 'https://api.kustomerapp.com/v1/routing/queue-rules/5f184e74c61792001af42e49' \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header 'Content-Type: application/json' \
  --data 'null'
```
