Guides
Filtering and sorting
Most lists accept sort and the created* and updated* time filters, many accept list-valued filters such as statuses, and some accept q for free-text search. The examples use the orders list.
Send sort with up to three comma-separated fields; repeating a field is a 400. Lists such as incidents, kits, services, payments, invoice payments and treasury accounts take only one field (see the parameter description). A leading - sorts that field in descending order: sort=-startDate,orderNumber. Each list names its sortable fields in the description of the parameter; for orders they are createdAt, updatedAt, startDate, endDate, orderNumber, grossPrice, rentalDays and itemsCount, and the default is -createdAt.
- A field that is not in the list of sortable fields is rejected with 400
validation_error, and the error names it. - Ties are broken by
id, so the order is stable across pages. - A cursor is bound to the sort it was issued with: keep
sortthe same on every page. See Pagination. GET /apidoes not accept/v1 /availability /unavailabilities sort: it follows the date cursor of its source. The lists that are not paginated (see Pagination) are not sortable either.- If you sort by a field that changes while you page, such as
updatedAt, a record can be repeated or skipped.
The sortable fields of every list:
| Operation | Sort by |
|---|---|
GET /api | createdAt, updatedAt, name, contactType, role, status, email |
GET /api | createdAt, updatedAt, name, sku, salePrice, depositValue, serializedItemsCount, collectionName |
GET /api | createdAt, updatedAt, startDate, endDate, orderNumber, grossPrice, rentalDays, itemsCount |
GET /api | position, itemName, quantity, startDate, endDate, rentalDays, unitPrice, linePrice, status, resourceType, transactionType |
GET /api | createdAt, updatedAt, invoiceNumber, invoiceDate, dueDate, subTotal, grossPrice |
GET /api | createdAt, updatedAt, quoteNumber, issueDate, startDate, endDate, subTotal, grossPrice, operativeStatus |
GET /api | createdAt, updatedAt, name, projectNumber, startDate, endDate, status |
GET /api | date, amount, createdAt, updatedAt |
GET /api | position, itemName, quantity, startDate, endDate, rentalDays, unitPrice, linePrice, resourceType, transactionType |
GET /api | position, itemName, quantity, startDate, endDate, rentalDays, unitPrice, linePrice, resourceType, transactionType |
GET /api | createdAt, updatedAt, code, serialNumber, status, condition, itemName |
GET /api | createdAt, updatedAt, name, internalReference, isWarehouse, building, floor |
GET /api | createdAt, updatedAt, date, status, total |
GET /api | createdAt, updatedAt, name, registrationNumber, status, seats, payloadKg |
GET /api | createdAt, updatedAt, fullName, staffType |
GET /api | createdAt, updatedAt, startDate, endDate, pickupDate, returnDate, status, type, quantity |
GET /api | createdAt, updatedAt, poNumber, poDate, status, type, grossPrice, netPrice, isDraft |
GET /api | createdAt, updatedAt, contractNumber, contractDate, startDate, endDate, status, signedAt, grossPrice |
GET /api | name, createdAt, updatedAt |
GET /api | path, name, order, depth, itemCount, createdAt, updatedAt |
GET /api | name, serviceType, defaultQty, createdAt, updatedAt |
GET /api | startDate, endDate, title, status, createdAt, updatedAt |
GET /api | createdAt, updatedAt, dueDate, identifier, title, status, priority |
GET /api | createdAt, updatedAt |
GET /api | createdAt, updatedAt, startDate, endDate, title, isCompleted, type |
GET /api | createdAt, updatedAt, name, identifier, status, amount, expectedCloseDate |
GET /api | createdAt, updatedAt, invoiceDate, dueDate |
GET /api | name, type, status, currency, createdAt, updatedAt |
GET /api | date, amount, createdAt, updatedAt |
GET /api | createdAt, updatedAt, issueDate, grossPrice |
GET /api | createdAt, updatedAt, issueDate, proformaNumber |
GET /api | name, isActive, triggerType, createdAt, updatedAt |
GET /api | name, type, createdAt, updatedAt |
GET /api | name, email, status, createdAt, updatedAt |
Time filters
Link to this section: Time filtersMost lists filter by the time a record was created or last updated. The two families share five suffixes:
| Suffix | The record's time is… | Created | Updated |
|---|---|---|---|
| On | on that date | createdOn | updatedOn |
| After | after that date | createdAfter | updatedAfter |
| Before | before that date | createdBefore | updatedBefore |
| From | on or after that date | createdFrom | updatedFrom |
| To | on or before that date | createdTo | updatedTo |
Each value is a bare day (YYYY-MM-DD) or an ISO 8601 instant with an offset. A bare day is read in the business timezone of the account (timezone): From starts at the beginning of that day, To ends at the end of it, After means after the end of that day, Before means before its start, and On covers the whole day. An instant with an offset is applied as given, except with On, which covers the whole business day that contains it.
The operators are strict where their names say so: After is >, Before is <, From is >= and To is <=, compared with millisecond precision. For a bare day, From and Before use 00:00:00.000 of that day and To and After use 23:59:59.999, so updatedAfter=2026-10-09 excludes the whole of 9 October. From together with Before gives a half-open window, [from, before), whose edges never overlap with the next window. That is the shape Syncing data builds on. Not every list has these filters: GET /api, GET /api, GET /api, GET /api and GET /api reject any created* or updated* filter with 400; GET /api, GET /api, GET /api, GET /api, GET /api, GET /api, GET /api and GET /api have no updated* filters, and GET /api has only created*; GET /api, GET /api and GET /api can be sorted by updatedAt but have no updated* filters. Check the parameters of the operation. Lists add their own date filters too; orders also filter on when they start and end (for example startsFrom and endsBefore) and on a rental period that overlaps a window (overlapsFrom and overlapsTo).
Filters that take several values
Link to this section: Filters that take several valuesSome filters have a list-valued twin. statuses, contactIds and projectIds take up to 50 values and return the records that match any of them. Repeat the parameter or separate the values with commas: statuses=reserved,prepared and statuses=reserved&statuses=prepared are the same filter.
- The single-value filter is a different parameter:
statustakes one operational bucket (draft,reserved,prepared,in_use,returned,completedorcancelled),contactIdone contact. - More than 50 values is a 400. To filter by a larger set, split it into batches of 50 and merge the results.
Free-text search
Link to this section: Free-text searchWhere a list offers q, it is a free-text search whose description says what it matches. On orders it searches the order number, the project name or alias and the external reference, with 1 to 200 characters.
An example
Link to this section: An exampleOrders that are reserved or prepared, updated since 1 October and before 8 October, whose text matches acme, soonest start first and the biggest first among equal starts:
curl -sS --fail-with-body -G "${FILMO_BASE_URL:-https://app.filmo.io}/api/v1/orders" \
-H "Authorization: Bearer $FILMO_API_KEY" \
--data-urlencode "statuses=reserved,prepared" \
--data-urlencode "updatedFrom=2026-10-01" \
--data-urlencode "updatedBefore=2026-10-08T00:00:00+02:00" \
--data-urlencode "q=acme" \
--data-urlencode "sort=startDate,-grossPrice" \
--data-urlencode "limit=50" |
jq -r '.data[] | [.orderNumber, .status, .startDate, .grossPrice] | @tsv'const base = process.env.FILMO_BASE_URL ?? "https://app.filmo.io";
const url = new URL("/api/v1/orders", base);
url.searchParams.set("statuses", "reserved,prepared"); // or repeat: statuses=reserved&statuses=prepared
url.searchParams.set("updatedFrom", "2026-10-01"); // on or after the start of that day (account timezone)
url.searchParams.set("updatedBefore", "2026-10-08T00:00:00+02:00"); // before this instant
url.searchParams.set("q", "acme");
url.searchParams.set("sort", "startDate,-grossPrice"); // soonest start first, then the biggest order
url.searchParams.set("limit", "50");
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.FILMO_API_KEY}` } });
if (!res.ok) throw new Error(res.status + " " + (await res.text()));
const { data } = await res.json();
for (const order of data) console.log(order.orderNumber, order.status, order.startDate, order.grossPrice);import os
import requests
base = os.environ.get("FILMO_BASE_URL", "https://app.filmo.io")
params = {
"statuses": ["reserved", "prepared"], # sent as repeated parameters; a comma-separated string works too
"updatedFrom": "2026-10-01", # on or after the start of that day (account timezone)
"updatedBefore": "2026-10-08T00:00:00+02:00", # before this instant
"q": "acme",
"sort": "startDate,-grossPrice", # soonest start first, then the biggest order
"limit": 50,
}
res = requests.get(
base + "/api/v1/orders",
headers={"Authorization": f"Bearer {os.environ['FILMO_API_KEY']}"},
params=params,
timeout=30,
)
res.raise_for_status()
for order in res.json()["data"]:
print(order["orderNumber"], order["status"], order["startDate"], order["grossPrice"])Combine filters with the loop in Pagination: keep the same filters, sort and limit on every page.
Related pages
Link to this section: Related pagesGuides
Pagination
Lists return one page at a time. Ask for a page with
limit, and whilepagination.ishasMore truecall again with thenextCursoryou were given.Guides
Syncing data
Filmo v1 does not send webhooks, so you keep another system in step by polling: read what changed in half-open time windows, and run a separate sweep to find what was deleted. Do not follow the pagination cursor to decide what changed or what disappeared.
Guides
Data types
Money is a decimal string, dates are ISO 8601, a property can be present and null, and custom fields are maps. Parse each type once, at the edge of your integration.
Was this page helpful?