The OData (Open Data Protocol) is an open standard from Microsoft that defines best practices for building and consuming REST APIs. In Business Central, you can extend OData capabilities by creating APIs with AL code and publishing your application to the environment, either deployed directly to a Sandbox from VS Code or uploaded through Extension Management in your production environment.

Business Central also delivers a comprehensive set of APIs out of the box for common tables. For example, you can perform POST, GET, PATCH, and DELETE operations on the Item table without writing any code. You can try this by running:

GET https://api.businesscentral.dynamics.com/v2.0/{tenantID}/{env}/api/v2.0/companies({companyId})/items

This will return a list of all the items in your Business Central environment. But what if you would like to filter these entries by only those that have inventory for example, thats when you can use filter expressions.

Business Central supports the following OData query options

  • $top - Limits the number of records returned
  • $filter - Narrows down which records to return
  • $select - Specifies which fields to include (reduces payload size)
  • $skip - Enables pagination by skipping records
  • $orderby - Sorts results by specified fields
  • $expand - Includes related entities

So let's get the three most recent items within a date and sort them by the newest first:

GET .../items?$top=3&$filter=postingDate gt 2025-12-13&$orderby=postingDate desc

Since we're into $filters which is by far the most advanced OData filter expression, let's look at the filter operators reference.

Comparison operators

# eq (Equal) - Returns items where type is Inventory:
$filter=type eq 'Inventory'
# ne (Not equal) - Returns all non-blocked items
$filter=blocked ne true
# gt (Greater than) - Returns items with unit inventory above 100
$filter=inventory gt 100
# ge (Greater than or equal) - Returns items with 50 or more units in stock
$filter=inventory ge 50
# lt (Less than) - Returns items with fewer than 50 units in stock
$filter=inventory lt 50
# le (Less than or equal) - Returns items with 10 or fewer units
$filter=inventory le 10

Logical operators

# and (Logical AND) - Returns available, non-blocked items with stock
$filter=inventory gt 0 and blocked eq false
# or (Logical OR) - Returns items that are either Inventory or Service type
$filter=type eq 'Inventory' or type eq 'Service'
# not (Logical negation) - Returns all items except chairs
$filter=not (itemCategoryCode eq 'CHAIR')

Grouping

# ( ) Precedence grouping - Returns Inventory or Service items that have stock on hand
$filter=(type eq 'Inventory' or type eq 'Service') and inventory gt 0

String functions

# contains (Search for substring) - Returns items with "bike" anywhere in the description field
$filter=contains(description, 'bike')
# endswith (Test if string ends with value) - Returns items whose number ends with "-RED"
$filter=endswith(number, '-RED')
# startswith (Test if string starts with value) - Returns items whose number starts with "1000"
$filter=startswith(number, '1000')
# tolower (Convert to lowercase) - Case-insensitive description match
$filter=tolower(description) eq 'bicycle'
# toupper (Convert to uppercase) - Case-insensitive category match
$filter=toupper(itemCategoryCode) eq 'BIKE'

Using $select for performance

By default, OData returns all fields for an entity. Using $select allows you to request only the fields you need, which improves performance and reduces the payload, and with that the bandwidth usage.

# Basic field selection
$select=number,description,unitPrice

Combining this with the $filter you can reduce payload size a lot:

$filter=contains(description, 'bicycle')&$select=number,description,inventory,baseUnitOfMeasure

Conclusion

This was a brief introduction to OData filter expressions in Business Central, more about $expand in another article. Go give it a try!

For documentation about the Item API used in this article, you can find it here: