Metric Export API
The Metric Export API delivers any metric of your plants as a time series, as CSV or JSON, with one GET request. It reads the same metric collection as the reports, including the metrics your organization defined itself.
Every link the Data Export page shows is a call of this API, so the easiest way to a working request is to build it there and copy it.
Open in Mirox
Data Export ▸ Metrics for a free selection, Data Export ▸ API builder for a template. Both show the link of what you selected.
The export links of the previous export keep working unchanged. They are described in the Legacy Export API; how to move from one to the other is in the migration guide.
Routes
All paths follow https://service.mirox.io/api.
| Route | Answer | Purpose |
|---|---|---|
GET /v1/export/series | CSV, or JSON with format=json | Export metrics as a time series |
GET /v1/export/series/estimate | JSON | Size and duration of an export, without reading data |
GET /v1/export/series/catalog | JSON, or a CSV glossary with format=csv | The metrics you can export |
GET /v1/export/series/lanes | JSON | The components of one plant |
GET /v1/export/series/template/{template_uid} | CSV, or JSON with format=json | Export a template |
POST /v1/export/template/{template_uid}/convert | JSON | Convert a legacy template |
Authentication
Send an API token of the group Metric Export in the Authorization header:
Authorization: Bearer YOUR_API_TOKEN
The token reads every export route on this page and the legacy routes. It cannot create, change or delete anything. In a browser where you are logged in to Mirox, the links work without a token.
You only receive data of the plants whose measurements you may read. The metrics of your organization are exported by every organization role except External. See Who can export what.
Metrics Are Selected by Id; a Query Is Scoped to the Plant
An export names metrics by their id. Mirox resolves each id to its own query, scoped to the plant. The metrics of your organization are validated entries of the collection that are scoped to the plant in the same way. The only query text a caller can send is a MetricsQL expression in expr: it is run on the plants of the request only, with the plant added to every selector, and it is refused when it names a plant, a park or an organization itself.
Exporting a Time Series
GET /v1/export/series
Grid feed-in of one plant over the previous month, per day:
curl --compressed "https://service.mirox.io/api/v1/export/series?park=ABC123DEF456&metrics=plant.grid_feedin&window=previous_month&step=day" \
-H "Authorization: Bearer YOUR_API_TOKEN" -o feedin.csv
Date;Grid feed-in (kWh)
2026-08-01;5321,4
2026-08-02;4980,2
...
Parameters
| Parameter | Values | Default | Meaning |
|---|---|---|---|
metrics | 1 to 20 metric ids, comma-separated | required unless expr is given | The columns, in this order. See Metrics and values. |
expr | a MetricsQL expression, repeatable up to 5 times | — | Raw queries of the time-series store, one set of columns each, after the metrics. See Raw MetricsQL queries. |
park | plant UIDs, comma-separated | — | The plants. park or portfolio is required. |
portfolio | portfolio UIDs, comma-separated | — | All plants of these portfolios, in addition to park. At most 50 plants in total. |
start, end | date or date with time | — | A free time range. See Time range. |
year, quarter, month, week, day | numbers | — | A calendar range. |
window | preset | previous_month | A named range. |
step | auto, 1min, 5min, 15min, 1h, day, week, month, quarter, year | auto | The length of one row. See Steps. |
mismatch | refuse, sparse | refuse | What happens to a metric that does not serve the step: refuse the request, or export it at its own step. See Metrics with different steps. |
values | auto, delta, cumulative, native | auto | The value mode of all metrics. |
tz | local, utc | local | The calendar of the rows. See Time grid. |
multi_park_agg | merge, split | merge | Several plants combined, or one column per plant. See Several plants. |
components | up to 100 component references, comma-separated | all | Restricts component metrics to these components. See Components. |
lane_limit | 1 to 100 | 50 | Components per metric and page. |
lane_page | 1 and up | 1 | The page of components. |
format | csv, json | csv | The format of the answer. |
language | en, de, es, fr, it, pt | en | The language of the column names. |
separator_csv | , ; tab | | ; | The column separator. |
separator_decimal | . , | , | The decimal separator. It must differ from separator_csv. |
datetime_format | strftime pattern, up to 64 characters | per step | The format of the time column. |
header | name, id | name | Column headers as names or as ids. See CSV answer. |
empty | blank, zero | blank | A missing value as an empty cell or as 0. |
offset_column | true, false | true | The column UTC offset. It appears only at steps shorter than a day in plant local time. |
precision | display, full | display | Values rounded to the digits of the metric, or unrounded. |
lane_limit and lane_page outside their bounds are set to the nearest bound. A parameter the route does not know is ignored.
Metrics and Values
A metric id has the form <prefix>.<name>, for example plant.grid_feedin, inverter.ac_power or sensor.irradiance. A metric of your organization is organization.<id of the metric>. The catalog lists all of them.
Each metric has a quantity, which decides the value modes it offers:
values | A row shows | Applies to |
|---|---|---|
delta | the amount within the interval | energy only |
cumulative | the running total since the start of the range | energy and other counted quantities |
native | the value as the metric delivers it | every metric |
auto | delta for energy, native for everything else |
A suffix sets the mode of one metric and wins over values:
metrics=plant.grid_feedin:cumulative,plant.grid_power
A mode that does not apply to a metric is never an error. The metric is exported as native, and the note value_mode_ignored says so. delta is never applied to a power.
The same metric in two modes gives two columns. The same metric in the same mode twice gives one.
Energy Per Interval Below 15 Minutes
A meter counts energy in whole steps. At 1min or 5min, an energy in mode delta therefore jumps between zero and one step. The export delivers it and adds the note energy_delta_fine_step, which names the matching power metric where the collection has one. For a curve use the power metric; for energy use 15min or longer.
Time Range
Give the range in one of three ways. Two ways in one request answer 400 window_conflict.
| Way | Parameters | Example |
|---|---|---|
| Free range | start, end | start=2026-07-01&end=2026-07-31 |
| Calendar | year with quarter, month, week or day | year=2026&quarter=2 |
| Preset | window | window=previous_week |
Free range. start and end are a date (2026-07-01) or a date with time (2026-07-01T06:00, 2026-07-01T06:00:00Z, 2026-07-01T06:00:00+02:00). A value without a time zone is read in the time zone of the rows. An end that is a date includes that day; an end with a time is the moment the range ends. Without end, the range ends now. end alone, without start, is refused.
Calendar. year from 2020 to 2100, quarter 1 to 4, month 1 to 12, week 1 to 53 (ISO week), day 1 to 31. day needs month. Without year, the current year is meant. day wins over week, week over month, month over quarter.
Presets. today, yesterday, last_7_days, last_30_days, this_week, previous_week, this_month, previous_month, this_quarter, previous_quarter, this_year, previous_year. The this_ presets run up to now; last_7_days and last_30_days roll up to now at steps below a day (the same clock time 7 or 30 days back); at day and coarser they are the last 7 or 30 local days including today. At day and coarser every window is widened to whole days (weeks, months …) in the plant's time zone, and the response echoes the effective window.
A range starts in 2020 at the earliest and spans at most 1827 days (five years). A range that reaches into the future ends now, with the note end_clamped.
Steps
step=auto chooses a step that every requested metric serves and that fits the limits: 15min for up to two days, 1h for up to 62 days, day for up to three years, month beyond. If that step does not fit, the next coarser one is tried, then the finer ones. The note step_auto and the header X-Mirox-Step name the step that was chosen.
Each metric offers its own steps. The catalog lists them as export_steps:
| Kind of metric | Steps |
|---|---|
| Energy from a meter that counts every minute | 1min to year |
| Energy counted less often — wind turbines, settled curtailment | 15min to year |
| Power (W, var, VA, W/m²), voltage, current, frequency | 1min, 5min, 15min |
| Temperature, state of charge and other measured levels | from the measuring interval to year |
| Operating states and status codes | 15min |
| Performance ratio | day, week, month, quarter, year |
| Availability | 15min, 1h, day, week, month, quarter, year |
| Metrics of your organization | from their finest resolution to year, never finer than 15min |
Power is offered at 15 minutes or finer only. A daily or monthly power is an average that hides what happened; the energy metric gives the figure that is meant.
A step is never changed silently. With mismatch=refuse, the default, a step that one of the metrics does not serve answers 400 step_not_served with the steps of every metric, and with step=auto, metrics that share no step answer 400 no_common_step. With mismatch=sparse, such a request is delivered instead — see Metrics with different steps.
Steps of a day or longer cover whole intervals. A range that starts or ends inside one is widened outward, with the note window_aligned. Weeks start on Monday.
Metrics With Different Steps
mismatch=sparse delivers a request whose metrics do not all serve the step, as long as each of them serves some step. The grid of the file is the requested step; with step=auto it is the step that most metrics serve as is, chosen by the range and the limits as usual. Column positions and the shape of the CSV and JSON answer do not change.
| The metric serves | What the export does | Note |
|---|---|---|
| only finer steps | Reads it at the coarsest of them and folds it up to the grid by the rule of its quantity: an energy is added, a reading averaged, a ratio recomputed from its halves, a state keeps its latest code. | step_folded with the read step |
| only coarser steps | Reads it at the finest of them and writes each value on the row its own interval starts on — a day's figure on the row of its local midnight, a month's on the row of its first day. The rows between stay empty. | step_sparse with that step |
| a coarser step, but none of its intervals starts on a row | The column is empty, for example a daily figure on a file that starts at 06:00. | metric_unavailable with reason off_grid |
Two cases are refused in both modes, with 400 step_not_served: a figure per month, quarter or year on a week file, because its first day is hardly ever a Monday; and a monthly figure such as the Marktwert on a quarter or year file, because a sum or a mean of months is not that figure. On a month file it is read as is, on a finer file it is sparse.
The estimate lists the same notes, counts the reads at each metric's own step, and marks a step in per_step as within budget even when not every metric serves it. The Data Export page always asks with mismatch=sparse; a template carries its own mismatch in its spec.
Time Grid
With tz=local, rows follow the local time of the plant, including daylight saving time: a day is a local day of 23, 24 or 25 hours, a month is a local month. With tz=utc, rows follow the UTC calendar.
- At steps shorter than a day in local time, the column UTC offset follows the time column (
+02:00). On the day the clocks go back, one hour appears twice; the offset tells the two apart.offset_column=falseleaves the column out. - Plants in different time zones share one time column. Such a request is answered on the UTC calendar, with the note
merged_on_utc, whether the plants are combined or split. - With
tz=utcand a step of a day or longer, a metric that exists per local day only has no UTC value. Its column stays empty, with the noteutc_calendar_unsupported.
The header X-Mirox-Grid names the calendar that was used: local:Europe/Berlin or utc.
Several Plants
With multi_park_agg=merge, every metric is one column for all plants, combined by the rule of the metric. The catalog lists the rule as merge:
merge | Combined value | Metrics |
|---|---|---|
sum | added over the plants | energy, counted quantities, power |
mean | averaged over the plants | irradiance, temperature, state of charge and other levels |
pair_ratio | recomputed from the plants' totals | performance ratio, availability and other ratios |
first | the shared value | prices, when all plants lie in one market zone |
split_only | cannot be combined | states and status codes |
A metric that cannot be combined is exported per plant, with the note merge_not_meaningful. This also holds for a ratio at a step at which its two halves are not available, and for prices of plants in different market zones.
With multi_park_agg=split, every metric is one column per plant. With a single plant, both give the same file.
Component metrics are always per plant (note components_split_by_park).
Components
A metric of a component level gives one column per component. The levels are inverter, gak (combiner box), string, turbine, sensor, meter, battery_box (container), battery_storage (rack), battery_module, battery_cell and battery_pcs (power converter).
Without components, the export carries all visible components of the plants, lane_limit per metric and page. If there are more, the note lanes_truncated names the total; request the next page with lane_page.
components restricts the export to the components you name. A reference has the form <level>:<id>, for example inverter:1043. A sensor or meter that Mirox measures but that has no entry in the plant's components has a reference of the form sensor:h3f9c2a71b04e6d5. The components route lists the references of a plant. A reference that belongs to none of the selected plants answers 400 unknown_lane.
metrics=inverter.ac_power&components=inverter:1043,inverter:1044
Raw MetricsQL Queries
expr adds a raw query in MetricsQL, the query language of the platform's time-series store, to an export — for a series the collection has no metric for. The parameter can be repeated up to five times; each expression may have up to 4 000 characters. A request may carry expr alone, or metrics and expr together; the metric columns come first.
expr=sum by (inverter_id) (powerplant_inverter_power_ac)&park=ABC123DEF456&window=yesterday&step=15min
An expression is evaluated per plant, as a dashboard evaluates it: on the plant's own data, at the requested step, as raw samples — every step is allowed, values and the folding rules of the metrics do not apply. Mirox adds the plant to every selector of the expression; an expression that names a park, organization or plant label itself is refused with 400 expr_forbidden_label.
| Case | header=name | header=id |
|---|---|---|
| One series per plant | MetricsQL sum by (inverter_id) (powerplant_inverter_power_ac) | expr1 |
| Several series on any plant | the heading followed by each series' own name{labels} | expr1{inverter_id="INV1"} |
| Several plants | the plant name in front, as for any column | ABC123DEF456/expr1 |
When an expression answers several series on any of its plants, every plant's columns of that expression carry the series labels, so a file has one naming per expression. A heading longer than 1 000 characters is cut with … inside the expression, never in the series text. In the JSON answer, columns[].key is the header=id text and columns[].metric is the expression's id, expr.e1, expr.e2, …, which the notes and refusals use. A plant on which the expression answers nothing keeps one empty column, with the note expr_no_series; with several plants, every plant gets its own columns, with the note expr_split_by_park.
An expression may answer at most 500 series on one plant (400 expr_too_many_series); aggregate it, with sum by (…) for example. The series count against the same 400 columns and 1 800 000 values as every export: the first read of each expression on each plant is a short probe, the widths are summed over the whole request, and a request that outgrows the limits is refused with 400 over_budget and params.series before any full read of any expression. An expression that does not parse, is empty, is too long, or that the store refuses answers 400 expr_invalid with the reason.
The estimate counts an expression as one column per plant, because its series are only known once it is read. Expressions are not stored in templates.
CSV Answer
The answer is UTF-8, with the file name series_export_<first day>_<last day>_<step>.csv. An answer larger than about 1 MB is compressed when the request carries Accept-Encoding: gzip (curl: --compressed).
The columns are, in this order: the time, the UTC offset where it applies, then the metrics in the order of metrics.
| Case | header=name | header=id |
|---|---|---|
| Time | Date | timestamp |
| UTC offset | UTC offset | utc_offset |
| One plant, or plants combined | Grid feed-in (kWh) | plant.grid_feedin |
| Plants split | Sunnyside - Grid feed-in (kWh) | ABC123DEF456/plant.grid_feedin |
| Component | WR 01.01 - AC power per inverter (W) | ABC123DEF456/inverter:1043/inverter.ac_power |
| Component, several plants | Sunnyside - WR 01.01 - AC power per inverter (W) | ABC123DEF456/inverter:1043/inverter.ac_power |
| Metric with variants, such as three phases | the name followed by the variant | the id followed by #<variant> |
| One metric in two value modes | the same name twice | plant.grid_feedin:delta, plant.grid_feedin:cumulative |
| Raw MetricsQL query | MetricsQL <expression>, followed by the series labels where there are several | expr1, expr1{inverter_id="INV1"} — see Raw MetricsQL queries |
Use header=id in Scripts and Workbooks
Names are made for people: they follow language and change when a metric is renamed. Ids are stable. A script or a workbook that finds its columns by header should request header=id. In a template you can also give each column a header text of your own.
The time column is formatted per step unless datetime_format is given:
| Step | Format | Example |
|---|---|---|
1min, 5min, 15min, 1h | %Y-%m-%d %H:%M | 2026-08-01 06:15 |
day, week | %Y-%m-%d | 2026-08-01 |
month, quarter, year | %Y-%m | 2026-08 |
Every row is stamped with the start of its interval. A missing value is an empty cell, so "no data" and "zero" can be told apart; empty=zero writes 0 instead.
Four headers of the answer repeat what was resolved:
| Header | Content | Example |
|---|---|---|
X-Mirox-Step | the step | day |
X-Mirox-Grid | the calendar | local:Europe/Berlin |
X-Mirox-Window | start and end of the exported range | 2026-08-01T00:00:00+02:00/2026-09-01T00:00:00+02:00 |
X-Mirox-Notes | the notes, separated by ; | step_auto:step=day |
JSON Answer
format=json answers the same table as structured data:
| Field | Content |
|---|---|
window | start, end, grid, tz_name, step, and aligned when the range was widened |
parks | the exported plants with uid, name and timezone |
buckets | the rows: start as a time with offset, ts as Unix seconds |
columns | one entry per column: key (the header=id text), metric, name, unit, digits, quantity, values_mode, merge, park_uid, lane (ref, level, title), variant, and values in the order of buckets; a missing value is null |
notes | the notes with code, metric and params |
lanes_total | components per component metric, before paging |
lane_page, lane_limit | the page that was delivered |
totals | values, queries and duration_ms of the export |
Notes
A note tells you what Mirox did on its own. It never fails an export. Notes are part of the JSON answer and of the header X-Mirox-Notes. The header holds up to 1 KB of notes, written as code:key=value,key=value and separated by ;. If not all of them fit, the header ends with notes_omitted:count=<n>; the JSON answer holds all of them.
| Note | Meaning |
|---|---|
parks_dropped | Plants you named but cannot read were left out. uids names them. |
grant_required | A money metric stays empty for a plant on which you lack the accounting permission. |
value_mode_ignored | The requested value mode does not apply to the metric; it was exported as native. |
energy_delta_fine_step | An energy per interval at a step below 15 minutes shows meter steps. twin names the matching power metric. |
legacy_id_mapped | An id of the previous export was translated. from, to and exactness say how. |
merge_not_meaningful | The metric cannot be combined over plants and is shown per plant. |
components_split_by_park | Component metrics are shown per plant. |
merged_on_utc | The plants lie in different time zones; the rows are in UTC. |
utc_calendar_unsupported | The metric has no value on the UTC calendar; its column is empty. |
window_aligned | The range was widened to whole intervals. start and end give the result. |
end_clamped | The range reached into the future and ends now. |
step_auto | The step that auto chose. |
step_folded | With mismatch=sparse: the metric was read at a finer step and folded up to the grid. |
step_sparse | With mismatch=sparse: the metric has one value per step, on the first row of each of its intervals. |
lanes_truncated | The metric has more components than the page holds. total, page and limit say where you are. |
lanes_unpaged | Measured series without an entry in the plant's components were exported as measured. |
metric_unavailable | The metric has no values for a plant; the column is empty. reason is planned, not_applicable, no_data_source, draft, deleted, unknown_lane, off_grid or, in a template, not_permitted. |
expr_no_series | A raw query answered no series on a plant; its column is empty. |
expr_split_by_park | Raw queries are read per plant and get one set of columns per plant. |
provider_note | A remark of the metric itself, for example which source answered. |
An empty column is always kept. A metric that does not apply to one of the plants, or a money metric without the accounting permission, leaves its column in place, so the positions of the other columns never move.
Estimating Before Exporting
GET /v1/export/series/estimate
The route takes the parameters of the export, without the file format, and answers what the export would be — without reading data and without counting against the hourly allowance.
| Field | Content |
|---|---|
step, grid, window | what the request resolves to |
parks, columns, rows, values, queries | the size |
bytes_csv, seconds_estimate | approximate file size and duration |
within_budget | whether the export would be delivered |
preview_ok | whether it is small enough for the preview in the app (200 000 values) |
limits | the limits in force |
per_step | for every step: served_by_all, values, within_budget, and the reason if not |
refusals | every error the export would answer, with code, params and hint |
notes | the notes the export would carry |
A refusal never fails the estimate: it answers 200 and lists the refusal. The estimate counts, it renders nothing: the row labels and headings are the export's. A raw query counts as one column per plant, and with mismatch=sparse the notes name the folded and sparse columns.
The Metric Catalog
GET /v1/export/series/catalog
| Parameter | Values | Default | Meaning |
|---|---|---|---|
park, portfolio | UIDs | — | The plants the metrics are judged against. Without plants, the whole collection is listed. |
language | en, de, es, fr, it, pt | en | The language of names and descriptions. |
level | a level | all | One level only. |
quantity | energy, amount, rate, level, ratio, state, price | all | One quantity only. |
search | text, up to 100 characters | — | Searches name, description, unit, id and the ids of the previous export. |
include_unavailable | true, false | true | Also lists metrics that cannot be exported for the selected plants. |
page, limit | numbers, limit up to 100 | 1, 100 | Paging. |
sort | order, name, id, level, with - in front for descending | order | The order of the list. |
format | json, csv | json | csv answers the glossary. |
Each metric carries, next to its id, name, description, unit and level:
| Field | Content |
|---|---|
quantity | what the number is: energy, amount (another counted quantity), rate (power), level, ratio, state or price |
value_modes, default_value_mode | the value modes it offers, and the one auto chooses |
export_steps | the steps it offers |
native_step_seconds | how often it is measured |
merge | how several plants are combined |
twin_item_id | for an energy metric, its power metric |
lane_level | for a component metric, the level of its components |
legacy_ids | the ids of the previous export it answers for |
applies_parks | on how many of the selected plants it applies |
exportable, export_reason | whether it can be exported, and if not why: draft, planned, grant_required, not_applicable or no_source |
For up to 10 plants, each plant is checked for the equipment a metric needs. Above that, plants are judged by their type only; what a single plant lacks shows at export time as a note metric_unavailable.
Glossary. format=csv answers the whole filtered list as a file, metric_catalog_<language>.csv, with the columns id, level, name, unit, description, quantity, value modes, steps, measuring interval, combination over plants, note and previous ids. page and limit do not apply.
curl "https://service.mirox.io/api/v1/export/series/catalog?format=csv&language=en" \
-H "Authorization: Bearer YOUR_API_TOKEN" -o metric_catalog_en.csv
Available Metrics
The collection is ordered by level. The prefix of an id tells where a metric belongs.
| Level | level | Id prefix | What it holds |
|---|---|---|---|
| Plant · measured | plant | plant. | What the plant itself measures: the grid meter, the inverter sums, the site sensors, the power limits it was told to hold. |
| Plant · reference | plant_reference | plant. | What the plant should have done: irradiation in the plane of the modules, expected production, performance ratio, specific yield, losses. |
| Plant · compensation | plant_compensation | plant. | Curtailment and shutdown losses as energy and power, per recipient and method. |
| Metrics | metrics | availability., organization. | Availability figures, sun hours, and the metrics of your organization. |
| Inverter | inverter | inverter. | One column per inverter. |
| Combiner box | gak | gak. | One column per combiner box. |
| String | string | string. | One column per string. |
| Battery | battery | battery. | The storage as a whole: energy, power, state of charge, setpoints. |
| Battery container | battery_box | battery_box. | One column per container. |
| Battery rack | battery_storage | battery_storage. | One column per rack. |
| Battery module | battery_module | battery_module. | One column per module. |
| Battery cell | battery_cell | battery_cell. | One column per cell or measuring point. |
| Battery converter (PCS) | battery_pcs | battery_pcs. | One column per power converter. |
| Wind turbine | turbine | turbine. | One column per turbine. |
| Sensor | sensor | sensor. | One column per sensor: irradiance, irradiation, temperature, humidity, wind. |
| Meter | meter | meter. | One column per energy meter. |
| Infrastructure | infrastructure | infrastructure. | The data path and the site: completeness, logger health, network, alarms, control connections. |
| Weather | weather | weather. | Weather at the site, including wind and temperature at 80, 120 and 180 m. |
| Market | market | market. | Prices and market values. |
| Plant financial | financial | financial. | Money values of the plant. They need the accounting permission. |
The complete list with names, units and descriptions in your language is the catalog, the glossary file, or Explanations on the Metrics tab. The weather forecast values of the previous export are not part of the collection; see the migration guide.
Components of a Plant
GET /v1/export/series/lanes
| Parameter | Values | Default | Meaning |
|---|---|---|---|
park | one plant UID | required | The plant. |
level | a component level | required | See Components. |
metric | a metric id | — | For sensors and meters: lists the ones that delivered this metric in the last 30 days. |
search | text | — | Searches the names. |
include_hidden | true, false | false | Also lists hidden components. |
page, limit | numbers, limit up to 100 | 1, 50 | Paging. |
sort | order, name, with - in front for descending | order | order is the order of the columns in the export. |
Each entry has the reference ref for the parameter components, the name, the level, the parent (parent_ref, parent_name — the inverter of a string, for example), attributes (role of a meter, position of an irradiance sensor, vendor), hidden, and source: db for an entry of the plant's components, store for a series that is measured but has no such entry.
A plant that does not exist and a plant you cannot read both answer 404 park_not_found.
Template System
A template is a saved list of metrics with defaults for step, time range, values, time zone, combination of plants, component page size and column headers. What templates are for, and how to manage them in the app, is in the Metric Export guide.
Exporting a Template
GET /v1/export/series/template/{template_uid}
The route takes the parameters of the export except metrics, components and values, which the template fixes. Every parameter you leave out takes the template's default; every parameter you give wins over it.
curl --compressed "https://service.mirox.io/api/v1/export/series/template/CAFE1000CAFE?park=ABC123DEF456&window=previous_month&header=id" \
-H "Authorization: Bearer YOUR_API_TOKEN" -o standard.csv
- A template of another organization answers
404 template_not_found. - A legacy template answers
400 template_is_legacy;params.legacy_urlis the link that exports it. - A column whose metric is no longer available is exported empty under its header, with the note
metric_unavailable. The same holds for a metric of your organization when you export as External (reasonnot_permitted).
System Templates
| Template | UID | Step | Time range |
|---|---|---|---|
| Standard Export | CAFE1000CAFE | day | previous_month |
| Extended Export | CAFE1001CAFE | day | previous_month |
| Extended Export (inverter availability) | CAFE1002CAFE | day | previous_month |
| Energy Availability Export | CAFE1003CAFE | day | previous_month |
| Report Technical | ABCD12340002 | day | previous_month |
| Wind Turbines | CAFE1010CAFE | day | previous_month |
| Battery Storage | CAFE1020CAFE | day | previous_month |
| Irradiance Sensors | CAFE1030CAFE | 15min | yesterday |
The first five succeed CAFE0000CAFE, CAFE0001CAFE, CAFE0002CAFE, CAFE0003CAFE and ABCD12340001, which keep working on the legacy route. Their columns are listed in the migration guide. They offer the steps day, week, month, quarter and year; the first four also offer 15min and 1h.
Managing Templates
Templates are listed, read, created, changed and deleted under /v1/export/template. Reading works with a Metric Export token. Writing needs the organization role Admin, Moderator, Asset Manager (Technical) or Asset Manager (Commercial) and a login or a Full Access token.
| Request | Purpose |
|---|---|
GET /v1/export/template | List templates. view=current lists the system templates of this page and your organization's templates; view=legacy, the default, lists the stored templates as before; view=all lists both. kind=series or kind=legacy filters. |
GET /v1/export/template/{template_uid} | Read one template. |
POST /v1/export/template | Create a template with kind=series and the content in spec. Without kind, the request creates a legacy template from metric_ids, as before. |
PUT /v1/export/template/{template_uid} | Change name, description or spec. The kind cannot change. |
DELETE /v1/export/template/{template_uid} | Delete a template. System templates cannot be changed or deleted. |
The spec of a template:
| Field | Values | Default |
|---|---|---|
items | 1 to 40 entries, each with metric, optionally values and label | required |
step | a step | auto |
values | a value mode | auto |
tz | local, utc | local |
window | a preset | previous_month |
multi_park_agg | merge, split | merge |
lane_limit | 1 to 100 | 50 |
header | name, id | name |
mismatch | refuse, sparse | refuse |
label is the header text of the column with header=name. A metric may appear once, and a template holds no raw queries. When a template is saved, every metric must be exportable, and the metrics must share a step — under mismatch=sparse, each must serve some step; otherwise the answer is 422 spec_invalid and params.problems names the metric and the reason. A template runs with its own mismatch (the app shows it as Metrics of another step: Strict or Lenient); the parameter on the export link wins over it.
Converting a Legacy Template
POST /v1/export/template/{template_uid}/convert
| Field | Values | Meaning |
|---|---|---|
name | up to 100 characters | The name of the new template. Default: the name of the legacy template followed by "(new)". |
dry_run | true, false | true answers the mapping without creating anything. |
The answer lists mapped (legacy_id, metric, values, exactness: exact or approximate) and unmapped (legacy_id, reason: formula, no_equivalent, report_value or instant, and up to three suggestions), and, unless it was a dry run, the new template. A dry run answers 200, a conversion 201.
The new template exports days over the previous month. The legacy template is never changed. Two legacy columns that read the same meter become one column. 422 nothing_to_convert means that no column has a counterpart, or that the template is not a legacy template.
Limits
An export is answered within one request, so its size is bounded. Every limit is checked before data is read; a request that is too large is refused at once and tells you what would fit.
| Limit | Value |
|---|---|
| Metrics per request | 20; in a template 40 |
| Raw MetricsQL queries per request | 5, of 4 000 characters each, with at most 500 series per plant |
| Plants per request | 50 |
| Components per metric and page | 50 by default, at most 100 |
| Columns | 400 |
| Values per column | 180 000 — 125 days at 1min, 625 days at 5min, five years at 15min |
| Values in total | 1 800 000 (rows × columns) |
| Time range | 1827 days |
| Reads of the measurement store per request | 1 500 |
| Duration | 50 seconds |
| Exports per user and hour | 240 |
| Exports running at the same time | 3 per organization |
Splitting a Large Export
400 over_budget names in params what was needed and what is allowed, and in hint the way out: step, the next coarser step that fits, and max_days, the longest range that fits at the requested step. Ask the estimate first if you build requests in a script; its per_step lists the size for every step.
If neither a coarser step nor a shorter range is what you want, split the export:
| Split by | How |
|---|---|
| Time | One request per month or quarter. Use the calendar parameters (year=2026&month=7) and join the files. |
| Plant | One request per plant or portfolio. |
| Metric | Component metrics in requests of their own. One component metric on a plant with 200 inverters is 200 columns. |
| Page | lane_page=1, 2, … for the components of one metric. |
Some metrics are worked out from several sources for every day, above all plant.production_reported (Production, resolved). They need many more reads of the measurement store than a meter reading, at every step. A request or a template that carries such a metric reaches about nine plant-months at present: one plant over nine months, or nine plants over one month. A step of a week or longer widens the range to whole intervals, and the widened range counts. Split such exports by time or by plant, or export the metric in a request of its own.
429 busy and 429 rate_limited carry the header Retry-After with the seconds to wait.
Errors
An error of the routes on this page has this form:
{
"detail": {
"code": "step_not_served",
"message": "The step is not served by every requested metric.",
"params": {"step": "1h", "metrics": {"plant.grid_power": ["1min", "5min", "15min"]}},
"hint": {"offered_common": ["1min", "5min", "15min"]}
}
}
code is stable and meant for programs. message is an English text for people. params says what was wrong, hint what would work.
| Status | code | Meaning | params and hint |
|---|---|---|---|
| 400 | scope_required | Neither park nor portfolio was given. | hint.example |
| 400 | unknown_metric | A metric id does not exist. | params.ids; hint.suggestions with similar ids |
| 400 | legacy_metric_id | An id of the previous export has no counterpart in the collection. | params.id, params.legacy_url; hint.reason, hint.closest, hint.pending, hint.legacy_url |
| 400 | metric_not_exportable | The metric exists but is not a time series you can export. | params.id, params.reason: draft, planned, no_source, events or master |
| 400 | window_conflict | The range was given in more than one way. | params.families |
| 400 | window_invalid | The range is not valid. | params.reason: end_before_start, start_in_future, before_2020, too_long, day_requires_month, start_required or invalid_date |
| 400 | step_not_served | A metric does not offer the requested step. | params.metrics with the steps of every metric; hint.offered_common |
| 400 | no_common_step | The metrics share no step. | params.metrics; hint.split |
| 400 | over_budget | The export is larger than a limit. | params.values, limit, queries, query_limit, columns, column_limit, parks; with more than 50 plants params.parks and park_limit; for a raw query params.series; hint.step, hint.max_days, hint.lane_limit, hint.reduce |
| 400 | unknown_lane | A component reference belongs to none of the plants. | params.refs |
| 400 | expr_invalid | A raw query cannot be run. | params.expr, params.reason: empty, syntax (with detail), too_long, too_large, store (with the store's detail) or parser_unavailable |
| 400 | expr_forbidden_label | A raw query names a plant, park or organization itself. | params.expr, params.labels |
| 400 | expr_too_many_series | A raw query answers more than 500 series on one plant. | params.expr, params.park, params.series, params.limit; hint.reduce |
| 400 | separator_conflict | Column separator and decimal separator are the same. | — |
| 400 | invalid_datetime_format | datetime_format is not a valid pattern. | hint.example |
| 400 | template_is_legacy | The template is a legacy template. | params.legacy_url |
| 403 | no_accessible_parks | You cannot read any of the selected plants. | — |
| 403 | metric_forbidden | A metric of your organization was requested with the organization role External. | params.ids |
| 404 | template_not_found, park_not_found | The template or the plant does not exist, or you cannot read it. | — |
| 409 | name_conflict | A template with this name exists. | params.name |
| 422 | — | A parameter has a value outside its list, or metrics holds more than 20 ids. | the field and the reason |
| 422 | spec_invalid, use_spec, nothing_to_convert | A template cannot be saved or converted as sent. | params.problems |
| 429 | busy | Too many exports are running. | header Retry-After |
| 429 | rate_limited | The hourly allowance is used up. | header Retry-After |
| 502 | store_error | The measurement store answered with an error. Nothing was exported; a value is never replaced by zero. | params.metric |
| 503 | store_timeout | The measurement store did not answer in time. | hint.step with a coarser step |
401 means that the token is missing, expired or revoked.
Ids of the Previous Export
The parameter metrics also accepts the ids of the previous export, such as energy_grid_daily or raw_grid_power. An id with a counterpart is translated to its metric, in the value mode that comes closest to the previous number, and the note legacy_id_mapped says which metric answered and whether the number is the same (exact) or the same quantity read in a better way (approximate).
An id without a counterpart answers 400 legacy_metric_id. hint.reason says why, hint.closest names the nearest metric where there is one, hint.pending names the metric that is planned to carry it, and legacy_url is the link of the previous export that still delivers the id. With more plants than a link can name, legacy_url names the first plant and params.legacy_url_scope is first. A component id of a battery level has no link of the previous export; hint.legacy_route is none then. The migration guide lists every id.
Excel and Scripts
- Metric Export for Excel — recipes, and the Power Query connection with the
Authorizationheader - External Report Generator — a complete Python example
Related Features
- Metric Export — the Data Export page
- Migrating to the Metric Export — old ids, new metrics and what changes
- Legacy Export API — the previous export links
- Metrics — define metrics of your own and export them
- API Tokens — create the Metric Export token
- API Overview — the interactive reference of all routes