Advanced queries — filter, project and paginate the API
PremiumBeyond calling one endpoint at a time, the Omniscol API offers three search surfaces. Together they cover free-text lookup, resolving a human name to a technical identifier, and running a filtered, projected, paginated query on top of any read endpoint — without stringing several calls together yourself.
The same building blocks answer the questions an intranet, a booking tool or an ETL asks most often — starting with "which room or teacher is free on this slot?" (see Finding an available room or teacher).
The three surfaces at a glance
| Endpoint | What it does | Best for |
|---|---|---|
POST /api/search |
Global free-text search across the whole account. Splits your text into words (case- and accent-insensitive) and returns the JSON paths where every word was found. | A quick "where does this term appear?" lookup. |
POST /api/search/entity |
Resolves a name to an entity. Handles accents, wildcards and approximate matching (Dice similarity), and returns the entity type, identifier and context. | Turning "6A" into the class, or "Martine Dupont" into the teacher. |
POST /api/search/query |
Query orchestrator: calls a read endpoint, then applies a where filter, field projection, sorting and pagination on the result. |
Complex, filtered questions that would otherwise take several calls. |
All three live in the interactive API reference (the /developers page) under the Search section, and require authentication — see Omniscol API.
The where filter (Mango / MongoDB-style)
Both /api/search/entity and /api/search/query accept a where
clause: a structured filter using MongoDB-style operators. A field
maps either to a direct value (implicit equality) or to an object of
operators; several operators on the same field combine with an implicit
AND. Field names support dot-paths to reach a parent context
(for example sites.name).
| Operator | Meaning |
|---|---|
$eq / $ne |
Equal / not equal |
$gt $gte $lt $lte |
Comparisons |
$in / $nin |
Value in / not in a list |
$exists |
Field is present |
$regex |
Regular expression (case-insensitive) |
$contains |
String or array contains a value (case-insensitive) |
$like |
Fuzzy text match, ignoring accents and punctuation (Dice) |
$and $or $not |
Logical composition |
A few examples:
{ "capacity": { "$gte": 20, "$lte": 50 } }
{ "level": { "$in": ["L1", "L2", "L3"] } }
{ "name": { "$regex": "^lab" } }
{ "city": { "$like": "ivry sur seine" } }
{ "$or": [ { "capacity": { "$gte": 50 } }, { "specialisation": "chemistry" } ] }
Projection, sorting and pagination
On /api/search/query, four more levers keep the payload small and
ordered — which matters for a dashboard, and even more for an AI agent
that pays per token:
project— the list of fields to keep (dot-paths allowed). Everything else is dropped.sort— one field,ascordesc. The pseudo-field_count.<field>sorts by the length of an array field.limitandoffset— page through the results.
The response also returns a meta block: how many items existed before
filtering, how many passed the filter, and how many were returned.
A complete example
Find rooms with a capacity of at least 30, keep only their name and capacity, largest first, and take the top 20:
curl -X POST "https://your-school.omniscol.com/api/search/query" \
-H "Authorization: Bearer $OMNISCOL_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"call": "os_dashboard_classrooms_get",
"where": { "capacity": { "$gte": 30 } },
"project": ["name", "capacity"],
"sort": { "capacity": "desc" },
"limit": 20
}'
call is the internal name of the read endpoint to run (as shown on the
/developers page), params carries that endpoint's own parameters,
and extract_path optionally points at the array to filter inside the
result — omitted here, it is auto-detected.
Finding an available room or teacher
The single most common integration — feeding an intranet, a booking tool or an ETL — is "who or what is free at this time?". The availability endpoints answer it directly: they return, per entity, only the free timeslots over the dates you ask for, already accounting for lessons, absences and mandatory wishes.
Availability comes in two shapes:
- Scoped —
GET /api/schedules/availability/{datesrange}/{entity}(optionally/{entityId}) for one entity type —teachers,classrooms,groups,resources… - Explicit filter —
GET /api/schedules/availability/{datesrange}with afilter, where you narrow the set with the same$whereseen above.
{datesrange} uses YYYYMMDD, and comma-separated segments request
sparse dates — exactly right for "two given Mondays":
20261005,20261012. Each returned slot carries day, start, end
and time (minutes), so "at least 3 hours" is a time >= 180 test on
your side.
A teacher free on a precise slot
"Which teachers are free on Monday 5 October?" — one scoped call:
curl -G "https://your-school.omniscol.com/api/schedules/availability/20261005/teachers" \
-H "Authorization: Bearer $OMNISCOL_TOKEN" \
--data-urlencode "with_entities=true"
Free slots come back grouped by kind, then by teacher — for example
{ "availability": { "teachers": { "t.dupont": [ { "day": "2026-10-05", "start": "14:00", "end": "17:00", "time": 180 } ] } } } —
and your tool keeps whoever covers the slot you need.
Rooms of a given size, free on two Mondays
Combine an entity filter with availability in a single call, using a
useful subset of the syntax — just $where on capacity:
curl -G "https://your-school.omniscol.com/api/schedules/availability/20261005,20261012" \
-H "Authorization: Bearer $OMNISCOL_TOKEN" \
--data-urlencode 'filter={"classrooms":[{"$where":{"capacity":{"$gte":30}}}]}' \
--data-urlencode "with_entities=true"
Omniscol returns the free slots, on both Mondays, of every room seating
at least 30. Your ETL then keeps the rooms with a 3-hour window
(time >= 180) on each date — the multi-day rule stays on your
side, which keeps it explicit and auditable.
The filter accepts, per entity type, a plain list of IDs
({"classrooms":["A101","B204"]}), a wildcard ({"teachers":"*"}), a
simple field match ({"teachers":[{"email":"…"}]}) or the structured
$where shown here.
Choosing the right surface
- "Where does this word appear?" →
POST /api/search. - "Which entity is this name?" →
POST /api/search/entity. - "Give me the rooms over 30 seats, sorted, first page" →
POST /api/search/query. - "Who or what is free on this slot?" →
GET /api/schedules/availability/….
For an AI agent
These surfaces exist largely for AI agents. Free-text and entity
resolution turn a user's phrasing ("teacher Jean Dupont", "class 6A")
into precise identifiers; the query orchestrator then answers a filtered
question in a single call and returns only the fields asked for — instead
of several tool calls and an oversized payload. When you connect an agent
through MCP — connect an external AI agent, these tools are part of what it can use.
Wiring it into an intranet, an ETL or a partner tool
The same read surfaces are what a third-party tool consumes day to day. Common shapes:
- A pull into an intranet or dashboard — your page calls the read endpoints (availability, the lessons endpoint, the dashboards) with a scoped API token and renders the result. Nothing to install on the Omniscol side.
- A nightly ETL — a scheduled job pulls what it needs (lessons over a
date window, teacher hours, room occupancy) and loads it into your
information system.
search/querykeeps each pull filtered, projected and paginated, so the payload stays small. - A push from your system — the reverse direction, to keep Omniscol
in step with your source of truth: a nightly job can update classes and
teachers (
POST /api/external/classes,POST /api/external/teachers) or load a custom-subjects catalog (POST /api/admin/subjects/custom) from your database. - A packaged SIS / ERP — for Aurion, Auriga and the like, the dedicated connector is the right tool — see Synchronization with external systems.
- Event-driven — to be notified when something changes instead of polling, register a hook — see API tweaks.
Keep each integration scoped: a token limited to the endpoints it actually needs, rotated periodically, and read-only wherever it only reads. See Omniscol API.