> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ozura.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Query Recurring Plans

> Look up one or more recurring plans, with filters for status, schedule, and upcoming charges

Use this endpoint to look up recurring plans you've created — either a single plan by ID or a filtered, paginated list. It powers dashboards, billing reports, and any internal tooling that needs visibility into a customer's subscription state.

## Quick Start

List all recurring plans for a merchant:

```bash theme={null}
curl -X GET "https://payapi.v2.ozurapay.com/api/v1/recurring/plans?merchantId=ozu_7bjg497249681346" \
  -H "x-api-key: your_merchant_api_key"
```

A successful response returns a `data` array of plan objects and a `pagination` object. To fetch one specific plan instead, include `planId` in the query string.

## The Basics

| What            | Value                                                   |
| :-------------- | :------------------------------------------------------ |
| **Method**      | `GET`                                                   |
| **URL**         | `https://payapi.v2.ozurapay.com/api/v1/recurring/plans` |
| **Called From** | Your server (never from browser JavaScript)             |

<Note>
  **Never call this from the browser.** Your API key must stay on the server.
  Use a backend (Node.js, Python, PHP, etc.) to query plans and pass the results
  to your frontend.
</Note>

## Required Headers

```
x-api-key: your_merchant_api_key
```

<Note>
  **Merchant API Key (`x-api-key`):** Developers → API Keys.

  The key must have read access to recurring plans enabled.
</Note>

## Single Plan vs. List

This endpoint operates in two modes, controlled by whether `planId` is in the query string:

* **List mode** — Omit `planId`. Returns a paginated array of plans matching your filters.
* **Single-plan mode** — Provide `planId`. Returns one plan in the same shape as list mode. Returns `404` if no plan matches.

