Filtering and search
Query parameter conventions shared by list endpoints: search, date ranges and time zones, booleans, enums, and strict validation.
List endpoints narrow results with query parameters. The same conventions apply everywhere.
Parameters are strict
An unknown or misspelled parameter answers 400. The API never ignores a filter, so a typo can never return an unfiltered list that looks like the right one.
curl "https://api-next.vitruve.fit/v1/workouts?userid=ATHLETE_ID" \
-H "X-API-Key: $VITRUVE_API_KEY"{
"ok": false,
"timestamp": 1738247125207,
"message": "Invalid query parameters: Unrecognized key(s) in object: 'userid'"
}Parameter names are case-sensitive: userId, not userid.
Parameter types
| Type | Format | Example |
|---|---|---|
uuid | A resource id. Lowercase or uppercase hex. | userId=3b9c1e24-6f7a-4d2b-8c15-a40e9d7f1b62 |
integer | Whole number. | limit=100 |
boolean | Exactly true or false. | recovered=false |
enum | One of the listed values, case-sensitive. | status=pending |
date | YYYY-MM-DD or an ISO 8601 datetime. | from=2026-01-01 |
string | Free text. Leading and trailing spaces are trimmed, empty is rejected. | search=garcia |
Date ranges
Endpoints with a date filter accept from, to and timezone. Both bounds are inclusive.
from and to take a bare date (YYYY-MM-DD) or an ISO 8601 datetime with at least hours and minutes, such as 2026-01-31T18:00, 2026-01-31T18:00:00Z or 2026-01-31T18:00:00+01:00. Anything else, such as 2026, Jan 5 or a Unix timestamp, answers 400. In a URL, encode the + of an offset as %2B: a bare + reads as a space.
| You send | Meaning |
|---|---|
from=2026-01-01 | From 2026-01-01T00:00:00.000Z |
to=2026-01-31 | Up to and including 2026-01-31T23:59:59.999Z: the whole day |
to=2026-01-31T12:00:00Z | Up to that exact instant |
from=2026-01-01&timezone=Europe/Madrid | From midnight in Madrid: 2025-12-31T23:00:00.000Z |
from=2026-01-01T08:00&timezone=Europe/Madrid | From 08:00 in Madrid: 2026-01-01T07:00:00.000Z |
from=2026-01-01T08:00%2B02:00&timezone=Europe/Madrid | From 2026-01-01T06:00:00.000Z: an explicit offset wins |
So from=2026-01-01&to=2026-01-31 returns everything in January, UTC. Either bound can be used alone.
timezone is an IANA time zone name such as Europe/Madrid or America/New_York, UTC by default. It sets how dates without an offset are read:
- A bare date covers that whole day in the zone. On a day whose midnight a daylight-saving change skips, the day starts at the change.
- A datetime without an offset is a wall-clock time in the zone.
- A datetime with
Zor an offset is taken as given.
An unknown zone answers 400.
Dates in a request body follow stricter rules: see Writes.
Which timestamp is filtered depends on the endpoint. For example, completed workouts are filtered and sorted by completedAt, pending ones by createdAt. The reference states it for each endpoint.
Text search
search matches case-insensitively with "contains" semantics. Athletes and coaches match name, surname or email, word by word: every word you send must match one of them, so search=ana garcia finds Ana García. Teams, programs, templates and exercises match their name.
Combining filters
Filters combine with AND. Filters of one endpoint can conflict. When they do, the endpoint answers 400 and its entry in the reference says which combination.
Validation errors
Validation failures answer 400. message names every offending parameter, separated by semicolons:
{
"ok": false,
"timestamp": 1738247125207,
"message": "Invalid query parameters: 'limit': Number must be less than or equal to 100; 'status': Invalid enum value. Expected 'completed' | 'pending', received 'done'"
}Path ids that are not UUIDs answer 400 with Invalid path parameters.
Pagination
Walk through any list with a cursor. Pages that stay correct while data changes, cost the same at any depth, and a copy-paste loop.
Writes
Create, update and delete athletes, coach assignments, teams, exercises, load-velocity profiles and injury reports, and retry creates safely with an Idempotency-Key.