messpunkt.io Partner API · Changelog
Preview V1 release candidate 1.0.0-rc.3 — production live since 30 September 2026; access per customer organisation on request: kontakt@messpunkt.io

Changelog

Release history of the messpunkt.io Partner API. We follow Semantic Versioning and use the category labels from Keep a Changelog.

Documentation 2026-10-04 Release candidate

No change to the contract (still 1.0.0-rc.3). The documentation now shows only what the API does today.

Added

  • Roadmap: who owns which data once an ERP writes occupancies, the planned building blocks (event feed, occupancy writes, external_ref, webhooks) and the semantics a writing ERP can prepare for. Nothing on that page can be called today.

Changed

  • Production status. auth.messpunkt.io, api.messpunkt.io and mcp.messpunkt.io have been live since 2026-09-30 against real data. ERP clients are registered on request; API access is enabled per customer organisation. Pages, spec and llms.txt no longer say that production goes live with the first pilot partner.
  • external_ref (field and filter) and obis are described as not supported today, without a release promise. The field stays in the contract and is always null; a non-empty external_ref filter returns an empty page.
  • ERP guide: resource — an ERP client that omits it gets a token for the REST API; send it anyway. The spec no longer claims the sandbox consent screen pre-selects nothing: all Properties is pre-selected.

Removed

  • Forward-looking statements outside the roadmap: first-party SDK packages, BVED 3.10 as a second rendering, a typical integration time, and the hint to prepare for write endpoints on the error page.
Operations 2026-09-30 Release candidate

No change to the contract (still 1.0.0-rc.3). Corrected on 2026-10-04: this entry said the production REST API would go live with the first pilot partner. In fact api.messpunkt.io has been running against real data since this day as well.

Added

  • MCP server live at https://mcp.messpunkt.io/v1, together with the production authorization server https://auth.messpunkt.io. Access is enabled per customer organisation on request (kontakt@messpunkt.io). Verified end to end with Claude Code. See the MCP reference and the landlord guide (German).
  • Sandbox on rc.3. auth.sandbox.messpunkt.io and api.sandbox.messpunkt.io now serve the rc.3 contract, including resource (RFC 8707) and /oauth/revoke.
1.0.0-rc.3 2026-09-29 Release candidate

rc.3 makes the contract describe the data messpunkt.io really has, and sets the data resolution to monthly. It contains four breaking changes. rc.2 promised that core types would no longer be reshaped; we break that promise once, deliberately, because no partner has gone live yet — after the first one, the same correction would be a /v2 with six months of parallel operation. From rc.3 on, UsageUnit, MeasuringPoint, DeviceSegment and MeterReading change only additively.

Breaking

  • Monthly resolution. GET /usage-units/{id}/consumption and GET /measuring-points/{id}/readings now return one reading per calendar month end instead of two readings at arbitrary dates. MeterReading.at is a date (was date-time); from/to are widened to whole months and capped at the last completed month. Why: radio meters report several times a day; a series that fine, per apartment, is a behavioural profile of the residents. Billing needs period values, and GDPR data minimisation (Art. 5(1)(c)) does not let us hand out more. The landlord portal follows the same rule, so an ERP sees what the landlord sees. There is no parameter to get finer data, and the announced granularity= parameter will not come.
  • MeasuringPoint.active_device is nullable. Difference meters (new is_difference_meter: true) have no device of their own, and a measuring point whose device was removed without replacement has none either. rc.2 declared the field required, which made both unrepresentable.
  • MeasuringPoint.usage_unit_id is nullable (named breaking change, decided before rc.3 is published). Measuring points in areas that are allocated to no usage unit — a plant room, a main water meter, above all the total heat meter — used to be invisible: they belonged to no unit, so no endpoint returned them. A heating-cost statement cannot be built without them. They are now delivered with usage_unit_id: null and an empty allocations, found through the new GET /properties/{id}/measuring-points, and readable with GET /measuring-points/{id} and …/readings. MeasuringPoint.property_id is required and always set. They are never part of a unit or of /usage-units/{id}/consumption. Why now: rc.3 is not published and no partner has gone live, so the type change costs nobody anything; after the first partner it would be a /v2. Action: handle null.
  • installed_at is nullable on Device and DeviceSegment. For many devices the installation date is not documented; rc.2 forced us to either invent one or fail the response. It is now null when unknown and set only when the date is documented — never a placeholder such as 1900-01-01, and never the date a record was created. For such segments, baseline_value is the first value known for the device.