`data` is always an array, even when you query a single plan (it'll contain exactly one element).

## Hierarchy ID (Required)

Every request must include **exactly one** of the following IDs in the query string, scoping the query to a level of your hierarchy:

| Parameter    | Description                                     |
| :----------- | :---------------------------------------------- |
| `merchantId` | Query plans owned by a single merchant          |
| `agentId`    | Query plans across all merchants under an agent |
| `isvId`      | Query plans across all merchants under an ISV   |
| `isoId`      | Query plans across all merchants under an ISO   |
| `groupId`    | Query plans across an entire group              |

Providing zero or more than one of these returns a `400` error. Which IDs you're allowed to query depends on your role — see [Who Can Query What](#who-can-query-what) below.

## Who Can Query What

Your API key's role determines which hierarchy IDs you can use:

| Your role  | Hierarchy IDs you can query                                                  |
| :--------- | :--------------------------------------------------------------------------- |
| `merchant` | `merchantId` (your own only)                                                 |
| `agent`    | `merchantId`, `agentId` (within your hierarchy)                              |
| `isv`      | `merchantId`, `agentId`, `isvId` (within your hierarchy)                     |
| `iso`      | `merchantId`, `agentId`, `isvId`, `isoId` (within your hierarchy)            |
| `group`    | `merchantId`, `agentId`, `isvId`, `isoId`, `groupId` (within your hierarchy) |

Trying to query a hierarchy ID you don't have access to — whether because your role doesn't allow it or because the specific ID isn't in your hierarchy — returns a `403` error.

<Note>
  A future "Authentication & Access" guide will document hierarchy rules in
  full. Until then, treat this section as the canonical reference.
</Note>

## Optional Query Parameters

All filters are optional and can be combined.

### Filters

| Parameter                    | Type   | Description                                                                     | Example                      |
| :--------------------------- | :----- | :------------------------------------------------------------------------------ | :--------------------------- |
| `planId`                     | string | Look up one specific plan by ID. Switches the endpoint into single-plan mode.   | `"RP2606020000167A143"`      |
| `status`                     | string | Filter by lifecycle state — see [RecurringPlanStatus](#recurringplanstatus)     | `"active"`                   |
| `interval`                   | string | Filter by billing cadence — see [RecurringInterval](#recurringinterval)         | `"monthly"`                  |
| `processor`                  | string | Filter by underlying processor (`elavon`, `nuvei`, `worldpay`)                  | `"elavon"`                   |
| `merchantRecurringReference` | string | Filter by the reference you passed when creating the plan                       | `"sub_customer_123"`         |
| `merchantPayLinkReference`   | string | Filter by the payment link reference the plan was created with                  | `"paylink_ref_001"`          |
| `paymentLinkId`              | string | Filter by the Ozura payment link ID the plan was created through                | `"pl_xxxxxxxxxxxx"`          |
| `dateFrom`                   | string | ISO 8601 — return plans created on or after this date                           | `"2025-01-01T00:00:00.000Z"` |
| `dateTo`                     | string | ISO 8601 — return plans created on or before this date                          | `"2025-12-31T23:59:59.999Z"` |
| `nextChargeBefore`           | string | ISO 8601 — return plans with their next scheduled charge on or before this date | `"2026-06-09T00:00:00.000Z"` |
| `nextChargeAfter`            | string | ISO 8601 — return plans with their next scheduled charge on or after this date  | `"2026-06-02T00:00:00.000Z"` |

<Note>
  `merchantRecurringReference`, `merchantPayLinkReference`, and `paymentLinkId`
  are only present on a plan if they were provided at creation. Plans created
  without them omit the fields entirely.
</Note>

### Pagination & Sorting

| Parameter   | Type   | Default     | Description                                   |
| :---------- | :----- | :---------- | :-------------------------------------------- |
| `page`      | number | `1`         | Which page of results to return               |
| `limit`     | number | `50`        | Results per page. Maximum `100`               |
| `sortBy`    | string | `createdAt` | Field to sort by                              |
| `sortOrder` | string | `desc`      | `asc` (oldest first) or `desc` (newest first) |

### Field Selection

| Parameter | Type   | Description                                                                    |
| :-------- | :----- | :----------------------------------------------------------------------------- |
| `fields`  | string | Comma-separated list of fields to return. See [Custom Fields](#custom-fields). |

## Custom Fields

By default, the endpoint returns a curated set of fields depending on whether you're in list mode or single-plan mode. To request only specific fields, pass `fields` as a comma-separated list:

```bash theme={null}
curl -X GET "https://payapi.v2.ozurapay.com/api/v1/recurring/plans?merchantId=ozu_7bjg497249681346&fields=planId,status,amount,nextChargeAt" \
  -H "x-api-key: your_merchant_api_key"
```

Useful for lightweight dashboard queries where you only need a few attributes per plan.

<Note>
  Some fields are restricted to administrators and will be silently omitted if
  you request them. If every field you request is restricted, the response is a
  `400` error.
</Note>

## Enums

### RecurringPlanStatus

The lifecycle state of a plan, returned in every plan response.

| Value       | Meaning                                                          |
| :---------- | :--------------------------------------------------------------- |
| `active`    | Plan is running and will bill on schedule                        |
| `paused`    | Billing is temporarily halted; can be resumed                    |
| `cancelled` | Plan has been permanently stopped                                |
| `completed` | All scheduled cycles have been charged, or maxCycles was reached |
| `failed`    | Exhausted all retries on a cycle. Needs merchant attention       |

### RecurringInterval

| Value     | Description        |
| :-------- | :----------------- |
| `daily`   | Charge every day   |
| `weekly`  | Charge every week  |
| `monthly` | Charge every month |
| `yearly`  | Charge every year  |

## Response Shape

The response shape is identical for list mode and single-plan mode — `data` is always an array of plan objects. Single-plan mode just returns one element.

```json theme={null}
{
  "success": true,
  "data": [
    /* one or more plan objects */
  ],
  "pagination": {
    "currentPage": 1,
    "totalPages": 3,
    "totalCount": 127,
    "limit": 50,
    "hasNextPage": true,
    "hasPrevPage": false,
    "nextPage": 2,
    "prevPage": null
  }
}
```

### Example

A query for a single plan, returning the full plan object:

```json theme={null}
{
  "success": true,
  "data": [
    {
      "planId": "RP2606020000167A143",
      "status": "active",
      "processor": "elavon",
      "planName": "Monthly Pro Subscription",
      "planDescription": "Pro tier, billed monthly",
      "merchantRecurringReference": "sub_customer_123",
      "amount": "29.99",
      "currency": "USD",
      "totalCharged": "29.99",
      "totalRefunded": "0.00",
      "interval": "monthly",
      "intervalCount": 1,
      "startDate": "2026-06-02T12:00:00.000Z",
      "anchorDay": 2,
      "nextCycleAt": "2026-07-02T12:00:00.000Z",
      "nextChargeAt": "2026-07-02T12:00:00.000Z",
      "lastChargeAt": "2026-06-02T12:00:00.000Z",
      "lastAttemptId": "RA2606020000A12B345",
      "cycleCount": 1,
      "maxCycles": null,
      "endDate": null,
      "maxAttempts": 3,
      "retryIntervalHours": 24,
      "surchargePercent": "0.00",
      "salesTaxExempt": false,
      "isCreditCard": true,
      "cardLastFour": "4242",
      "cardExpMonth": "03",
      "cardExpYear": "30",
      "cardBrand": "VISA",
      "cardBin": "424242",
      "firstName": "Jane",
      "lastName": "Doe",
      "email": "jane.doe@example.com",
      "phone": "+15551234567",
      "address1": "123 Main St",
      "address2": "Apt 4B",
      "city": "Miami",
      "state": "FL",
      "zipcode": "33101",
      "country": "US",
      "clientIpAddress": "203.0.113.42",
      "avsResponseCode": "Y",
      "cvvResponseCode": "M",
      "citTransactionId": "26060200001D66653",
      "citTransactionChannel": "ecommerce",
      "recurringTransactionType": "recurringCreditCardSale",
      "initialPricingConfig": null,
      "ozuraUserDetails": {
        "ozuraUserId": "ozu_user_xxx",
        "ozuraMerchantId": "ozu_7bjg497249681346"
      },
      "pausedAt": null,
      "pausedUntil": null,
      "pauseReason": null,
      "cancelledAt": null,
      "completedAt": null,
      "failedAt": null,
      "createdAt": "2026-06-02T12:00:00.000Z"
    }
  ],
  "pagination": {
    "currentPage": 1,
    "totalPages": 1,
    "totalCount": 1,
    "limit": 50,
    "hasNextPage": false,
    "hasPrevPage": false,
    "nextPage": null,
    "prevPage": null
  }
}
```

### Field Notes

| Field                                                   | What It Is                                                                               |
| :------------------------------------------------------ | :--------------------------------------------------------------------------------------- |
| `status`                                                | Current lifecycle state — see [RecurringPlanStatus](#recurringplanstatus)                |
| `nextChargeAt`                                          | When the worker will next attempt to charge — may be a retry time after a failed attempt |
| `nextCycleAt`                                           | The true next billing date — never moves during retries within a cycle                   |
| `cycleCount`                                            | How many successful cycles have charged so far                                           |
| `totalCharged`                                          | Cumulative sum of all successful cycles                                                  |
| `totalRefunded`                                         | Cumulative sum of all refunds against this plan's transactions                           |
| `lastAttemptId`                                         | The ID of the most recent attempt (success or failure)                                   |
| `initialPricingConfig`                                  | If set, the trial/setup-fee config defined at plan creation; `null` otherwise            |
| `citTransactionId`                                      | Transaction ID of the initial CIT charge made at plan creation                           |
| `pausedAt` / `cancelledAt` / `failedAt` / `completedAt` | Lifecycle timestamps — populated only when the plan reaches the corresponding state      |

## Common Use Cases

### Fetch a single plan

```bash theme={null}
curl -X GET "https://payapi.v2.ozurapay.com/api/v1/recurring/plans?merchantId=ozu_7bjg497249681346&planId=RP2606020000167A143" \
  -H "x-api-key: your_merchant_api_key"
```

### List only active plans

```bash theme={null}
curl -X GET "https://payapi.v2.ozurapay.com/api/v1/recurring/plans?merchantId=ozu_7bjg497249681346&status=active" \
  -H "x-api-key: your_merchant_api_key"
```

### List plans charging in the next 7 days

Useful for "upcoming charges" dashboard views. Combine `status=active` with a `nextChargeBefore` cutoff:

```bash theme={null}
curl -X GET "https://payapi.v2.ozurapay.com/api/v1/recurring/plans?merchantId=ozu_7bjg497249681346&status=active&nextChargeBefore=2026-06-09T00:00:00.000Z" \
  -H "x-api-key: your_merchant_api_key"
```

### Paginate through a large set

Page 1, 25 plans per page, oldest first:

```bash theme={null}
curl -X GET "https://payapi.v2.ozurapay.com/api/v1/recurring/plans?merchantId=ozu_7bjg497249681346&page=1&limit=25&sortOrder=asc" \
  -H "x-api-key: your_merchant_api_key"
```

### Lightweight query with custom fields

When you only need a few attributes per plan:

```bash theme={null}
curl -X GET "https://payapi.v2.ozurapay.com/api/v1/recurring/plans?merchantId=ozu_7bjg497249681346&fields=planId,status,amount,nextChargeAt,cardLastFour" \
  -H "x-api-key: your_merchant_api_key"
```

## What's Next?

Once you've found the plan you're looking for, head to [Manage Recurring Plans](/guides/payments/payapi/recurring/manage-plans) to pause, cancel, or update it.
