Skip to content

Run query

Ask one DataSet a question

POST/v1/signals/{signal_id}/datasources/{datasource_id}/datasets/{dataset_id}/query

Metrics and dimensions are the ids published by this DataSet's self-description. The Signal's entitlements are applied before the query runs, so the answer never covers data outside them.

Authenticate with an API key in X-Api-Key, or a bearer token in Authorization: Bearer <token>.

Parameters#

Path parameters#

  • signal_idstring · required

  • datasource_idstring · required

  • dataset_idstring · required

Request body#

application/json, required.

A question asked of one DataSet.

  • metricsarray of string · required · at least 1 item · at most 25 items

  • periodobject

    The time window. A dimension, but with first-class syntax.

    rolling is the moving-average window in periods. It is part of the question, not a display setting: a smoothed value and an unsmoothed one are different numbers, and a base read beside a smoothed value covers the same window.

    Show 5 fields
    • granularitystring

      Omit for the Signal's standard unit where the DataSet has it, else the data project's own; the answer's meta.period says which was used.

      One of month, quarter, halfyear, year.

    • lastinteger · ≥ 1 · ≤ 120 · default 1

      How many periods, counting back from ending. Above 1, a row that stands for one period of the window (a moving average is a series, one row per period) carries that period as a dimension, and the answer declares its column, even when group_by names no period; a window pooled into one figure carries none. Group by the period for one row per period every time. A driver's position has one place rather than one per period: it is answered for the last period only (as last: 1), and meta.warnings says so.

    • endingstring · nullable

      Last period to include, named by any day in it: a period id as the API writes one (2026-09, 2026-Q3, 2026-H2, 2026) or a date. Omit for the latest available.

    • rollinginteger · ≥ 1 · ≤ 12

      Moving-average window in periods (1 = none); the windows allowed per unit are in discovery. Omit for the portal's preset for the unit (discovery period.defaults_by_granularity).

    • complete_onlyboolean

      Exclude a trailing period that has not finished; an open question then ends at the last finished period, as the portal does. Omit for the portal's preset for the unit.

  • dimensionsobject

    One vocabulary, two uses.

    group_by and filters name the same dimensions — the ids discovery published for this DataSet. A dimension that is not filterable cannot be filtered on, and one that is not groupable cannot be grouped by; both are stated in discovery, and a request that does either is refused.

    Show 2 fields
    • group_byarray of string

    • filtersmap of array of string or integer or boolean

      Dimension id → the member ids to keep, as the values endpoint lists them: integers for brands and survey answers (entity, gender, age_group: 1, not "1"; a whole number written as text is read as the integer), text for dimensions whose ids are text (channel_type, provider). Any other value on an integer dimension is refused with a 422.

  • entitiesarray of integer or string · nullable

    The entity ids the answer covers: integers, as discovery lists them (34, not "34"). Rank and reference values are computed over exactly these entities, as in the portal; omit for every entity the Signal may read on this DataSet.

  • focusarray of integer or string · nullable

    The brand or brands the question is about: integer ids, as entities. Each is added to the brands the answer covers, whether the question names them (entities or an entity filter) or leaves them to the Signal's default competitors, so a brand outside a top-N is still answered. Without it, an open question gets the Signal's standard brand added instead (the DataSet's defaults.own_brands). Narrowed by the Signal's entitlements as entities is. Applies to metrics broken out per brand.

  • optionsobject

    Show 2 fields
    • includearray of string

      Context values to compute alongside each value.

    • limitinteger · ≥ 1 · ≤ 50000 · default 5000

      Maximum rows. Exceeding it is an error, never a silent truncation. The caller's plan caps it (5 000 rows on an MCP seat, a trial or a sandbox; 50 000 on the API packages).

Example request#

Shell
curl -X POST "https://api.odysseysignal.app/v1/signals/{signal_id}/datasources/{datasource_id}/datasets/{dataset_id}/query" \
  -H "X-Api-Key: $ODYSSEY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "metrics": [
      "string"
    ]
  }'

Response 200#