Added

  • DeviceSegment.period_consumption — end value, raw consumption and billable_value per segment, computed like the landlord portal. Sum billable_value across segments; do not bill last − first reading.
  • DeviceSegment.baseline_value / baseline_date — the value consumption is measured from. It can lie before from, and a replacement device starts at its own start value, not 0. Without it, a swap in mid-year silently under-reports consumption.
  • DeviceSegment.factor / Device.factor — K-factor (Bewertungsfaktor) for heat cost allocators, usually 1 otherwise. Raw HCA units without the factor bill wrongly.
  • MeterReading.is_synthetic — true when messpunkt.io interpolated the month-end value instead of receiving it from the device.
  • ReadingStatus value calibration_expired — the device's statutory calibration period had ended; the value must not be billed (billable_value is 0). Reporting it as measured or missing would both lead to wrong bills.
  • SubstitutionMethod values weighted_recent_2values, weighted_recent_3values, baseline_fallback, baseline_single_value — the methods our aggregation actually uses when it extrapolates an end value.
  • replacement_reason value DeviceReplacement — the meter swap, which is the case you will actually see.
  • Metric value water_outdoor — outdoor/garden water (Außenwasser, Sprengwasser). It must not be added to the water billed to residents, so mapping it onto water_cold would be a billing error.
  • GET /properties/{id}/measuring-points (scope read:devices, paginated) — every measuring point of one Property with and without a usage unit; MeasuringPoint.property_id.
  • MeasuringPoint.is_difference_meter (also on MeasuringPointSummary and MeasuringPointConsumption).
  • Documentation: Data resolution, Migrating from rc.2, Metrics and units, Errors sections; error examples (application/problem+json) and code samples for every operation; the MCP server https://mcp.messpunkt.io/v1 for landlords' own AI assistants, announced as part of V1.

