Filtering, sorting, and expanding

Narrow Wingspan V3 lists with filter[field][operator], order them with sort[field], and inline related resources with expand.

Use Wingspan V3 query parameters to filter and sort list results, and expand related resources in a single request. V3 replaces the V1 schema.filter('field', '=') style with one bracketed syntax that works consistently across endpoints.

Each endpoint declares which fields and operators it accepts. The reference page for the endpoint lists them. Anything the endpoint doesn't declare is rejected with 422 ValidationError, so a typo in a filter never silently returns the whole list.

Tip: Brackets in query strings confuse some tools. With curl, pass -g (as in the examples below) or URL-encode the brackets.

Filter

Filters use the form filter[field][operator]=value:

curl -g "https://api.wingspan.app/v3/payments/payables?filter[status][eq]=Opened" \
  -H "Authorization: Bearer $WINGSPAN_TOKEN"

Operators

OperatorMeaningExample
eqEqualsfilter[status][eq]=Opened
neDoes not equalfilter[metadata.invoiceType][ne]=approvedInvoicesPayment
gt, gteGreater than, greater than or equalfilter[createdAt][gte]=2026-01-01T00:00:00Z
lt, lteLess than, less than or equalfilter[createdAt][lte]=2026-03-31T23:59:59Z
anyOfMatches any value in a listfilter[status][anyOf][]=Opened&filter[status][anyOf][]=Paid
noneOfMatches none of the values in a listfilter[status][noneOf][]=Deactivated

Operators are words, never symbols. For the list operators anyOf and noneOf, repeat the parameter once per value with [] at the end.

Not every endpoint accepts every operator. Check the endpoint's reference page for the operators each field accepts. Recurring invoice and recurring payable status filters, and webhook metadata filters, currently accept a single eq value and don't support anyOf yet.

Add more parameters to combine filters. Every filter must match because Wingspan joins filters with AND:

curl -g "https://api.wingspan.app/v3/platform/batches?filter[type][eq]=PayableImport&filter[status][anyOf][]=Completed&filter[status][anyOf][]=Failed&filter[createdAt][gte]=2026-04-01T00:00:00Z" \
  -H "Authorization: Bearer $WINGSPAN_TOKEN"

Values follow the field's type: enum values in TitleCase, timestamps in ISO 8601 UTC, dates as YYYY-MM-DD.

Look up by your own ID

Resources with an externalId usually accept filter[externalId][eq]. Use it to find a record from the ID in your system:

curl -g "https://api.wingspan.app/v3/payments/payees?filter[externalId][eq]=CONTRACTOR-00417" \
  -H "Authorization: Bearer $WINGSPAN_TOKEN"

Filter by metadata

Some list endpoints accept filters on metadata keys with a dotted name, such as filter[metadata.region][eq]=west. Check the endpoint's reference page to confirm that it supports metadata filtering. Metadata values are strings, so use equality operators rather than ranges.

Filter across child Accounts

Some payer-side lists, including payees, payables, and invoices, accept filter[accountIds][anyOf][]=.... Use this filter to read across multiple Accounts you can access in one call. To work within one child Account, send X-Wingspan-Account instead. See Acting on behalf of Accounts.

Sort

Sort uses the form sort[field]=asc or sort[field]=desc:

curl -g "https://api.wingspan.app/v3/payments/recurring-invoices?sort[createdAt]=desc" \
  -H "Authorization: Bearer $WINGSPAN_TOKEN"

Each list has a default order. Check the endpoint's reference page to confirm that it accepts sort and identify the fields you can sort by. Search endpoints accept exactly one sort field. See Search.

Sort one field at a time. Accounting sync activities use sort=createdAt or sort=-createdAt instead.

Expand

Some read responses include an ID for a related resource, such as payeeId on a payable. Add expand to include that related resource inline in the response and avoid a second call:

curl -g "https://api.wingspan.app/v3/payments/payables/b3VhT6gJq1MzR8xKd5WnPe?expand=payee&expand=attachments" \
  -H "Authorization: Bearer $WINGSPAN_TOKEN"

Repeat expand once per value. The bracket form expand[]=payee is also accepted and means the same thing. Don't comma-separate values; expand=payee,attachments is rejected.

Only specific read endpoints support expansion, and each accepts a fixed set of values. Values are case-sensitive and use different casing conventions, so copy them exactly:

EndpointSupported expand values
GET /v3/payments/invoices/{invoiceId}payer, payee, attachments, splits.payee
GET /v3/payments/payables/{payableId}payer, payee, attachments, splits.payee
GET /v3/payments/payee-engagements/{payeeEngagementId}Requirements, WorkDefinitions
GET /v3/payments/payees/{payeeId}/engagements/{payeeEngagementId}Requirements, WorkDefinitions
GET /v3/payments/payers/{payerId}/engagements/{payerEngagementId}workDefinitions
GET /v3/payments/payees/{payeeId}ComplianceEntity
GET /v3/payments/payers/{payerId}ComplianceEntity
GET /v3/payments/payouts and GET /v3/payments/payouts/{payoutId}routing, settingsSnapshot
GET /v3/payments/payroll-runs/{payrollRunId}Breakdown
GET /v3/platform/accounts/{accountId}ComplianceEntity
GET /v3/platform/persons/{personId}ComplianceEntity, IntercomIdentity
GET /v3/platform/plansproducts
GET /v3/platform/batches/{batchId}/summaryBreakdown
GET /v3/onboarding/payee-requirements/{requirementId}Configuration
GET /v3/onboarding/requirement-definitions/{requirementDefinitionId}DataSource
GET /v3/compliance/forms/{formId}BlockedByIds
GET /v3/compliance/insurance-monitors/{monitorId}Configuration, Coverage

An unsupported value returns 422 ValidationError. A supported value that has nothing to include (for example, a payable with no attachments) returns 200 without that key.

Expansion on invoices and payables is caller-relative: you receive the related record from your side of the relationship. For example, when a payer expands payee, the response includes that payer's Payee record, not the other party's view.

From V1 query parameters

V1V3
schema.filter('status', '=')filter[status][eq]=...
schema.filter('status', '!=')filter[status][ne]=... or filter[status][noneOf][]=..., whichever the endpoint lists
schema.filter('status', 'in')filter[status][anyOf][]=... repeated
>, >=, <, <=gt, gte, lt, lte
betweengte and lte together
contains on names and emailsfilter[searchString][eq]=... on the /v3/search endpoints
clientData.externalId / memberData.externalIdfilter[externalId][eq]=...
labels.*filter[metadata.*][eq]=... where supported
page=2&limit=10page[size]=10 and page[token]=.... See Pagination

V1 also let you filter on tax identifiers and W-9 fields. V3 doesn't offer filters on tax identifiers.

What can go wrong

ResponseCauseFix
422 ValidationError, errors[].code: UnsupportedValueThe field or operator isn't declared for this endpoint, or an enum value is misspelledCheck the endpoint's reference page for the fields and operators it accepts
422 ValidationError on expandThe expand value isn't supported on this endpoint, its case is wrong, or several values were comma-separatedUse a value from the table above, spelled exactly
422 ValidationError on sortThe endpoint doesn't accept sort, or not on that fieldRemove sort, or use a field the reference lists

Related pages


Did this page help you?