Pagination, filtering, sorting
Most Odus API endpoints that return lists of resources (e.g. GET /payments) support pagination, filtering, and sorting to help you retrieve data efficiently. This page describes the available options and how to use them.
Pagination
To paginate results, you can use the page and pageSize query parameters:
GET /payments?page=1&pageSize=10
| Parameter | Description | Supported Values | Default Value |
|---|---|---|---|
page | The page number to retrieve. | Positive integers | 1 |
pageSize | The number of items per page. | Positive integers less than or equal to 100 | 10 |
Invalid page or pageSize values will fail silently, returning the first page with the default size.
Response structure
All paginated endpoints return a response in the following structure:
{
"data": [
/* Array of items */
],
"pagination": {
"hasNextPage": true,
"hasPreviousPage": false,
"itemCount": 40,
"page": 1,
"pageCount": 4,
"pageSize": 10
}
}
data: An array of items returned by the endpoint.pagination.hasNextPage: Indicates if there is a next page of results.pagination.hasPreviousPage: Indicates if there is a previous page of results.pagination.itemCount: The total number of items for the resource, including all pages.pagination.page: The current page number.pagination.pageCount: The total number of pages available.pagination.pageSize: The number of items per page.
Sorting
To sort results, you can use the sortBy and sortDirection query parameters:
GET /payments?sortBy=createdAt&sortDirection=desc
| Parameter | Description | Supported Values | Default Value |
|---|---|---|---|
sortBy | The field to sort by. | Any sortable field | createdAt |
sortDirection | The direction of sorting. | asc, desc, ASC, DESC | asc |
Each endpoint supports different fields for sorting, which are documented below in the Supported endpoints section.
Filtering
To filter results, you can pass the filter criteria as a query parameter in LHS bracket notation:
GET /payments?amount[gt]=100&status[eq]=succeded
The list of supported operators differs by data type. The following operators are supported:
| Operator | Description | Boolean | Number | String | Date |
|---|---|---|---|---|---|
eq | Equal to | ✓ | ✓ | ✓ | ✓ |
ne | Not equal to | ✓ | ✓ | ✓ | ✓ |
gt | Greater than | ✓ | ✓ | ||
gte | Greater than or equal to | ✓ | ✓ | ||
lt | Less than | ✓ | ✓ | ||
lte | Less than or equal to | ✓ | ✓ | ||
in | In | ✓ | ✓ | ✓ | |
nin | Not in | ✓ | ✓ | ✓ | |
like | Like (partial match) | ✓ | |||
contains | Array contains value | ✓ | ✓ | ✓ | ✓ |
Each endpoint supports different fields for filtering, which are documented below in the Supported endpoints section.
All filter values come to Odus API as strings, and the API will attempt to convert them to a valid type based on the field's data type. If the conversion fails, the filter will be ignored.
Parsing rules:
- Boolean: only
trueandfalseare valid. - Number: only integers are valid. Float values are parsed as integers (e.g.,
100.5becomes100). - String: any string is valid. String filters are case-insensitive (e.g.,
name[eq]=johnwill matchJohn,JOHN, etc.). - Date: supports ISO 8601 date strings (e.g.,
2023-10-01T00:00:00Z) and short date formats (e.g.,2023-10-01). - Null: use
nullto filter for null values (e.g.,customer.firstName[eq]=null).
Building query strings
We recommend using a QS library like qs which allows building complex query strings from objects:
import qs from 'qs';
const query = qs.stringify({
amount: { gt: 100 },
status: { eq: 'succeeded' },
});
const url = new URL(`https://api.odus.com/payments`);
url.search = query;
console.log(url.toString()); // https://api.odus.com/payments?amount[gt]=100&status[eq]=succeeded
Filtering by nested fields
To filter by nested fields, you can use dot notation in the filter criteria for the supported endpoints:
GET /payments?customer.name[like]=John
Using in and nin operators
To pass arrays as filter values, you can use the in and nin operators. The values should be passed individually, each in its own query parameter:
GET /payments?status[in]=succeeded&status[in]=pending
Comma notation (e.g., status[in]=succeeded,pending) is not supported and will be parsed literally, which may lead to unexpected results. Always use the in operator with separate query parameters for each value.
Using contains operator
The contains operator checks if an array field contains a specific value. This is useful for filtering resources where a field stores multiple values (e.g., subscribed event types).
GET /webhook-subscribers?subscribedTo[contains]=payment.created
To pass multiple values to check against, use the $and operator with array notation:
GET /gateway-profiles?$and[0][supportedPaymentMethods][contains]=applepay&$and[1][supportedPaymentMethods][contains]=card
Using logical $or operator
The $or operator is only supported at the root level of the query string. You cannot nest $or groups within other $or groups or combine them with other filter criteria.
It is possible to to match multiple condition groups using the $or operator. Any result that matches either OR group will be included in the results:
GET /payments?$or[0][status][eq]=succeeded&$or[0][isCaptured][eq]=true&$or[1][status][eq]=succeeded&$or[1][isReversed][eq]=true&$or[1][isCaptured][eq]=true
All conditions within a single $or group are combined using logical AND. The example above is a query to find all payments that are either captured or captured and reversed afterwards.
$or[0][status][eq]=succeeded&$or[0][isCaptured][eq]=true= The payment status must besucceededand the payment must be captured.$or[1][status][eq]=succeeded&$or[1][isReversed][eq]=true&$or[1][isCaptured][eq]=true= The payment status must besucceededand the payment must be both reversed and captured.
JSON fields filtering
JSON fields, such as metadata, support filtering using the same operators as string fields. You can filter by specific keys within the JSON object using bracket notation. Unlike regular string fields, JSON field filters are case-sensitive — the filter value must match the stored value exactly.
Let's take this payment as an example:
{
"id": "pay_123",
"amount": 100,
"metadata": {
"field1": "value",
"field2": "value2"
}
}
You can filter by field1 in the metadata object like this:
GET /payments?metadata[field1][eq]=value
When filtering metadata fields with ne, nin, like, in, or comparison operators, entities without that metadata key will NOT be included in the results due to SQL NULL semantics.
For example:
metadata[field1][eq]=value- Only matches entities wherefield1exists and equalsvaluemetadata[field1][ne]=value- Only matches entities wherefield1exists and does NOT equalvalue(entities withoutfield1are excluded)
To include entities without a specific metadata key, use the $or operator to create a condition group that checks for both the presence of the key with the desired value and the absence of the key:
GET /payments?$or[0][metadata][field1][ne]=test&$or[1][metadata][field1][eq]=null
This query means: "include payments where field1 is not 'test' OR where field1 doesn't exist"
Read more about metadata in the Metadata guide.
Supported endpoints
Customers
Endpoint: GET /customers
Sortable fields: id, createdAt, updatedAt
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
firstName | String |
lastName | String |
email | String |
phoneNumber | String |
dateOfBirth | Date |
restrictMit | Boolean |
restrictCit | Boolean |
restrictReason | String |
metadata | JSON |
Payments
Endpoint: GET /payments
Sortable fields: id, createdAt, updatedAt, amount, status, currency
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
amount | Number |
status | String |
displayStatus | String |
currency | String |
amountCaptured | Number |
amountReversed | Number |
captureMethod | String |
captureDelay | Number |
captureAt | Date |
statementDescriptor | String |
isCaptured | Boolean |
isReversed | Boolean |
isChargebacked | Boolean |
isRedirectRequired | Boolean |
customer | String |
customer.email | String |
latestTransaction | String |
latestTransaction.processorId | String |
paymentMethod | String |
paymentMethod.type | String |
paymentMethod.card.lastFour | String |
paymentMethod.card.bin | String |
paymentMethod.card.brand | String |
paymentMethod.card.expYear | String |
paymentMethod.card.expMonth | String |
paymentMethodOptions.card.gatewayProfile | String |
paymentMethodOptions.card.cascade | String |
paymentMethodOptions.card.mode | String |
paymentMethodOptions.paypal.gatewayProfile | String |
metadata | JSON |
Subscriptions
Endpoint: GET /subscriptions
Sortable fields: id, createdAt, updatedAt, status, currentPeriodStart, currentPeriodEnd, startDate, endDate
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
status | String |
startDate | Date |
endDate | Date |
autoBillingEnabled | Boolean |
autoBillingDisabledAt | Date |
autoBillingDisabledReason | String |
cancelAtPeriodEnd | Boolean |
currentPeriodStart | Date |
currentPeriodEnd | Date |
currentCycle | Number |
customer | String |
customer.email | String |
price | String |
metadata | JSON |
Payment Methods
Endpoint: GET /payment-methods
Sortable fields: id, createdAt, updatedAt, isDefault, customer
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
isDefault | Boolean |
customer | String |
card.lastFour | String |
card.brand | String |
card.expYear | String |
card.expMonth | String |
Users
Endpoint: GET /users
Sortable fields: id, createdAt, updatedAt, email
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
email | String |
firstName | String |
lastName | String |
username | String |
Webhook Subscribers
Endpoint: GET /webhook-subscribers
Sortable fields: id, createdAt, updatedAt
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
Products
Endpoint: GET /products
Sortable fields: id, createdAt, updatedAt, name, active
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
name | String |
active | Boolean |
metadata | JSON |
Prices
Endpoint: GET /prices
Sortable fields: id, createdAt, updatedAt, amount, type
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
amount | Number |
currency | String |
type | String |
name | String |
product | String |
product.id | String |
product.name | String |
active | Boolean |
metadata | JSON |
Invoices
Endpoint: GET /invoices
Sortable fields: id, createdAt, updatedAt, status
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
status | String |
currency | String |
amount | Number |
voidedReason | String |
periodStart | Date |
periodEnd | Date |
payment | String |
retryNextAt | Date |
retryNextGateway | String |
retryPolicy | String |
subscription | String |
number | String |
Customer Blacklist
Endpoint: GET /blacklist
Sortable fields: id, createdAt, updatedAt, email
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
email | String |
reason | String |
Secret Keys
Endpoint: GET /secret-keys
Sortable fields: id, createdAt, updatedAt
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
active | Boolean |
Request Logs
Endpoint: GET /logs
Sortable fields: id, createdAt, updatedAt
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
requestId | String |
url | String |
method | String |
clientIp | String |
statusCode | Number |
initiator | String |
Gateway Profiles
Endpoint: GET /gateway-profiles
Sortable fields: id, createdAt, updatedAt
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
title | String |
integration | String |
active | Boolean |
Cascades
Endpoint: GET /cascades
Sortable fields: id, createdAt, updatedAt, active, name
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
name | String |
active | Boolean |
algorithm | String |
Jobs
Endpoint: GET /jobs
Sortable fields: id, createdAt, updatedAt, status, type
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
status | String |
type | String |
progress | Number |
Job Items
Endpoint: GET /jobs/:id/items
Sortable fields: id, createdAt, updatedAt, status
Filterable fields:
| Field | Data Type |
|---|---|
id | String |
createdAt | Date |
updatedAt | Date |
status | String |