Integrating Third-Party Datasources: A Step-by-Step Guide for integrators

Follow

This guide describes the process for third-party data providers (utility data aggregators, metering platforms, IoT gateways, etc.) to integrate their service into Spacewell Energy as a Market App with a Datasource Type. After integration, platform users can install the provider's app, grant consent to their meters, and have readings flow automatically into their account.

Audience: technical teams at the provider. Requires basic knowledge of HTTP/REST and JSON.


1. How the platform models data

Concept

Meaning

Deployment

A customer account, identified by an account/deployment ID

Datasource

A gateway or logical source that sends data; contains N devices

Device

An individual meter or sensor, identified within its datasource by a local device ID (did)

Parameter

The type of each datapoint (e.g. Active Energy, Gas Volume, Temperature)

Readings

Time-series values per device and parameter

Recommended mapping: one logical grouping on the provider side (e.g. a connection, site, or — where applicable — an authorisation/consent) = one datasource. All meters in that grouping become devices under that datasource, separated by device ID. The platform does not discover meters automatically — your app defines which meters belong to each datasource (for consent-based integrations, typically the meters explicitly listed in the authorisation).


2. Integration overview

The integration has four building blocks:

  1. A Market App — your service registered in the platform. Registration gives you an app_id and secret, and triggers a handshake on installation that yields a permanent API token.

  2. APIv3 — the platform's REST API (https://api.dexma.com/v3), authenticated with the permanent x-dexcell-token. You use it to register and update your datasources, and to read platform entities (deployments, locations, devices, parameters, session details) as needed.

  3. A Datasource Type — declared in the app configuration. It lets users create datasources of your type and tells the platform which URLs to call for health checks and for your embedded UI.

  4. Data insertion (IS3) — the HTTPS/JSON insertion API where you push readings for the datasources you created. Note that readings flow through IS3, not APIv3.

Your app's UI pages (including any consent/authorisation widget) are embedded in the platform via iframe. Make sure your pages can be framed by the platform domain — coordinate Content-Security-Policy (frame-ancestors) / X-Frame-Options settings with the Spacewell Energy team, and see section 5 for the full security requirements.


3. Step-by-step process

Step 1 — Register the app

A SuperAdmin user registers your application in the platform (see Registering a Market App). You provide:

  • Installation/uninstallation URLs and URLs for any views or reports

  • Requested scopes (read/write permissions per API area)

  • The Datasource Type section (see Step 3)

You receive an app_id and a secret.

Step 2 — Implement the installation handshake

When a user installs your app, the platform initiates a handshake that produces the permanent token (x-dexcell-token) your app must use on every APIv3 request:

  1. Platform calls GET <your installation URL>?dep_id=<deployment>&temp_token=<temp> (ignore the legacy callback parameter).

  2. Your app calls POST https://api.dexma.com/v3/oauth/access-token?app_id=<id>&secret=<secret>&temp_token=<temp> (endpoint reference).

  3. APIv3 responds 201 CREATED with the permanent token in the body.

  4. Your app stores the token (per deployment) and returns 200 OK.

If the token is lost it cannot be recovered — the user must reinstall the app. Tokens are scoped per app-deployment pair.

Also implement the uninstallation URL declared at registration: when a user uninstalls the app, clean up the stored token and local state for that deployment. A later reinstall runs the handshake again and produces a new token.

Step 3 — Declare the Datasource Type

In the app registration form, fill in the Datasource Type section:

  • Name (mandatory): shown to users when adding a datasource of your type

  • Icon: your logo

  • URL (mandatory): base URL for gateway communication. <URL>/ping must answer 200 with body pong while your service is up — the platform checks it before offering your type and marks it unavailable otherwise. Your app should also expose <URL>/app-status returning 200 with a JSON health summary (status, per-dependency statuses, serverTime), even when degraded

  • URL for UI (mandatory): base URL for the embedded pages:

    • <URL for UI>/datasources/new — register a new datasource (typically your consent/authorisation flow)

    • <URL for UI>/datasources/<id> — edit an existing datasource

    • <URL for UI>/datasources — (optional) list existing datasources for the deployment

  • Key (mandatory, unique): prefix for the names of all datasources you generate

