# Pagination & Filtering

> Pagination helps you efficiently navigate, sort, and filter large collections of data without fetching everything at once.
This is especially useful for endpoints like:

# Pagination

Pagination helps you efficiently navigate, sort, and filter large collections of data without fetching everything at once.
This is especially useful for endpoints like:

- [List Payments](/api/v2-payments-list)
- [List Products](/api/v2-products-list)
- [List Invoices](/api/v2-invoices-list)
- [List Subscriptions](/api/v2-subscriptions-list)

# Filtering

Filtering is another way to efficiently navigate and filter large collections of data without fetching everything at once.

Whenever pagination is applied, then so is filtering.

Filtering allows you to filter your fetched objects through specific features or conditions like queries.

Whenever an endpoint may return many items, Stream uses a consistent pagination and filtering structure across all list responses.

---

# Request Parameters

## Pagination Parameters

You can control pagination using the following query parameters:

| Parameter        | Type   | Description                                                                 |
|------------------|--------|-----------------------------------------------------------------------------|
| `page`           | int    | Page number starting from **1**.                                            |
| `limit`          | int    | Number of items per page. Maximum: **100**.                                |
| `sort_field`     | string | Field used to sort the results.                                             |
| `sort_direction` | string | Either `"asc"` or `"desc"` depending on sorting direction.                  |

By default, `sort_field` is `created_at` and `sort_direction` is `desc`.

```
GET api/v2/products?page=1&limit=20&sort_field=created_at&sort_direction=desc
```

---

#Filtering allows you to query objects based on specific attributes. When you apply filters, the `pagination` metadata in the response will reflect the total count of items *matching* your filter, not the total database count.

| Parameter     | Type             | Description                                                                                       |
|---------------|------------------|---------------------------------------------------------------------------------------------------|
| `search_term` | `string`         | A generic query string. The API searches relevant fields (e.g., names, IDs, descriptions) for matches. |
| **Field Specific**| `string` / `array` | Specific attributes depending on the resource (e.g., `invoice_id`, `statuses`, `currency`).       |

**Note on Array Filters:**
Some parameters, like `statuses`, accept multiple values. In the query string, this appears as repeating keys:
`statuses=PENDING&statuses=PROCESSING`

For example, the [List Payments](/api/v2-payments-list) endpoint takes filtering queries like `invoice_id` and `statuses` to filter down the returned payments.

Example query:

```
GET api/v2/payments?page=1&limit=20&invoice_id=73b89d47-1bb1-443c-9a4c-f0ee23e22191&statuses=PENDING&statuses=PROCESSING
```

---

# Pagination Response Structure

Paginated responses include a `pagination` object that provides metadata about the current, previous, and next pages.

| Field              | Description                                                                 |
|--------------------|-----------------------------------------------------------------------------|
| `total_count`      | Number of objects returned in the current page.                             |
| `max_page`         | Maximum page number available.                                              |
| `current_page`     | Page you are currently on.                                                  |
| `limit`            | Page size (echoes your request, capped at 100).                             |
| `has_next_page`    | Whether another page exists after this one.                                 |
| `has_previous_page`| Whether a page exists before this one.                                      |

Example response snippet:

```
{
  "data": [...],
  "pagination": {
    "total_count": 20,
    "max_page": 12,
    "current_page": 1,
    "limit": 20,
    "has_next_page": true,
    "has_previous_page": false
  }
}
```

---

# Examples (Python)

Below are practical examples using Python's `requests` library.

## 1. Basic Pagination

Fetching the first page of results with a custom limit.

```python

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://stream-app-service.streampay.sa/api/v2/products"

response = requests.get(
    BASE_URL,
    headers={"x-api-key": API_KEY},
    params={
        "page": 1,
        "limit": 20
    }
)

data = response.json()
print(f"Showing page {data['pagination']['current_page']} of {data['pagination']['max_page']}")
```

## 2. Global Search Filtering

Using the `search_term` to find items matching a specific string (e.g., a customer name or partial ID).

```python

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://stream-app-service.streampay.sa/api/v2/customers"

response = requests.get(
    BASE_URL,
    headers={"x-api-key": API_KEY},
    params={
        "search_term": "JOHN DOE", # Searches for customer with that name
        "limit": 10
    }
)

results = response.json()["data"]
print(f"Found {len(results)} matches for 'Al-Faisaliah'")
```

## 3. Advanced Filtering (Lists & Specific Fields)

Filtering by a specific `invoice_id` and multiple `statuses`. Note how the list of statuses is passed to the `params` dictionary.

```python

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://stream-app-service.streampay.sa/api/v2/payments"

# To filter by multiple statuses, pass them as a list
payload_filters = {
    "page": 1,
    "limit": 50,
    "invoice_id": "73b89d47-1bb1-443c-9a4c-f0ee23e22191",
    "statuses": ["PENDING", "PROCESSING"] # Requests handles this as statuses=PENDING&statuses=PROCESSING
}

response = requests.get(
    BASE_URL,
    headers={"x-api-key": API_KEY},
    params=payload_filters
)

payments = response.json()["data"]
for p in payments:
    print(f"Payment ID: {p['id']} | Status: {p['status']}")
```

## 4. Iterating Through All Pages

A robust pattern to fetch every item available.

```python

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://stream-app-service.streampay.sa/api/v2/products"

page = 1
all_products = []

while True:
    response = requests.get(
        BASE_URL,
                headers={"x-api-key": API_KEY},
        params={"page": page, "limit": 100} # Maximize limit to reduce requests
    )

    body = response.json()
    all_products.extend(body["data"])

    # Stop if there are no more pages
    if not body["pagination"]["has_next_page"]:
        break

    page += 1

print(f"Successfully fetched {len(all_products)} products.")
```

---
