Skip to content

Metrics ​

2 reads, no writes, on train 2026-11. Scopes: metrics:read.

OperationMethodScopePath
The metric dictionaryGETmetrics:read/api/v1/metrics
Compile one query from the dictionary and answer with its rowsPOSTmetrics:read/api/v1/metrics/query

The metric dictionary ​

GET /api/v1/metrics

Scopes: metrics:read

Every metric and dimension the platform defines, each with one sentence saying what it is, how it rolls up, the grain it is held at, the record it is read from, and the day it entered the dictionary.

OptionalInWhat it is
Tightly-VersionheaderThe date train to answer on.
bash
curl "https://api.app.tightly.io/api/v1/metrics" \
  -H "Authorization: Bearer $TIGHTLY_API_KEY"

What it answers

json
{
  "data": {
    "domains": [
      {
        "data_source": "Sale orders",
        "domain": "sales",
        "grain": "One sale order line: a variant sold on one order.",
        "grains": [
          "daily",
          "monthly",
          "weekly"
        ],
        "label": "Sales",
        "supports_time_range": true
      }
    ],
    "metrics": [
      {
        "data_source": [
          "Sale orders",
          "Sale orders against the merchandise financial plan"
        ],
        "definition": "Sales after discounts and returns, before tax.",
        "domains": [
          {
            "data_source": "Sale orders",
            "domain": "sales",
            "grain": "One sale order line: a variant sold on one order.",
            "label": "Sales",
            "served": true,
            "unsupported_reason": null
          },
          {
            "data_source": "Sale orders against the merchandise financial plan",
            "domain": "sales_plan",
            "grain": "One month, category and sales channel, carrying the actual and the plan together.",
            "label": "Sales vs plan",
            "served": true,
            "unsupported_reason": null
          }
          …
        ]
      }
    ]
  }
}

What it refuses

  • 401 key_invalid: "The API key is not valid." No usable key: malformed, unknown, revoked, expired or stopped. One refusal covers all five, telling a caller which is which maps the surface for them. A request with no Authorization header at all is refused 400 before any key is looked for.
  • 403 scope_missing: "This key cannot read Metrics." The key may not reach this operation. scope_missing when the key does not hold Metrics; organization_mismatch when the path names an organisation that is not the key's; ip_not_allowed when the caller's address is outside the key's allowlist.
  • 429

Try it in the reference

Compile one query from the dictionary and answer with its rows ​

POST /api/v1/metrics/query

Scopes: metrics:read

Hand this the query the dictionary describes and it answers with rows, the columns, the formats each figure prints in, the window it actually ran over and the query itself, echoed back.

OptionalInWhat it is
Tightly-VersionheaderThe date train to answer on.
Idempotency-KeyheaderA string of your own, up to 255 characters, that makes this write safe to retry.
bash
curl -X POST "https://api.app.tightly.io/api/v1/metrics/query" \
  -H "Authorization: Bearer $TIGHTLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d @body.json

What to send, as body.json

json
{
  "query": {
    "dimensions": [
      "sales_channel"
    ],
    "domain": "sales",
    "grain": "week",
    "measures": [
      "net_sales"
    ],
    "time_range": {
      "amount": 12,
      "kind": "relative",
      "unit": "week"
    }
  }
}

What it answers

json
{
  "data": {
    "columns": [
      "week",
      "sales_channel",
      "net_sales"
    ],
    "explanation": "Net sales by sales channel, by week, over the last twelve weeks.",
    "formats": {
      "net_sales": "currency"
    },
    "query": {
      "dimensions": [
        "sales_channel"
      ],
      "domain": "sales",
      "grain": "week",
      "measures": [
        "net_sales"
      ],
      "time_range": {
        "amount": 12,
        "kind": "relative",
        "unit": "week"
      }
    },
    "resolved_time_range": {
      "end": "2026-09-05",
      "start": "2026-06-14"
    },
    "row_count": 2,
    "rows": [
      {
        "net_sales": 842100,
        "sales_channel": "Online",
        "week": "2026-08-30"
      },
      {
        "net_sales": 342100,
        "sales_channel": "Wholesale"
        …
      }
    ]
  }
}

What it refuses

  • 400 The query is the caller's to fix. field names the control, key the term that was wrong and allowed what may go there.
  • 401 key_invalid: "The API key is not valid." No usable key: malformed, unknown, revoked, expired or stopped. One refusal covers all five, telling a caller which is which maps the surface for them. A request with no Authorization header at all is refused 400 before any key is looked for.
  • 403 scope_missing: "This key cannot read Metrics." The key may not reach this operation. scope_missing when the key does not hold Metrics; organization_mismatch when the path names an organisation that is not the key's; ip_not_allowed when the caller's address is outside the key's allowlist.
  • 429

Try it in the reference

Tightly API, version 2026-11.