Guides

Build searches from advertised capabilities

Choose the correct operation and construct typed searches from the contract published by each Service and Collection.

Let the Service interpret text queries

query contains the caller's search text, and the Service decides how to interpret it. ODP does not standardize searchable fields, tokenization, stemming, case folding, language processing, semantic matching, or relevance.

Agents therefore preserve the caller's query and do not assume equivalent results across Services. When a request includes both text and filters, an Offering must satisfy the Service-interpreted query and every Filter Expression.

Discover capabilities before filtering

search_capabilities advertises Filter and Sort Definitions that a Service accepts. Each source is either a bounded inline array or a same-origin link to a pageable definition sequence. Filters and sorts are independent sources.

The field appears only when the Service advertises search-offerings. It can be published at Service scope or on a Full Collection for searches that explicitly name that Collection.

{
  "search_capabilities": {
    "filters": {
      "inline": [
        {
          "id": "result-count",
          "title": "Result count",
          "description": "Maximum results returned by the Offering.",
          "type": "integer",
          "operators": ["eq", "in", "gte", "lte"],
          "refinable": true
        }
      ]
    },
    "sorts": {
      "inline": [
        {
          "id": "most-results",
          "title": "Most results",
          "description": "Order by the largest result count.",
          "keys": [
            {
              "filter_id": "result-count",
              "direction": "descending",
              "missing": "last"
            }
          ]
        }
      ]
    }
  }
}
A definition belongs to one search context

A capability identifier has meaning only within its Service, operation, source, definition kind, and effective scope. Similar identifiers at different Services or scopes are not interchangeable.

An Agent retrieves and validates an entire linked source before exposing any definitions from it. A failed source is omitted from the normalized catalog without preventing text-only Offering search.

Combine the applicable search capabilities

An Offering search without collection_id uses only Service-wide capabilities. A search naming a Collection uses the union of Service-wide capabilities and capabilities advertised by that exact Collection.

  • Service scope: apply Service-wide definitions first
  • Collection scope: add definitions from only the Collection explicitly named by the request
  • Descendant expansion: change Offering membership scope without inheriting capabilities from descendants
  • Conflicts: remove every duplicated identifier from the usable catalog instead of choosing an override

Ancestors, descendants, and other Collections do not contribute definitions. A Sort Definition that references a missing, invalid, or conflicting Filter Definition is also unavailable, while unrelated definitions remain usable.

Use typed Filter Definitions

A Filter Definition declares its identifier, human-readable title and description, value type, and supported operators. It maps each Offering to zero or more scalar values without exposing how the Service stores or computes them.

TypeWire valueCompatible operators
stringJSON stringeq, in, exists
booleanJSON Booleaneq, in, exists
integer, numberJSON integer or numberAll seven core operators
decimalBase-10 string without an exponentAll seven core operators
date, date-timeRFC 3339 date or instantAll seven core operators

The seven core operators are eq, in, lt, lte, gt, gte, and exists. Ordered comparisons do not apply to strings or Booleans.

String filter equality is case-sensitive and performs no normalization or locale folding. A definition marked refinable: true must advertise eq, in, or both.

Construct valid Filter Expressions

Each expression identifies an effective Filter Definition, selects one of its advertised operators, and supplies a value of the declared type. Every expression in the request combines with logical AND.

  • Scalar comparisons: eq, lt, lte, gt, and gte accept one scalar
  • Set membership: in accepts 1 through 100 unique values and matches when either set intersects
  • Presence: exists accepts a Boolean and tests whether the Offering's mapped value set is empty
  • Ranges: repeat one identifier with lower and upper comparison expressions

ODP 1.0 does not define a general Boolean tree, negation, substring matching, or regular-expression filtering. An unknown identifier, unadvertised operator, or incorrectly typed value produces an INVALID_REQUEST problem.

Select an advertised sort recipe

A Sort Definition is a complete ordering recipe with one through three keys. The Agent selects it by identifier and does not add, remove, reverse, or reorder those keys.

Each key references an effective Filter Definition and fixes its direction and missing-value placement. The Service appends Offering id as the final ascending tie-breaker. Omitting sort uses the Service's preferred ordering.

Request contextual refinements

A Filter Definition marked refinable: true can produce value-count buckets for guided navigation. The initial Offering-search request names up to 16 refinable identifiers, and the initial response can return bounded groups for useful values.

A bucket count applies the query, Collection scope, access context, and every filter except expressions for that bucket's own filter. This preserves independent constraints while showing viable alternatives for the selected dimension.

{
  "odp_version": "1.0",
  "items": [
    {
      "id": "web-search",
      "name": "Web search"
    }
  ],
  "refinements": [
    {
      "filter_id": "result-count",
      "values": [
        {
          "value": 20,
          "count": 4
        },
        {
          "value": 50,
          "count": 2,
          "count_relation": "lower_bound"
        }
      ]
    }
  ],
  "next": "/odp/offerings/search?cursor=opaque-value"
}

The response says that four distinct Offerings match the criteria when result-count equals 20. At least two match when it equals 50; lower_bound prevents the Agent from presenting that second count as exact.

Counts describe the logical result set

Sorting and page limits do not affect a bucket count. An exact count omits count_relation; a count known only as a minimum uses lower_bound. Refinement values are contextual suggestions, not a complete enumeration of the filter's domain.

Distinguish no matches from an invalid request

A well-formed search that finds nothing succeeds with an empty page. A request that cannot be interpreted against the advertised contract fails with an INVALID_REQUEST problem instead of silently ignoring the unsupported criterion.

Invalid requestWhy it fails
No query or filtersOffering search requires at least one constraint; use a list operation otherwise.
Unknown filter or sort IDThe identifier is unavailable in the effective capability catalog.
Unadvertised operatorThe Filter Definition did not authorize that comparison.
Wrong value type or shapeThe value does not match the filter type or the selected operator's scalar, array, or Boolean contract.
Descendants without a Collectioninclude_descendants has no scope unless collection_id is present.
Unavailable refinementThe referenced filter is missing, invalid, duplicated, or not marked refinable.

A named Collection that does not resolve under the current access context produces 404 Not Found. The Service can use the same result when confirming that an inaccessible Collection exists would disclose protected information.

Preserve the search across pages

The Service chooses a stable logical sequence and returns an opaque next reference when another page exists. The continuation preserves the original query, filters, sort, Collection scope, access context, representation, and effective page limit.

Follow the continuation reference as returned rather than reconstructing or editing it. Refinement groups describe the complete logical result set and can appear only on the initial response, not continuation pages. See Pagination and caching for traversal and refresh behavior.

Next steps

Domain data

Define searchable attributes

Give specialized Offering data explicit types and constraints.

Custom attributes
Traversal

Keep result pages stable

Follow continuation references and HTTP cache controls correctly.

Pagination and caching