Skip to content

Sorting

Sort criteria for collection queries


Sorting allows clients to specify the order of resources in collection responses. Multiple sort criteria are applied in sequence.


A sort specifies ordering for a single attribute:

{
"attribute": "created_at",
"direction": "desc"
}
FieldTypeRequiredDescription
attributestringYesAttribute to sort by
directionstringYesSort direction
ValueSQL EquivalentDescription
ascASCAscending (smallest first)
descDESCDescending (largest first)

Multiple sorts create compound ordering:

{
"sorts": [
{ "attribute": "status", "direction": "asc" },
{ "attribute": "created_at", "direction": "desc" }
]
}

Sorts are applied in array order:

{
"sorts": [
{ "attribute": "country_code", "direction": "asc" },
{ "attribute": "city", "direction": "asc" },
{ "attribute": "name", "direction": "asc" }
]
}
// SQL: ORDER BY country_code ASC, city ASC, name ASC

Primary sort is first, then secondary, etc.


Servers MUST define which attributes are sortable:

{
"sorts": {
"self": ["name", "created_at", "updated_at", "status", "total_amount"]
}
}
  • Sorting on non-allowed attributes MUST return an error
  • Servers SHOULD expose allowed sorts via mesh.describe
{
"errors": [{
"code": "INVALID_ARGUMENTS",
"message": "Sort attribute not allowed: secret_score",
"retryable": false,
"source": {
"pointer": "/call/arguments/sorts/0/attribute"
},
"details": {
"attribute": "secret_score",
"allowed": ["name", "created_at", "status"]
}
}]
}

When no sort is specified, servers SHOULD apply a default sort:

  • By primary key (id) ascending
  • By creation timestamp (created_at) descending
  • By a natural ordering attribute

Servers MUST document their default sort behavior.

For pagination stability, servers SHOULD include a unique attribute (like id) as the final sort criterion, even if not explicitly requested:

// Client requests
{ "sorts": [{ "attribute": "status", "direction": "asc" }] }
// Server applies (for stability)
// ORDER BY status ASC, id ASC

TypeOrder
Numbers1, 2, 3, 10, 100
StringsA, B, C, a, b, c (locale-dependent)
DatesOldest first
Booleansfalse, true
NullsFirst or last (implementation-defined)
TypeOrder
Numbers100, 10, 3, 2, 1
Stringsc, b, a, C, B, A (locale-dependent)
DatesNewest first
Booleanstrue, false
NullsFirst or last (implementation-defined)

Servers SHOULD document null ordering behavior:

BehaviorDescription
nulls_firstNulls sort before non-null values
nulls_lastNulls sort after non-null values

{
"sorts": [
{ "attribute": "created_at", "direction": "desc" }
]
}
{
"sorts": [
{ "attribute": "name", "direction": "asc" }
]
}
{
"sorts": [
{ "attribute": "priority", "direction": "asc" },
{ "attribute": "created_at", "direction": "asc" }
]
}
{
"sorts": [
{ "attribute": "distance", "direction": "asc" }
]
}

{
"call": {
"function": "orders.list",
"version": "1",
"arguments": {
"sorts": [
{ "attribute": "created_at", "direction": "desc" }
]
}
}
}
{
"arguments": {
"sorts": [
{ "attribute": "status", "direction": "asc" },
{ "attribute": "priority", "direction": "desc" },
{ "attribute": "created_at", "direction": "asc" }
]
}
}
{
"arguments": {
"filters": [
{ "attribute": "status", "operator": "in", "value": ["pending", "processing"] }
],
"sorts": [
{ "attribute": "created_at", "direction": "desc" }
],
"pagination": {
"limit": 25
}
}
}
{
"call": {
"function": "locations.list",
"version": "1",
"arguments": {
"filters": [
{ "attribute": "type", "operator": "equals", "value": "pickup_point" },
{ "attribute": "country_code", "operator": "equals", "value": "FI" }
],
"sorts": [
{ "attribute": "distance", "direction": "asc" },
{ "attribute": "name", "direction": "asc" }
],
"pagination": {
"limit": 10
}
}
}
}
{
"protocol": { "name": "mesh", "version": "0.1.0" },
"id": "req_sorted",
"call": {
"function": "tracking_events.list",
"version": "1",
"arguments": {
"fields": {
"self": ["id", "status", "location", "occurred_at"]
},
"filters": [
{ "attribute": "shipment_id", "operator": "equals", "value": "ship_12345" }
],
"sorts": [
{ "attribute": "occurred_at", "direction": "desc" }
],
"pagination": {
"limit": 100
}
}
}
}

Functions SHOULD advertise sortable attributes via mesh.describe:

{
"result": {
"function": "orders.list",
"query": {
"sorts": {
"self": ["id", "order_number", "status", "total_amount", "created_at", "updated_at"]
},
"default_sort": [
{ "attribute": "created_at", "direction": "desc" }
]
}
}
}