Skip to main content
Most list endpoints in the Gumnut API support pagination, filtering, and sorting to help you efficiently retrieve the data you need.

Pagination

List endpoints support cursor-based pagination using limit and starting_after_id:
Paginated responses include a has_more field indicating whether additional results exist:
To fetch the next page, pass the id of the last item as starting_after_id.
If you’re using one of our SDKs, pagination is handled automatically with built-in iterators.

Paging search results

GET /api/search and POST /api/search page by number instead of by cursor, and the SDK search methods return one page per call rather than an iterator. Pass limit (1–200, default 20) and a 1-indexed page. While has_more is true, increment page and repeat the same search criteria, filters, and limit:
Stop when has_more is false, even if the current page is full. Search requires a nonblank text query or an uploaded image and returns a limited number of the most relevant matches in relevance order, not every match in your library. GET /api/search requires text; POST /api/search accepts text, an image, or both. A request without either returns 422, even when structured filters are supplied. Use GET /api/assets for browsing with only structured filters and follow its cursor pagination. Each result can carry match_strength. best results are strong matches and come first; possible results follow and are often unrelated. It is null when the search did not judge the result, such as an image search. distance remains in each search result for compatibility, but is deprecated. Don’t use it to judge text-search relevance or result order; use match_strength for text-search relevance. A text query search can return fewer than limit results, or none, and has_more can be false after a short or empty page. An empty first page means nothing within your filters closely matches that wording: rephrase or broaden the query, or change the filters, instead of requesting another page.

Filtering

Use query parameters to filter results:

Filtering albums by name

You can filter GET /api/albums with the optional name query parameter. For example, GET /api/albums?name=summer matches album names containing summer, regardless of case. The match is a literal substring, so % and _ are treated as characters. Gumnut trims surrounding whitespace; omitting name or sending it blank applies no name filter. Filtering happens before cursor pagination, so the next page continues through matching albums.

Filtering by capture time

local_datetime_after and local_datetime_before filter on the asset’s capture time:
  • Send offsetless values such as 2024-01-01T00:00:00 when you want wall-clock filtering.
  • Send offset-aware values such as 2024-01-01T00:00:00-05:00 when you want an absolute time window.
  • Keep both bounds consistent. Mixing an offsetless value with an offset-aware value in the same request is rejected.
  • Assets with a known capture offset are compared using that offset. Assets without one fall back to wall-clock comparison, so offsetless captures still participate in aware range filters.
Use GET /api/search when you want natural-language or metadata search. The endpoint accepts the same canonical date and album filters as asset lists:
Use an album ID, not an album name, for album_id. You can also pass person_ids for one or more people. These filters narrow a content search; they do not replace the required nonblank query. The same filters are available on POST /api/search, which requires text, an image, or both in the multipart request. Use GET /api/assets when you only need album, people, rating, media-type, date, or location filters. Use the canonical parameter names shown above. The legacy search spellings captured_after, captured_before, and album_ids are no longer supported; replace them with local_datetime_after, local_datetime_before, and album_id.

Filtering by location

GET /api/assets and GET /api/assets/counts support the same two location filter shapes:
  • center + radius for a circular search area in meters
  • bbox for a rectangular viewport in min_longitude,min_latitude,max_longitude,max_latitude order
Use center and radius together. Don’t combine them with bbox. Spatial count filters compose with the endpoint’s album, people, rating, media-type, date, and lifecycle filters. When a count response has more pages, repeat the same spatial selector with starting_after_bucket. To count all and only assets with coordinates, send the full-world box:
Coordinate-less assets do not match this box. This is the geotagged-only count idiom; there is no separate coordinate-presence flag. A viewport that crosses the antimeridian is a single box whose west longitude is greater than its east longitude. It selects the band running east from min_longitude over ±180° to max_longitude, so you don’t split it into two requests. Because longitude order carries that meaning, it’s significant: a box with west and east transposed reads as a crossing viewport rather than an error. A viewport 360° or wider must be sent as the full range -180,...,180,..., which the wrapped form can’t express. For semantic search, GET /api/search supports both center + radius and bbox as mutually exclusive location filters. Include a nonblank query; location only narrows that content search. Use GET /api/assets to browse by coordinates without text. See Requests & Responses for how local_datetime is serialized, and see the API Reference tab for the full list of available filter parameters for each endpoint.

Map views with geo clusters

When you need a map-friendly summary of geotagged assets inside a viewport, use GET /api/assets/geo-clusters instead of paging through GET /api/assets and grouping results client-side. The endpoint takes a bbox string in min_longitude,min_latitude,max_longitude,max_latitude order plus a cell_size in decimal degrees.
It also supports the same top-level filters you already use on asset lists: library_id, album_id, person_ids, local_datetime_after, local_datetime_before, and state. Each item in data represents one non-empty grid cell and includes a centroid (latitude, longitude), the number of matching assets (count), and a representative_asset_id you can use as a cover image or lookup key.
GET /api/assets/geo-clusters is not paginated. The response is capped at 1000 non-empty cells, so a dense viewport returns 422 instead of partial results. If that happens, increase cell_size or zoom in and retry. A viewport crossing the antimeridian is clustered as one wrap-around band — send it as a single box whose west longitude is greater than its east longitude. Note that the 1000-cell cap then applies to that one response, so a viewport both very wide and very dense across ±180° may need a coarser cell_size than each half would have.
See the API Reference tab for the full request and response schema.