Changed

  • DPoP is supported and optional (was "required in production"). A token obtained with a DPoP proof is bound to your key and must then always be sent with a valid proof; plain bearer tokens work otherwise. DPoP can be made mandatory per registered client on request.
  • Consent: the landlord chooses all Properties, including future ones (property_scope: "all") or a selection. Disconnecting in the portal takes effect within 60 seconds; changing the selection means reconnecting. The previously described in-place scope editing is not offered.
  • Authentication section documents resource (RFC 8707), iss in the authorization response (RFC 9207), /oauth/revoke (RFC 7009), registered ERP clients (private_key_jwt, client_secret_basic) and the per-Tenant API activation.
  • Canonical model corrected: measuring points hang off a Sector under the Address, and Sectors are allocated to UsageUnits — not UsageUnit → Sector as drawn before.
  • ReadingStatus no longer claims to map 1:1 to an internal type; each value is described by what it means.
  • linear_interpolation / degree_day_weighted now describe how calculated month-end values were interpolated.
  • Rate limits clarified and published, the same in production and sandbox: /v1/* 300 requests/min per connection (grant, the token's sid), counted after the token is validated, requests whose token fails validation per caller address; /oauth/token and /oauth/revoke 60/min per client_id after successful client authentication, in addition 60/min per caller address; /oauth/authorize 60/min per caller address; the MCP server 60/min per connection. 429 with Retry-After; counted in memory per server instance (best effort). rc.2 said "per client_id" in one place and "per caller IP" in another; neither described /v1/*, which is counted per connection because one ERP system serves many landlords from one address.
  • Examples use fictional addresses (Musterstraße, Musterstadt) and unit labels without names.

Not populated today

  • obis is always null. messpunkt.io does not store OBIS codes; the OBIS mapping table and the advice to prefer OBIS over metric are withdrawn.
  • resolution is always null; messpunkt.io does not record device resolution.
  • external_ref is always null and cannot be written; the external_ref filter matches nothing.
  • electricity and gas stay in Metric (removing them would be breaking) but there are no readable devices for them today.
  • replacement_reason values EndOfLife, Defect, PeriodEnd, Other and SubstitutionMethod value last_value_forward are not assigned today.
  • Pre-metering points (Vorerfassung) are not exposed — they would double-count the meters behind them. Unit sums therefore do not add up to a building total; the total meters of a plant room are delivered separately (usage_unit_id: null).

Removed

  • The expired GA target date (second quarter of 2026). GA ships with the first pilot partner and will be announced here.
  • The granularity= roadmap item (conflicts with monthly resolution).

Migration from rc.2

  • Parse MeterReading.at as a date; do not expect exactly two readings per segment.
  • Bill the sum of period_consumption.billable_value per measuring point; never bill a segment whose status is calibration_expired or missing.
  • Handle installed_at: null; do not replace it with a date of your own.
  • Handle usage_unit_id: null; read the total meters of a plant room from GET /properties/{id}/measuring-points.
  • Handle active_device: null and measuring points with is_difference_meter: true and no segments.
  • Keep water_outdoor out of residents' water; tolerate unknown enum values from now on.
  • Stop relying on obis, resolution and external_ref.
  • The sandbox keeps serving the rc.2 shape until its rc.3 update, which will be announced here.

rc.3 — Clarifications (not breaking)

Documentation of the same rc.3 contract, written down while building the rc.3 sandbox. No field, type or enum value changed, so the version number stays 1.0.0-rc.3.

  • Errors: GET /properties and GET /usage-units document 400 invalid-request for an invalid limit, page_cursor or property_id. A consumption range that lies entirely after the last completed month is 400, and so is an unknown metric value (named in detail). Every operation now lists 500 internal-error and 503 service-unavailable — no detail, retry with backoff.
  • /whoami answers 401 invalid-token when the landlord's API access has ended — never 404.
  • Device removed inside the range: period_consumption.end_value is the value on the removal day, status measured; if the removal day is a month end, the value also appears as that month's reading.
  • Unknown installation date: baseline_date is the month-end before from if known, otherwise the first known value — which can lie inside the range, not only before from.
  • No value at the end of the range: nothing is carried forward from an earlier month; unless the value is substituted, period_consumption.status is missing.
  • token_expires_at is omitted when unknown, never null.
  • Shared Sectors: how measuring points of a Sector shared by several UsageUnits appear under usage_unit_id will be fixed before GA.
  • Sandbox: the data is static up to 2026-12-31, and the fixture contains no substituted values.

rc.3 — Addendum (additive)

Additions to the same rc.3 contract before its publication. Only new optional fields, new schemas and descriptions — no field removed, no type changed, no new required field — so the version number stays 1.0.0-rc.3. One statement changes meaning (shared Sectors, see Changed meaning below).

  • For AI agents: the MCP server lists five read-only tools — list_properties, get_property_overview, get_consumption, get_device_status and get_connection_info. Their schemas are in the MCP tool reference.
  • DeviceSegment.baseline_origin (new, optional): where baseline_value comes from — recorded, assumed_zero, first_reading, portal_rule, month_end_before_range, first_known_in_range or none. assumed_zero means the start value of a replacement heat cost allocator was not recorded and is assumed to be 0 — the consumption of that segment rests on this assumption.
  • is_system_linked (new, optional, default true) on MeasuringPoint and MeasuringPointConsumption: false for a measuring point without an active assignment to a heating or water system. It is delivered with its values; the landlord portal shows 0 for it.
  • substituted is not produced today: ranges end at a completed month end, where messpunkt.io stores only calculated values. substitution_method therefore appears only on calculated values (degree_day_weighted for heat meters and heat cost allocators, linear_interpolation otherwise). The status stays in the contract.
  • calibration_expired can come with is_synthetic: true (an interpolated value of a device whose calibration has expired); substitution_method is then null. The value-status table said false only.
  • Usage units: floor, position and unit_type are taken from the unit's Sector with the highest allocation share; country_code is currently always DE.
  • Shared Sectors (new, optional): MeasuringPoint.allocations[] (usage_unit_id, share), MeasuringPointConsumption.unit_share and PeriodConsumption.weighted_billable_value (= billable_value × unit_share, only in /usage-units/{id}/consumption).

rc.3 — Addendum: error type and smaller corrections

Changed before rc.3 is published, so the version number stays 1.0.0-rc.3.

  • Problem type is now https://developer.messpunkt.io/errors/#<code>, the same in sandbox and production, and each value opens the explanation on Error handling. It used to be https://api(.sandbox).messpunkt.io/errors/<code>, an address where no page lives. The codes are unchanged. Action: branch on the fragment after # instead of the last path segment. The authorization server's 429 uses the same form.
  • 404 resource-not-found is also the answer for an {id} in the path that is not a UUID. It used to be an empty 404 without application/problem+json.
  • Property.addresses lists every address of the Property, including addresses without usage units; before, only addresses that carried a unit appeared.
  • Error texts: 403 says how to get the missing scope; an invalid date echoes the value (from must be an ISO 8601 date (yyyy-MM-dd); got '2025-13-01'.). detail stays free text — do not parse it.

rc.3 — Addendum: changed meaning (shared Sectors)

rc.3 said that values are “per device and never pre-weighted” and left open how a measuring point of a Sector shared by several usage units appears. messpunkt.io has such Sectors in production — 46 partial allocations, with 12 Sectors split between three to five units each — so the open point is now fixed:

  • MeasuringPoint.usage_unit_id is the primary unit (highest share; tie: the smallest id). allocations[] lists every unit with its share.
  • The measuring point is listed under every unit with a share, with that unit's unit_share. Before, rc.3 did not say that one measuring point can appear under several units.
  • Device values stay unweighted (readings, value, billable_value). The number to bill for a unit is now weighted_billable_value — the same weighting as the residents' portal; summed over the units of a Sector it gives the Sector's consumption, so a shared meter is never billed twice.
  • Action: sum weighted_billable_value (fall back to billable_value while it is absent) when you bill a unit. A client that keeps summing billable_value per unit bills a shared meter in full to every unit that shares it.
1.0.0-rc.2 2026-04-18 Release candidate

Added

  • New SDK & client generation page with copy-ready commands for OpenAPI Generator (C#, TypeScript, Python, Java, Go, PHP) and NSwag
  • Per-endpoint x-codeSamples for curl, C#, TypeScript and Python on the three most-used operations (whoami, listProperties, getUsageUnitConsumption) — rendered automatically in Redoc and Scalar

Changed

  • Sandbox tenant renamed from Hausverwaltung Musterfrau GmbH to Musterhausverwaltung GmbH — clearer, more business-like, still unambiguously fictional
  • Sandbox consent screen fully redesigned: German UX, action-verb permission descriptions, "Select all" Properties toggle, signed-in avatar, trust-building footer about revoke
  • Device serials are now pure numeric (8–10 digits) matching real WMBus format; manufacturer field remains the sole source of brand identity
  • Fixture addresses now use 34 realistic German street names across 14 mid-sized cities (Potsdam, Leipzig, Dresden, Hannover, Stuttgart, Freiburg, Kiel, Münster, Bremen, Erfurt, Augsburg, Karlsruhe, Regensburg, Nürnberg)
1.0.0-rc.1 2026-04-18 Release candidate

Added

  • Live sandbox on api.sandbox.messpunkt.io + auth.sandbox.messpunkt.io with 3 Properties, 27 UsageUnits, 87 MeasuringPoints of synthetic data
  • Full OAuth 2.1 Authorization Code + PKCE flow with DPoP support on the sandbox
  • Refresh-token grant with family rotation + replay-detection (OAuth 2.1 §4.13)
  • Bruno collection (download zip from /bruno) with 13 pre-configured requests
  • Per-IP rate limiting — 60 rpm on /oauth/*, 300 rpm on /v1/*
  • OBIS-code section (IEC 62056-6-1, BDEW alignment) with per-metric mapping table
  • AI-ready artifacts: llms.txt, .well-known/ai-plugin.json
  • RFC 9116 security.txt at /.well-known/security.txt
  • Property-scope enforcement — returns 404 (not 403) for out-of-scope resources to avoid scope enumeration

Changed

  • Version bumped from 0.1.0-draft to 1.0.0-rc.1; formal stability contract documented in the Reference
  • Bumped Scalar CDN to @1.52.2 (fixes OAuth scope-preselect bug upstream)
Pre-release sketches 2026-02 – 2026-04

Added

  • Initial OpenAPI 3.1 contract covering Introspection, Properties, Units, and Measuring points
  • Three viewer surfaces — Redoc Reference, Swagger UI, Scalar
  • Canonical data-model documentation (Tenant → Property → UsageUnit → Sector → MeasuringPoint → Device → MeterReading)