Operational data

Figures that live beside the ledger: headcount, volume, revenue per seat. Sent as operational data and read back dataset by dataset, they feed the dashboard and the report blocks that read a non-financial number.

Writing operational data

The endpoints

MethodPathWhat it does
POST/api/v1/organisations/{organisation}/operation-data Writes the figures
POST/api/v1/organisations/{organisation}/operation-data/validate The same checks; nothing is written

Needs a bearer token, a credential issued for that company, and the credential's operation_data.write scope.

The body

{
  "declarations": {
    "source_reference": "hr-export",
    "period": "2026-09",
    "value_basis": "company_base",
    "rate_direction": "document_to_base",
    "base_currency": "SGD",
    "mode": "replace_period"
  },
  "records": [
    { "period": "2026-09", "dimension_1": "Singapore", "dimension_2": "Operations", "value": 128 },
    { "period": "2026-09", "dimension_1": "Kuala Lumpur", "dimension_2": "Operations", "value": 76 },
    { "period": "2026-09", "account_code": "4000", "dimension_1": "Singapore", "value": 12500.00 }
  ]
}

Declarations

DeclarationRequiredValue
source_referenceyesYour own id for the feed, 1–64 characters.
periodyesThe month, YYYY-MM. Each record states its own period as well, so one payload may span months.
value_basisyesThe envelope asks for it on every kind but accounts; state the company's own.
rate_directionyesAs for any kind that is not accounts.
base_currencyyesThe company's reporting currency.
scenarionoActual (default), Budget or Forecast; a record may override it.
modenoreplace_period (default), replace_all or merge.
webhook_urlnoCalled once when the request finishes or fails.

The fields

FieldTypeRequiredWhat it means
perioddateyesThe month the figure belongs to, as YYYY-MM. Part of the record's identity.
scenariostringnoThe request's scenario when absent. Part of the identity.
dimension_1, dimension_2, dimension_3string noWhat the figure is broken down by — entity, department, channel. Part of the identity.
account_codestringnoThe account the figure belongs to, when the dataset is account-based. Part of the identity.
valuenumberyesThe figure.

Identity: period, scenario, the three dimensions and the account together. Two records that agree on all of them are the same figure, and stating it twice in one payload is refused with duplicate_record_identity.

What it does

What it answers

{
  "id": 97, "kind": "operation_data", "source_reference": "hr-export",
  "period": "2026-09", "status": "written", "records_received": 3,
  "counts": { "created": 3, "updated": 0, "unchanged": 0, "rejected": 0 },
  "recalculation": null,
  "written_at": "2026-10-23T06:44:31+00:00",
  "links": { "self": "…/requests/97", "results": "…/requests/97/results" }
}

Refusals

CodeWhen
required_field_missingA record states no period or no value
invalid_typevalue is not a number
duplicate_record_identityTwo records state the same period, scenario, dimensions and account
unknown_fieldA field outside the six above was sent

Reading operational data

The figures that live beside the ledger - headcount, volume, revenue per seat - stored in datasets and read by the dashboard and the report blocks.

The endpoints

MethodPathAnswers
GET/api/v1/organisations/{organisation}/operation-dataThe datasets the company holds
GET…/operation-data/{dataset}One dataset's figures for a month

Both need a bearer token, a credential issued for that company, and the operation_data.read scope.

The datasets

GET …/operation-data

{
  "data": [
            { "id": 23, "name": "Sales by Customer and Product", "description": null,
              "row_count": 978, "scenario": "Actual", "scenario_mode": "column",
              "translation_mode": "none", "scenarios": ["Actual", "Forecast", "Budget"],
              "period_range": { "from": "2024-10", "to": "2026-09" },
              "dimensions": ["Customer", "Product", null] }
          ],
          "page": 1, "per_page": 50, "total": 1, "has_more": false
        }
FieldWhat it says
row_countHow many rows the dataset holds.
dimensionsWhat each of the three dimension columns means in this dataset, in order, so a caller can label a figure. null where the dataset does not name one.
scenario, scenario_modeThe scenario the dataset keeps and how it keeps it: dataset when the whole dataset is one scenario, column when each row states its own.
scenariosWhich scenarios this dataset can be asked for - the one it holds, or whichever of the three its uploads stored.
translation_modeWhether its values are converted to another currency, and on what basis.
period_rangeIts first and last month, so a caller knows what to ask for before asking.

A dataset is listed under the name it is stored with, so a feed written through this API appears as API: <source reference>.

One dataset

ParameterWhat it does
periodThe month, YYYY-MM. Required.
scenarioActual, Budget or Forecast.
dimensionOne value of the first dimension.
GET …/operation-data/23?period=2026-09

{
  "dataset_name": "Sales by Customer and Product", "period": "2026-09", "scenario": "Actual",
  "rows": [
    { "dimension": "Acme Manufacturing", "dimension_2": "Enterprise Licence", "dimension_3": null,
      "account": "SA-4000 - Sales Revenue", "value": 6279.61 }
  ]
}

A row is one figure: the three dimension values, the account it belongs to when the dataset is account-based, and the value. A dataset the company does not hold answers 404.