## Search recurring deals

`POST /v1/recurring-deals/search`

Finds deal recurrence settings using conditions in the request body. Use it to filter schedules and retrieve selected fields.

For selections up to 5000 records, use [List recurring deals](./list.md). Search accepts its conditions in JSON and can split a wide date filter into intervals.

## Request body fields

| Field | Type | Required | Description |
|---|---|---|---|
| `filter` | object | No | Filter by fields from [Recurring deal fields](./fields.md).<br>[Filtering syntax](/docs/filtering). Example body field: `"filter":{"active":false}` |
| `sort` | string / object / string[] | No | Sort fields. `id` sorts ascending, `-id` descending |
| `order` | object | No | Alternative to `sort`, for example `{"id":"desc"}` |
| `select` | string / string[] | No | Response fields. A comma-separated string or an array of names |
| `limit` | number / string | No | Selection size, default 50, maximum 5000. A numeric string is also accepted |
| `offset` | number | No | Offset from the start of the selection. A value greater than zero is incompatible with automatic splitting of a date range wider than 14 days. Use `autoWindow: false` with `sort: "id"` for pagination |
| `autoWindow` | boolean | No | Set to `false` to disable automatic splitting of a wide date filter into windows |
| `withTotal` | boolean | No | Requests the total count in `meta.total` |

## Examples

### curl — personal key

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/recurring-deals/search" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filter":{"active":false},"sort":"id","select":["id","dealId","basedId","active","nextExecution","lastExecution","counterRepeat","startDate","categoryId","isLimit","limitRepeat","limitDate","params"],"limit":2,"withTotal":true}'
```

### curl — OAuth application

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/recurring-deals/search" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"filter":{"active":false},"sort":"id","select":["id","dealId","basedId","active","nextExecution","lastExecution","counterRepeat","startDate","categoryId","isLimit","limitRepeat","limitDate","params"],"limit":2,"withTotal":true}'
```

### JavaScript — personal key

```javascript
const response = await fetch('https://vibecode.bitrix24.com/v1/recurring-deals/search', {
  method: 'POST',
  headers: { 'X-Api-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' },
  body: JSON.stringify({"filter":{"active":false},"sort":"id","select":["id","dealId","basedId","active","nextExecution","lastExecution","counterRepeat","startDate","categoryId","isLimit","limitRepeat","limitDate","params"],"limit":2,"withTotal":true}),
})
const result = await response.json()
if (!result.success) throw new Error(result.error.message)
console.log(result.data)
```

### JavaScript — OAuth application

```javascript
const response = await fetch('https://vibecode.bitrix24.com/v1/recurring-deals/search', {
  method: 'POST',
  headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({"filter":{"active":false},"sort":"id","select":["id","dealId","basedId","active","nextExecution","lastExecution","counterRepeat","startDate","categoryId","isLimit","limitRepeat","limitDate","params"],"limit":2,"withTotal":true}),
})
const result = await response.json()
if (!result.success) throw new Error(result.error.message)
console.log(result.data)
```

## Response fields

| Field | Type | Description |
|---|---|---|
| `success` | boolean | Whether the request succeeded |
| `data` | object[] | Recurrence settings. See [recurring deal fields](./fields.md) |
| `meta.total` | number | Total matching settings, when returned |
| `meta.hasMore` | boolean | Whether more records are available |
| `meta.durationMs` | number | Execution time in milliseconds, when returned |
| `meta.warnings` | object[] | Warnings, when returned. Unknown `select` fields can be ignored in a successful request |
| `meta.autoWindowed` | boolean | Whether date windowing was applied |
| `meta.windowCount` | number | Number of date intervals, when windowing is applied |
| `meta.windowErrors` | number | Number of failed intervals, when failures occur |
| `meta.windowErrorSample` | object | First interval error with code and message, on partial failure |
| `meta.pageErrorSample` | object | Sample subpage error when the returned selection is incomplete |


## Response example

