Skip to main content

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
ParameterDescriptionSupported ValuesDefault Value
pageThe page number to retrieve.Positive integers1
pageSizeThe number of items per page.Positive integers less than or equal to 10010
note

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
ParameterDescriptionSupported ValuesDefault Value
sortByThe field to sort by.Any sortable fieldcreatedAt
sortDirectionThe direction of sorting.asc, desc, ASC, DESCasc

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:

OperatorDescriptionBooleanNumberStringDate
eqEqual to
neNot equal to
gtGreater than
gteGreater than or equal to
ltLess than
lteLess than or equal to
inIn
ninNot in
likeLike (partial match)
containsArray contains value

Each endpoint supports different fields for filtering, which are documented below in the Supported endpoints section.

warning

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 true and false are valid.
  • Number: only integers are valid. Float values are parsed as integers (e.g., 100.5 becomes 100).
  • String: any string is valid. String filters are case-insensitive (e.g., name[eq]=john will match John, 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 null to 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:

Using qs to build query strings
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
warning

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

note

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.

  1. $or[0][status][eq]=succeeded&$or[0][isCaptured][eq]=true = The payment status must be succeeded and the payment must be captured.
  2. $or[1][status][eq]=succeeded&$or[1][isReversed][eq]=true&$or[1][isCaptured][eq]=true = The payment status must be succeeded and 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
important

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 where field1 exists and equals value
  • metadata[field1][ne]=value - Only matches entities where field1 exists and does NOT equal value (entities without field1 are 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:

FieldData Type
idString
createdAtDate
updatedAtDate
firstNameString
lastNameString
emailString
phoneNumberString
dateOfBirthDate
restrictMitBoolean
restrictCitBoolean
restrictReasonString
metadataJSON

Payments

Endpoint: GET /payments

Sortable fields: id, createdAt, updatedAt, amount, status, currency

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
amountNumber
statusString
displayStatusString
currencyString
amountCapturedNumber
amountReversedNumber
captureMethodString
captureDelayNumber
captureAtDate
statementDescriptorString
isCapturedBoolean
isReversedBoolean
isChargebackedBoolean
isRedirectRequiredBoolean
customerString
customer.emailString
latestTransactionString
latestTransaction.processorIdString
paymentMethodString
paymentMethod.typeString
paymentMethod.card.lastFourString
paymentMethod.card.binString
paymentMethod.card.brandString
paymentMethod.card.expYearString
paymentMethod.card.expMonthString
paymentMethodOptions.card.gatewayProfileString
paymentMethodOptions.card.cascadeString
paymentMethodOptions.card.modeString
paymentMethodOptions.paypal.gatewayProfileString
metadataJSON

Subscriptions

Endpoint: GET /subscriptions

Sortable fields: id, createdAt, updatedAt, status, currentPeriodStart, currentPeriodEnd, startDate, endDate

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
statusString
startDateDate
endDateDate
autoBillingEnabledBoolean
autoBillingDisabledAtDate
autoBillingDisabledReasonString
cancelAtPeriodEndBoolean
currentPeriodStartDate
currentPeriodEndDate
currentCycleNumber
customerString
customer.emailString
priceString
metadataJSON

Payment Methods

Endpoint: GET /payment-methods

Sortable fields: id, createdAt, updatedAt, isDefault, customer

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
isDefaultBoolean
customerString
card.lastFourString
card.brandString
card.expYearString
card.expMonthString

Users

Endpoint: GET /users

Sortable fields: id, createdAt, updatedAt, email

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
emailString
firstNameString
lastNameString
usernameString

Webhook Subscribers

Endpoint: GET /webhook-subscribers

Sortable fields: id, createdAt, updatedAt

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate

Products

Endpoint: GET /products

Sortable fields: id, createdAt, updatedAt, name, active

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
nameString
activeBoolean
metadataJSON

Prices

Endpoint: GET /prices

Sortable fields: id, createdAt, updatedAt, amount, type

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
amountNumber
currencyString
typeString
nameString
productString
product.idString
product.nameString
activeBoolean
metadataJSON

Invoices

Endpoint: GET /invoices

Sortable fields: id, createdAt, updatedAt, status

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
statusString
currencyString
amountNumber
voidedReasonString
periodStartDate
periodEndDate
paymentString
retryNextAtDate
retryNextGatewayString
retryPolicyString
subscriptionString
numberString

Customer Blacklist

Endpoint: GET /blacklist

Sortable fields: id, createdAt, updatedAt, email

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
emailString
reasonString

Secret Keys

Endpoint: GET /secret-keys

Sortable fields: id, createdAt, updatedAt

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
activeBoolean

Request Logs

Endpoint: GET /logs

Sortable fields: id, createdAt, updatedAt

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
requestIdString
urlString
methodString
clientIpString
statusCodeNumber
initiatorString

Gateway Profiles

Endpoint: GET /gateway-profiles

Sortable fields: id, createdAt, updatedAt

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
titleString
integrationString
activeBoolean

Cascades

Endpoint: GET /cascades

Sortable fields: id, createdAt, updatedAt, active, name

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
nameString
activeBoolean
algorithmString

Jobs

Endpoint: GET /jobs

Sortable fields: id, createdAt, updatedAt, status, type

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
statusString
typeString
progressNumber

Job Items

Endpoint: GET /jobs/:id/items

Sortable fields: id, createdAt, updatedAt, status

Filterable fields:

FieldData Type
idString
createdAtDate
updatedAtDate
statusString