The endpoints your app must expose behind URL and URL for UI are part of the datasource lifecycle — see Step 4.

Step 4 — Implement the datasource lifecycle

Your app must be able to:

  1. Register a virtual datasource for a deployment via APIv3 and persist it locally

  2. Update a registered datasource (only name and status are modifiable)

  3. Insert readings linked to existing datasources (Step 5)

The lifecycle combines calls in both directions — pages the platform loads from your app (using the URLs declared in Step 3) and APIv3 calls your app makes (base URL https://api.dexma.com/v3, authenticated with x-dexcell-token):

Action

Direction

Call

Query parameters

Notes

Open creation page

Platform → App

GET {URL for UI}/datasources/new

dep_token, session_id, lang

Must show your page to register a new datasource (e.g. your consent flow)

Create datasource

App → Platform

POST /datasources (reference)

— (datasource definition in JSON body)

Returns the datasource id (and key, prefixed with your Datasource Type key)

Get datasource token

App → Platform

GET /datasources/{id}/token (reference)

Returns the token used as x-dexcell-source-token when inserting readings via IS3 (Step 5)

Open edit page

Platform → App

GET {URL for UI}/datasources/<id>

dep_token, session_id, lang

Must show your page to edit the existing datasource

Update datasource

App → Platform

POST /datasources (reference)

— (datasource definition in JSON body)

Merge of the existing datasource; only name and status are modifiable

Delete datasource (platform-initiated)

Platform → App

DELETE {URL}/datasources/<id>

dep_token

Return 2xx on success (body ignored); on an error code the datasource is not deleted in the platform. Remove it locally too

Delete datasource (app-initiated)

App → Platform

DELETE /datasources/{id} (reference)

Removes the datasource in the platform, e.g. when it's deleted or revoked on your side. Remove it locally too

Query parameters sent by the platform on the platform → app calls:

  • dep_token (always sent): identifies the deployment for which the call is made — use it for authentication

  • session_id (UI calls): can be used to obtain session details via the APIv3 session endpoint

  • lang (UI calls): current platform language (en_US format), for internationalising your pages

Typical creation flow: the user fills in your embedded /datasources/new page → your app validates and stores the datasource locally → POST /datasources to register it in the platform → GET /datasources/{id}/token to obtain the insertion token → store both. If the platform call fails, roll back your local record.

Illustrative exchange (see the endpoint references above for the exact schemas):

POST https://api.dexma.com/v3/datasources
x-dexcell-token: <permanent token>
Content-Type: application/json

{ "name": "<datasource name>", "status": "ENABLED" }

→ 201 with the created datasource (note the "id")

GET https://api.dexma.com/v3/datasources/<id>/token
x-dexcell-token: <permanent token>

→ 200 with the datasource token (use as x-dexcell-source-token in Step 5)

Persisting datasource state locally is mandatory: IS3 rejects insertions for datasources that don't exist or aren't enabled/online, but querying datasource state before each insertion will exhaust your API quota. Keeping the local copy in sync is your responsibility.

Full request/response schemas: developers.dexma.com.

Step 5 — Insert readings (IS3)

Push readings with POST https://insert.dexma.com/readings?source_key=<datasource key> and headers:

x-dexcell-source-token: <datasource token>
Content-Type: application/json

The datasource token is the one obtained via GET /datasources/{id}/token in Step 4.

Body — an array of messages:

json

[
  {
    "did": "meter-001",
    "sqn": 1,
    "ts": "2026-06-01T00:00:00+02:00",
    "values": [
      { "p": 402, "v": 123456.7 }
    ]
  }
]
  • did: local device ID (max 25 chars) — use it to separate the meters under one datasource

  • sqn: always set to 1

  • ts: ISO 8601 with explicit offset or Zulu time. The timezone is set at datasource level: you can insert with any offset as long as it corresponds to the correct moment in time — the platform always converts the timestamp to the datasource's timezone

  • p / v: parameter ID (see below) and value

Choosing the parameter ID (p): every parameter has a 3-digit base code (e.g. 402 = Active Energy, 401 = Power, 301 = Temperature) — see the platform parameters spreadsheet. The ID you insert with depends on how the data is measured:

  • Cumulative (basic) data — meter index values that always increase: use the 3-digit code as is (e.g. 402). The platform computes consumption for all frequencies by interpolating between readings.

  • Instantaneous data — point-in-time values like temperature or power: also the 3-digit code (e.g. 301, 401).

  • Interval (discrete) data — per-interval values like "kWh consumed this half hour": use the 5-digit composite code SSSFO, where SSS is the base code, F the frequency (0 = QH, 1 = H, 2 = D, 3 = W, 4 = M, 6 = 30min, 7 = 10min, 8 = 5min) and O the operation (1 = Delta for accumulated parameters, 2 = Avg / 3 = Max / 4 = Min for instantaneous ones). E.g. 40201 = quarter-hourly active energy delta; 40102 = quarter-hourly average power. Interval data is calculated only towards coarser resolutions, and a device parameter cannot have two discrete resolutions at once.

More detail: Introduction to Parameters.

Key conventions:

  • Max 5,000 readings per message

  • Interval data: timestamp must be the beginning of the interval, aligned to the data frequency (e.g. daily readings at local midnight). Misaligned timestamps return 200 OK but are silently discarded

  • Mind timezone offsets when using Zulu time

Historical data and backfill: most integrations need to load history in addition to live data. Insert historical readings in chronological order wherever possible — out-of-order insertions and overwrites trigger recalculation processes with edge cases around month boundaries. Batch readings (up to the 5,000/message limit) rather than sending one by one. Note that gap-filling between cumulative readings is limited (long gaps may leave intervals empty), and that after a large backfill you should verify a sample of the data via APIv3 or the platform UI rather than relying on the 200 OK alone.

Step 6 — Test, then go live

Use a test deployment to validate: installation handshake, datasource creation through your embedded UI (iframe rendering and CSP), reading insertion, and visibility of data in the platform. Once validated, the app can be published in the Apps Market.


4. Operational considerations

  • Rate limits (APIv3): defined per application and applied per token (per app-deployment pair). Exceeding them returns 429; every response carries X-Ratelimit-* headers — honour them in your client and back off before hitting the limit. IS3 has no hard rate limit, but batch readings for throughput.

  • Error handling: APIv3 validation errors return a JSON body with status, code, message and a per-field errors array (e.g. 422 for invalid pagination or entity fields) — surface these in your logs. On IS3, remember that 200 OK means accepted, not stored: misaligned or invalid readings are silently discarded, so monitor that inserted data actually appears.

  • Securing your endpoints: validate dep_token on every platform → app call and reject requests without it; your DELETE {URL}/datasources/<id> endpoint in particular must only act on legitimate platform calls, since it destroys data.

  • Datapoints: each accepted device parameter consumes a datapoint, which is the platform's billing unit — only send parameters that are useful for analysis.

  • Authorization: access is constrained by the scopes granted at installation plus per-resource ACLs.

  • Consent lifecycle (if your integration is consent-based): handle authorisation expiry/revocation in your app and reflect it in the datasource status.

  • Support: if you intend to develop an integration for Spacewell Energy, contact support.energy@spacewell.com or product.energy@spacewell.com for further directions, and to have a test account and user created.


5. Security requirements for embedded apps

These requirements apply to any app whose UI is embedded in the platform via iframe:

  • HTTPS is mandatory for all app endpoints.

  • As a general rule, configure CSP and CORS as restrictively as possible, and keep the app regularly updated and patched.

  • You must be able to adjust your security configuration (CSP, CORS, etc.) on request from the Spacewell Energy team, and an app detected to be dangerous to the platform can be blocked.

Content Security Policy: your CSP headers must explicitly allow the platform domain to frame your pages. Minimum:

Content-Security-Policy: frame-ancestors <energy-platform dns>;

Recommended:

Content-Security-Policy:
  default-src 'self';
  frame-ancestors <energy-platform dns>;
  object-src 'none';
  base-uri 'self';
  form-action 'self';

CORS recommendations:

Requirement

Rule

Public, unauthenticated assets

Access-Control-Allow-Origin: * may be acceptable

Authenticated APIs

Allow only the platform origin

Cookies or auth headers

Use an explicit origin, never *

Multiple environments

Use an allowlist: dev, staging, production

Preflight requests

Handle OPTIONS securely


6. References

Was this article helpful?