```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "dealId": 575,
      "basedId": 573,
      "active": false,
      "nextExecution": null,
      "lastExecution": "2020-06-16T22:00:00.000Z",
      "counterRepeat": 2,
      "startDate": "2020-06-15",
      "categoryId": 1,
      "isLimit": "T",
      "limitRepeat": 2,
      "limitDate": null,
      "params": {
        "mode": "multiple",
        "singleBeforeStartDateValue": 0,
        "singleBeforeStartDateType": "day",
        "multipleType": "day",
        "multipleInterval": 1,
        "offsetBeginDateType": "day",
        "offsetBeginDateValue": 1,
        "offsetCloseDateType": "day",
        "offsetCloseDateValue": 1
      }
    },
    {
      "id": 3,
      "dealId": 3865,
      "basedId": 3863,
      "active": false,
      "nextExecution": null,
      "lastExecution": "2021-01-12T22:00:00.000Z",
      "counterRepeat": 2,
      "startDate": "2021-01-14",
      "categoryId": 0,
      "isLimit": "D",
      "limitRepeat": null,
      "limitDate": "2021-01-13",
      "params": {
        "mode": "single",
        "singleBeforeStartDateValue": 1,
        "singleBeforeStartDateType": "day",
        "multipleType": "day",
        "multipleInterval": 1,
        "offsetBeginDateType": "day",
        "offsetBeginDateValue": 0,
        "offsetCloseDateType": "day",
        "offsetCloseDateValue": 0
      }
    }
  ],
  "meta": {
    "total": 4,
    "hasMore": true,
    "durationMs": 123
  }
}
```

## Error response example

400 — unknown filter field:

```json
{
  "success": false,
  "error": {
    "code": "UNKNOWN_FILTER_FIELD",
    "message": "Unknown filter field 'madeUp' for entity 'recurring-deals'. Available: id, dealId, basedId, active, nextExecution, lastExecution, counterRepeat, startDate, categoryId, isLimit, limitRepeat, limitDate"
  }
}
```

## Errors

| HTTP | Code | Description |
|---|---|---|
| 400 | `INVALID_REQUEST` | The request body is not a JSON object |
| 400 | `INVALID_LIMIT` | `limit` cannot be interpreted as a finite number. Numbers and numeric strings are accepted |
| 400 | `INVALID_SELECT_TYPE` | `select` is not a string or an array of strings |
| 400 | `INVALID_SORT_TYPE` | `sort` is not a string, object or array of strings |
| 400 | `UNKNOWN_FILTER_FIELD` | The filter references an unknown field. See the error message and [field definitions](./fields.md) |
| 400 | `INVALID_FILTER_FIELD` | A field name starts with the unsupported prefix `@` or `!@` |
| 400 | `INVALID_FILTER_OPERATOR` | An unknown operator, an empty condition object, or a logical condition using `$or` or `$and` |
| 400 | `INVALID_DUPLICATE_FILTER_FIELD` | Two conditions map to the same filter condition. Supply only one |
| 400 | `INVALID_SORT_FIELD` | Sorting uses a forbidden name: `__proto__`, `constructor` or `prototype` |
| 400 | `UNKNOWN_SORT_FIELD` | Sorting references an unknown field |
| 400 | `INVALID_SORT_DIRECTION` | A sort direction is not one of the strings `asc`, `desc`, `ASC`, `DESC` or the numbers `1`, `-1` |
| 400 | `INVALID_FILTER_SHAPE` | `filter` is not an object |
| 400 | `UNSTABLE_OFFSET_PAGINATION` | `offset > 0` is combined with automatic splitting of a date range wider than 14 days. Use `autoWindow: false` with `sort: "id"` for pagination |
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header is missing |
| 401 | `TOKEN_MISSING` | No Bitrix24 access tokens are configured |
| 403 | `SCOPE_DENIED` | The API key lacks the `crm` scope |
| 403 | `BITRIX_ACCESS_DENIED` | Bitrix24 denied access, including a missing required scope |
| 422 | `BITRIX_ERROR` | Bitrix24 rejected the operation or a plan restriction applies. See `error.message` |
| 503 | `BITRIX_TIMEOUT` | Bitrix24 did not respond in time. Retry after the interval in `Retry-After` |
| 502 | `BITRIX_UNAVAILABLE` | A connection to Bitrix24 could not be established |
| 429 | `RATE_LIMITED` | The request rate limit was exceeded. The effective limit is in the `x-ratelimit-limit` header. Retry after the interval in the `Retry-After` header |

For the full list of common API errors, see [Error codes](/docs/errors).

## Known specifics

The response can include settings with `active: false`. To retrieve active schedules only, filter by `active: true`.

## See also

- [List recurring deals](./list.md)
- [Get a recurring deal](./get.md)
- [Recurring deal fields](./fields.md)
- [Aggregate recurring deals](./aggregate.md)
- [Recurring deals](../recurring-deals.md)
- [Filtering syntax](/docs/filtering)
