Advanced queries — filter, project and paginate the API

Premium

Advanced queries: the Omniscol API offers three search surfaces — global free-text search, AI-oriented entity resolution, and a query orchestrator with Mango / MongoDB-style filtering (where, projection, sorting, pagination) that runs on top of any read endpoint. Available on accounts that offer the API integration.

Beyond 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, asc or desc. The pseudo-field _count.<field> sorts by the length of an array field.
  • limit and offset — 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:

  • ScopedGET /api/schedules/availability/{datesrange}/{entity} (optionally /{entityId}) for one entity type — teachers, classrooms, groups, resources
  • Explicit filterGET /api/schedules/availability/{datesrange} with a filter, where you narrow the set with the same $where seen 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/query keeps 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.

See also