application/json.

  • query_idstring · required

    Deterministic id for this question. The same question yields the same id, so support can compare two answers to it.

  • cacheobject · required

    Show 2 fields
    • hitboolean · default false

    • age_sinteger · nullable

  • columnsarray of objects · required

    Show 7 fields
    • namestring · required

    • rolestring · required

      One of dimension, metric.

    • typestring · required

    • unitstring · nullable

    • entityboolean · nullable

    • rangemap of number · nullable

    • referenceobject · nullable

      The unit of a metric's context.reference when it is its own figure.

      Show 2 fields
      • unitstring · required

      • rangemap of number · nullable

  • rowsarray of objects · required

    Show 7 fields
    • dimensionsmap of object · required

      Show 6 fields
      • idstring or integer · required

      • labelstring · required

      • groupstring · nullable

      • typestring · nullable

        What the member is, where the source says: a brand member carries the study's entity type. ghost marks a ghost brand: a made-up brand per demand space that a Signal with ghost brands switched on gets as rows of its own on an aggregated brand position: a reference point, never a brand.

      • descriptionstring · nullable

      • demand_spaceobject · nullable

        The demand space an attribute belongs to, as the survey defines it.

        Show 2 fields
        • idinteger · required

        • labelstring · required

    • metricstring · required

    • valuenumber or object · required · nullable

      Show 2 fields
      • xnumber · required

      • ynumber · required

    • baseinteger · required · nullable

    • qualityobject · required

      Metadata about the value — how much to trust it.

      Show 3 fields
      • base_warningstring · required

        One of ok, caution, low.

      • suppressedboolean · default false

      • smoothing_completeboolean · default true

    • contextobject

      Metadata around the value — what to compare it with.

      Show 4 fields
      • referencenumber · nullable

      • rankinteger · nullable

      • moenumber · nullable

      • polarobject · nullable

        The same point in polar form, as the map draws it.

        Derived from x/y, so it is context rather than a measurement: r is the distance from the centre, theta the angle from the x-axis counter-clockwise and phi the angle from the top clockwise — the one the demand spaces are cut by — all in radians.

        radius_true and outside_map come only from a method that keeps the map's edge as a boundary rather than a position (position2): a brand beyond the edge is drawn on it, r is then the edge, and radius_true how far out it really is. Absent, not null, otherwise.

        Show 5 fields
        • rnumber · nullable

        • thetanumber · nullable

        • phinumber · nullable

        • radius_truenumber · nullable

        • outside_mapboolean · nullable

    • fieldsmap of number · nullable

  • metaobject · required

    Show 6 fields
    • figures_rulestring

      How the figures may be used: as given, never as the input to a new one. The same text on every answer.

      Default: Use only the figures in this answer, exactly as given, each with its label, metric, market and period. Never compute a new figure from them: no ratio, no share of a share (such as consideration among those aware), no conversion rate, no difference or change between two figures (give both and say which is higher), no sum, no average, no index. Never estimate, round differently or fill a gap: a figure that is not in an answer is not available, so say so. Every claim, explanation and conclusion must rest on the answers; do not invent reasons the data does not give. Before presenting, check every figure again against the answer it came from and correct or drop any that does not match.

    • warningsarray of string

    • row_countinteger · default 0

    • periodobject · nullable

      The window the answer covers, every field resolved.

      Echoed because a question may leave any of it open and the defaults depend on the Signal and the DataSet, so a client presenting the figures does not have to work them out again.

      Show 7 fields
      • granularitystring · required

        One of month, quarter, halfyear, year.

      • lastinteger · required

      • endingstring · required · nullable

        The period counted back from, as a period id at granularity: the one asked for, or the latest with data.

      • rollinginteger · required

        Moving-average window in periods; 1 means no smoothing.

      • complete_onlyboolean · required

        False when a last period that has not finished is included.

      • pooledboolean · default false

        Present, and true, only when the window spans several periods and each figure covers all of it as one span (the portal's "whole period pooled"), so no row names a period: unsmoothed, and not broken down by period. Group by period for a figure per period.

      • last_completeboolean · nullable

        Whether the last period the answer holds (ending) had finished by the latest data the Signal may read: false means its figures cover only the months so far. Left out when the waves are not dated.

    • applied_filtersarray of objects

      Every filter the answer was computed with, its members labelled; brands are the dimension entity.

      Show 4 fields
      • dimensionstring · required

      • labelstring · required

      • originstring · required

        request when the question named these members; signal_default when it left the filter open and the Signal's default filled it in (its standard market, its default competitors: see the DataSet's defaults); default when it left the filter open and the answer covers every member available to it.

        One of request, signal_default, default.

      • membersarray of objects · required

        Show 4 fields
        • idstring or integer or boolean · required

        • labelstring · required · nullable

          Null when this DataSet has no such member; the answer then carries a warning saying so.

        • rolestring · nullable

          On a brand: focus when the question named it in focus, standard_brand when it is the Signal's standard brand, added because the question named no focus. Absent otherwise.

          One of focus, standard_brand.

        • has_rowsboolean · default true

          Present, and false, only when the rows break the answer down by this dimension and none of them is this member: the answer has no data for it, and a warning names it.

    • environmentstring · nullable

      The data environment the answer was read in, prod or test: the one Odyssey set on the Signal, or the one an Odyssey person picked for this call.

Errors#

Errors are application/problem+json (RFC 9457): type, title, status, detail and, for some, more fields that say how to fix the call. The type is https://api.odysseysignal.app/problems/<code>.

StatusCodeWhen
400invalid-requestThe request is not valid for this DataSet; detail says why.
401unauthorizedNo credential, or one that is not accepted.
403forbiddenThe credential is valid but does not cover what was asked.
404not-foundNothing there, or nothing this credential may read.
422validation-failedThe request does not match the contract; errors lists each field.
429rate_limitedToo many requests, or the monthly quota is used up.
503unavailableA service behind the API did not answer; try again.