Connect API - Device Onboarding
TL;DR
GET /vendors→GET /vendors/{id}/connection-options→ run the OAuth/form flow →POST /vendors/{id}/connections→GET /vendors/{id}/devices→POST /devices- The
flowfield tells you which auth to implement:oidcProxy(WebView + intercept redirect),oidc(PKCE + deep link),ocpp(user pastes URL in wallbox),push(user pastes URL in vendor portal),form(text/secret fields).flowis returned per vendor onGET /vendorsand again onGET /connection-options— callconnection-optionsfor the form/login details, not just to learn the flow type GET /vendors/{id}/devicesreturns VendorDevices — link candidates read live from the vendor, no clever-PV id. Already linked devices can still appear withavailable: false. They are not the same thing as the Devices returned byGET /devicesafter linking. See Concept: VendorDevice vs. Device- After
POST /devices(linking), the device appears inGET /deviceswith itscapabilities[]— that's where real interaction starts - If the vendor rejects a connection's OAuth login,
GET /vendors/{id}/devicesreturns nothing for it and removes the connection unless a linked device uses it. See Rejected OAuth login
Complete flow for connecting vendor devices via the Connect API.
Just browsing the catalog? The vendor/model catalog is also reachable without authentication via the Public Vendor Catalog — authenticate to get your app-scoped catalog, or call anonymously for the default clever-PV catalog. Onboarding itself still requires the authenticated flow below.
Don't want to implement vendor login yourself? Hand the browser to Connect UI instead of steps 2–4, then list vendor devices and link them. OCPP wallboxes and push meters stay on the dedicated pages below.
Step 1: List Vendors
Code
Response:
Code
Note:
flowis a non-nullable string per vendor. Values:form | oidcProxy | oidc | ocpp | push. The vendor → flow mapping is not contractual — re-read it on every onboarding attempt.
Step 2: Get Connection Options
Code
Response Structure:
Code
Note: Enum values are serialized as camelCase strings.
When to use which flow
You don't choose the flow — the vendor does. You receive it on GET /vendors (per vendor) and again on GET /connection-options. Your job is to implement the five flow types so your client can handle whichever vendor the user picks.
| Flow | Used by (typical) | What the client must implement | Why this flow |
|---|---|---|---|
oidcProxy | Tesla, Volkswagen, Home Connect | A WebView that opens data.url, intercepts the redirect URL containing data.redirect, and POSTs the full URL back. No token handling on the client. | Vendor requires a confidential OAuth client; clever-PV holds the secret and exchanges the code server-side. |
oidc | Viessmann | Standard OIDC with PKCE: generate code_verifier/code_challenge, register the deep-link com.cleverpv.cleverpv://oauthredirect/, exchange code yourself. | Vendor allows a public OAuth client; PKCE keeps it secure without a server secret. |
ocpp | Wallboxes (any OCPP-1.6/2.0.1 hardware) | Display a generated OCPP server URL to the user; they paste it into the wallbox's own configuration UI. No browser flow. | OCPP is a wallbox-to-backend protocol — the wallbox itself initiates the connection. |
push | Push-based electric meters | After POST /connections, read flowOptions[name="pushUrl"] from the response and display it to the user; they paste it into their vendor portal. No browser flow, no client secret. See the dedicated Push Meter Onboarding page. | Vendor-initiated server-push — the vendor portal posts telemetry to the URL on its own cadence; no client secret leaves the server. |
form | Shelly, Vaillant (and others without OAuth) | Render the returned formOptions (text/secret fields or a vendor consent WebView) and POST the collected values as data. | Vendor has no OAuth at all — either a static API key/serial number, or a vendor-specific consent page that returns parameters in the redirect URL. |
Decision rules for client code:
- Always branch on
flow. Never assume a vendor uses a specific flow — vendors can change, and new vendors can be added at any time without a Connect-API version bump. oidcProxyandoidclook similar but are NOT interchangeable.oidcProxyrequires forwarding the full redirect URL;oidcrequires you to extract the code yourself and send it together with the originalcode_verifier.ocpphas no user-facing browser step. If you build an in-app onboarding wizard, theocppbranch must show instructions and the OCPP URL — not a WebView.pushalso has no browser step. The URL is not informOptions— it is returned in theflowOptionsarray of the create-connection response (see Step 4). Display the URL, instruct the user to paste it into the vendor portal.- For
form, inspectformOptions[].typebefore rendering:textandsecretare simple inputs,loginis a WebView whose intercepted redirect URL you forward unchanged asdata.url(see Option D below).
The vendor IDs returned by GET /vendors are stable, but vendor → flow mapping is not contractual. Always re-fetch /connection-options per onboarding attempt.
Step 3: OAuth Flow
Based on the flow value, execute the appropriate OAuth flow:
Flow Types:
oidcProxy: OAuth flow proxied through Clever PV servers. User authenticates via vendor's OAuth page, Clever PV handles token exchange.oidc: Direct OpenID Connect flow.ocpp: Open Charge Point Protocol flow for wallboxes. User manually enters OCPP server URL in their device configuration.push: Vendor-initiated server-push for electric meters. User manually enters a generated push URL in the vendor portal. URL + API key are returned in the create-connection response (flowOptions).form: Non-OAuth authentication using vendor-specific forms (text fields, secrets) or vendor consent pages.
Option A: "oidcProxy"
Example Response from Get Connection Options (here: Tesla):
Code
Flow:
- Open
data.urlin WebView (replace{{ locale }}with e.g.de) - User authenticates with vendor
- Detect and intercept redirection in WebView: URL contains
data.redirectstring - Store the intercepted URL (including the code) in memory for usage in the "Create Connection" step
Redirect Detection:
Code
Example Redirect URL:
Code
Cancelled or refused login: If the user cancels or refuses the authorization, or the vendor reports another OAuth error, the redirect URL still contains
data.redirectbut carries an OAutherrorparameter (for exampleerror=access_denied) instead ofcode. Forwarding this URL in Step 4 creates no connection and returns400withvendorAuthorizationDeniedorvendorAuthorizationFailed(see Vendor authorization errors). To try again, opendata.urlto start a new vendor authorization; do not resend the same redirect URL.
Option B: "oidc" (Direct OIDC with PKCE)
For this flow you have to register the redirect Url com.cleverpv.cleverpv://oauthredirect/ as a deep link handler.
Notice: The
redirectUrlis predefined by Clever PV and cannot be customized. You must use the redirect URL returned by the API (com.cleverpv.cleverpv://oauthredirect/) this might lead to conflicting deep link handling, when the user also has the clever-PV app installed on the same device.
Example Response (here: Viessmann):
Code
Flow:
- Fetch OIDC config from
discoveryUrl - Generate PKCE:
code_verifier(random 64 chars) →code_challenge(SHA256 + Base64URL) - Build authorization URL with
code_challenge - Register deep link handler for
redirectUrlscheme - User authenticates, app receives deep link with
code
PKCE Generation:
Code
Authorization URL:
Code
Redirect Detection:
Code
The OAuth
stateparameter is yours. Generate a random value for every login, add it asstateto the authorization URL, keep it until the deep link returns, and accept the callback only if it carries the same value — this ties the callback to the login you started and protects against forged redirects. The Connect API never receives or checksstate: the create-connection request has nostatefield, and a missing or wrong value causes no API error. The same applies tooidcProxy: the vendor URL indata.urlcomes withoutstate, and the server does not validate one. Only Connect UI generates and checksstateitself.
Option C: "ocpp" (OCPP Wallbox Protocol)
For OCPP-enabled wallboxes, the API provides a unique OCPP server URL that the user must manually configure in their wallbox device.
Example Response:
Code
Flow:
- Create the connection first:
POST /vendors/{vendorId}/connectionswithtype: "ocpp" - Read the stable URL from
flowOptions[name="ocppUrl"]in the create response - Display that URL to the user and instruct them to open their wallbox's configuration interface
- User enters the OCPP URL in the wallbox settings, saves and restarts the wallbox (if required)
- Wallbox connects to Clever PV's OCPP endpoint
- Device becomes available in "List Devices of Connection" step
Note: The URL shown by
GET /connection-options(example above) is a randomized preview — its device tag changes on every read. Always use theflowOptions[name="ocppUrl"]URL from the connection, which is stable from creation onward (also re-surfaced onGET /vendors/connections).
Note: The wallbox will not appear in the devices list until it successfully connects to the OCPP endpoint for the first time.
Option D: "form" (Vendor-Specific Forms)
For vendors without OAuth, the API returns form fields to collect. Field types:
"text": Simple text input (e.g., serial number)"secret": Password input (masked, e.g., API key)"login": WebView-based consent flow (not OAuth)
Example Response (Text Field):
Code
Text Field Flow:
- Display input field for
data.label - User enters value
- POST with collected data as shown in the Create Connection - For "form" sub-section.
Example Response (Login Field):
Code
Login Field Workflow:
The "login" field resembles a redirect-based flow similar to OAuth, but it's not standard OIDC/OAuth2. Instead, it's a vendor-specific flow. When a login field is present, it's always the only field in the array.
- Replace placeholders in
data.url(see below), then open it in a WebView (vendor's consent/login page) - User authenticates or grants consent on vendor's page
- Vendor redirects to URL containing
data.redirectstring - Intercept the redirect and forward the complete redirect URL, unchanged (including its query string), as
data.urlin the POST request withtype: "form"— the same pattern as theoidcProxyflow. The Connect API parses the vendor-specific query parameters server-side.
Important: This is not OAuth2/OIDC - there's no authorization code exchange, no tokens. The redirect URL simply contains vendor-specific parameters (like gateway IDs, consent status). Do not parse them out and send them as individual fields — send the full URL as
data.url, otherwise the request fails with401 invalidCredentials.
Placeholders in
data.url: The login URL may contain{state}— a blank the server intentionally does not fill in. Filling it is your job before you open the URL in the WebView. Any random string works: the Connect API never looks at the value. Its only purpose is that the vendor attaches the same value to the redirect URL again, so you can check that the callback really belongs to the login you started. Don't confuse it with{{ locale }}(see Option A): double braces are the server's own placeholder system, which normally arrives already resolved —localeis the only one the client replaces there too.
Example:
Code
Option E: "push" (Push API for Electric Meters)
For push-based electric meters, the API generates a unique push URL on connection creation — not in the connection-options response. The user pastes that URL into their vendor portal so the vendor can post telemetry to Clever PV.
Example Response (from GET /connection-options):
Code
Note:
formOptionsis intentionally empty — the URL is minted byPOST /connections(see Step 4: For"push") and returned insideflowOptions.
Flow:
- Call
POST /connectionswith{ "type": "push" } - Read
flowOptions[name="pushUrl"].datafrom the response and display it - Instruct the user to open their vendor portal and paste the URL into the push/webhook URL field
- User saves the configuration
- Vendor starts posting telemetry at its own cadence
- Device becomes available immediately in Step 7 — you do not need to wait for the first push
See also: Push Meter Onboarding for a complete step-by-step walkthrough with real example payloads.
Step 4: Create Connection
Heads-up — two unrelated
typefields: Thetypediscriminator in the request body below must be one ofform,oidcProxy,oidc,ocpp,push(the onboarding flows fromDeviceOnboardingFlow).
Thetypeyou may have seen insideformOptions[](e.g.text,secret,login) is a form-field type and is unrelated to the connection request — never use it as the requesttype.
Heads-up —
flowOptionson the response: Some flows return a genericflowOptionsarray on the connection response — a list of{name, data}pairs surfacing flow-specific values the client needs after the connection exists. Todaypushpopulates it (withpushUrlandapiKey) andocpppopulates it (withocppUrl). Match entries byname; order is not guaranteed.
For "oidcProxy":
Code
For "oidc":
Code
Note: Field is named
codeChallengebut expects thecode_verifiervalue.
codeis required. Send the PKCEcode_verifierincodeChallengewhenever the login used PKCE — the vendor's code exchange needs it. There is nostateorredirectUrifield: the redirect URI is the fixedredirectUrlfrom the connection options, andstatestays on your side (see Option B).
For "ocpp":
Code
Response:
Code
Note: Read
flowOptions[name="ocppUrl"]from this response (or re-fetched viaGET /vendors/connections) — don't compose the URL fromconnection-optionsyourself. Only one pending OCPP connection is allowed at a time per user: a connection is pending until a wallbox has connected to it, and a second create request returns409 pendingOcppWallboxExists. If the wallbox doesn't connect, delete the connection before creating a new one.
For "push":
Code
Response:
Code
Note: The push flow needs no
datapayload — the connection itself mints the credential. ReadpushUrlandapiKeyfrom theflowOptionsarray (match byname, not by index). Multiple open push connections per vendor are allowed.
For "form":
Code
Or, for a login field, with the full intercepted redirect URL (do not send parsed query parameters as individual fields):
Code
Response:
Code
Connection and device verification errors
Creating a connection and linking a device in Step 8 can require verification with the vendor. These requests can fail even if an earlier discovery request succeeded. Handle the following errors when either operation returns them:
| HTTP status | errorCode | Meaning and next step |
|---|---|---|
401 | invalidCredentials | The vendor rejected the credentials or access. Check the submitted credentials and vendor-account permissions, then repeat the form flow. |
502 | vendorCommunicationError | The vendor request timed out, could not connect, was rate-limited, returned a server error, or returned an unusable response. Retry later with increasing delays; do not ask the user to replace credentials solely because of this error. |
These errors use application/problem+json, as in the discovery error example. Use errorCode to choose the next action and keep traceId for support. The detail text is intended for display, not client-side parsing; vendor-response and JSON-parser diagnostics are not exposed in communication-error responses.
Vendor authorization errors
For oidcProxy, the Connect API checks the forwarded redirect URL before it redeems anything. If the URL carries an OAuth error parameter instead of an authorization code, no code is exchanged with the vendor and no connection is created. The request fails with 400 Bad Request and type operationFailed:
| HTTP status | errorCode | Meaning and next step |
|---|---|---|
400 | vendorAuthorizationDenied | The user cancelled or refused the authorization at the vendor (access_denied; Tesla reports a cancelled login as login_cancelled). No connection was created. Offer the user a new vendor authorization. |
400 | vendorAuthorizationFailed | The vendor returned a different OAuth error instead of an authorization code. No connection was created. Start a new vendor authorization; keep the traceId for support if the error persists. |
Resending the same redirect URL cannot succeed, now or later. Do not retry these requests: start a new vendor authorization by opening the vendor login from Step 3 again, then create the connection with the new redirect URL.
Changed behavior: Such redirect URLs previously returned
502vendorCommunicationError. If your client retries502responses automatically, it now receives these400codes for cancelled or failed vendor logins and must start a new vendor authorization instead.
Code
Step 5: Delete Connection (Optional)
Supported for connections created with the ocpp, push and form flows. Connections created with oidc or oidcProxy cannot be deleted through this endpoint; the request returns 400 with errorCode: "deleteConnectionNotPossible".
For OCPP, this is mandatory cleanup when a wallbox fails to connect — only one pending OCPP connection (no wallbox connected yet) is allowed per user. For Push, deletion is purely optional; multiple open push connections are allowed, so you only need to delete to revoke an API key.
Code
Response: 204 No Content on success
Important: All devices attached to the connection must be deleted first (via
DELETE /v1/users/{userId}/devices/{deviceId}— see Step 10: Delete Device). If you attempt to delete a connection with linked devices, the endpoint returns409withocppConnectionHasDevices,formConnectionHasDevicesorpushConnectionHasDevices.
Use cases:
- Wallbox failed to connect to the OCPP endpoint
- User entered incorrect configuration
- Need to create a new OCPP connection (must delete the existing one first)
Step 6: List User Connections (Optional)
Code
Response:
Code
Note:
flowOptionsis re-surfaced on every list call for flows that need it. Todaypushpopulates it (pushUrl,apiKey) andocpppopulates it (ocppUrl); for other connections the field isnull/ omitted. Match items byname, not by index — order is not guaranteed.
Concept: Connections
A connection is one login to one vendor account of the user. It belongs to exactly one vendor and gives access to the devices of that account:
- Same vendor account, more devices: no new connection is needed. Step 7 lists every device of the account under the existing
connectionId; link the next one with Step 8. - Another vendor: needs its own connection, created with that vendor's onboarding flow. A connection never spans vendors, and devices cannot be attached to a connection manually.
- Several accounts of the same vendor: a user can hold several connections of the same vendor, one per login.
GET /vendors/{vendorId}/deviceswithoutconnectionIdqueries all of them. - Logging in again creates a new connection. The API does not detect that a new
oidc,oidcProxyorformlogin belongs to an account that is already connected; each successful create-connection request returns a newconnectionId. To renew the login of an existing connection — e.g. afterauthentication-required— re-authorize it instead: via Connect UI or the device'sconnectcapability. Both keep theconnectionIdand its linked devices. - Deleting a device (Step 10) removes only that device. The connection and its other devices stay, and the connection is not deleted automatically when its last device is gone. Deleting the connection itself is a separate step (Step 5).
Concept: VendorDevice vs. Device
Step 7 and Step 9 below both return something you might call "a device" — they are not the same resource, and conflating them is the most common source of confusion in this flow.
| VendorDevice (Step 7) | Device (Step 8 / 9) | |
|---|---|---|
| Returned by | GET /vendors/{vendorId}/devices?connectionId= | POST /devices, GET /devices, GET /devices/{deviceId} |
| Identity | No clever-PV id. Identified by externalId (the vendor's own serial number / VIN / gateway id) + the connectionId it was found under | Stable clever-PV id (GUID) — used for every further call (PATCH, PUT /{capability}, DELETE) |
| Where it comes from | Fetched live from the vendor's own API on every call — not stored by clever-PV. Exceptions: for ocpp the list shows the wallboxes that have connected to the connection's OCPP URL, for push a single entry for the push connection. Once linked it stays in the list with available: false; it only disappears when removed from the vendor's account | A persisted clever-PV resource, created exactly once via POST /devices |
| What it's for | A candidate to show the user so they can pick what to link | The linked, functional device — the only place capabilities[] (telemetry, control, interventions) exist |
Linking one to the other: POST /devices (Step 8) takes the VendorDevice's externalId, its model.id, and the connectionId — that's the entire bridge between the two objects. name/text on the VendorDevice are display suggestions only; they are not copied over automatically, so pass them again in the POST /devices body if you want the same label to stick.
What available: false actually means
The API collapses several distinct situations into a single boolean:
- a Device already exists for this
externalId— in the current home or in any other home, including homes in the clever-PV app or in another partner's app - the vendor itself reports the device as offline, on unsupported firmware, or an unsupported model
Note: The response only exposes
available, not the reason behind it — you cannot tell "already linked by you", "already linked elsewhere", and "vendor says it's unusable" apart from the VendorDevice alone.
Important: A device is unique across all clever-PV homes, partners, and the clever-PV app.
POST /deviceschecks theexternalIdglobally and returns409 ConflictwitherrorCode: "duplicateDevice"if it is already linked anywhere — also when it was linked between yourGETand yourPOST. The user has to disconnect the device in the app where it is currently linked before it can be linked here.
Firmware and model compatibility
Devices whose models are available for selection in your app's catalog can still be returned with available: false if the vendor reports incompatible firmware or an unsupported model. Devices whose models are missing from that catalog or cannot be selected are omitted; Step 7 returns 206 Partial Content when such models are found, with only the supported catalog entries in data.
The response does not expose a status, a detailed compatibility reason, or a required firmware version. Do not infer a particular reason from available: false; keep the device unavailable for selection and show a general availability message.
Step 7: List Devices of a Connection
Code
Response:
Code
Discovery responses and errors
The response rules apply to every vendor. A successful request can return 200 with an empty data array: the vendor may have no devices, or no connection may match the requested vendor and optional connectionId. A vendor failure is not treated as a successful empty discovery.
| HTTP status | errorCode | Meaning and next step |
|---|---|---|
200 | — | Supported catalog entries were returned, possibly none. Check each entry's available flag before offering it for linking. A connection whose OAuth login the vendor rejected returns no entries and no error, see Rejected OAuth login. |
206 | — | Some discovered models are absent from the app's selectable catalog. Only supported catalog entries appear in data, which can be empty. |
401 | invalidCredentials | The vendor rejected the stored credentials, and the connection was not handled as described in Rejected OAuth login. Ask the user to re-authenticate with that vendor; refreshing the Connect API bearer token does not fix this error. |
401 | May be absent | The Connect API bearer token is missing, invalid or expired. Obtain a valid API token. The authentication layer may return an empty response body. |
403 | authenticationFailed or an access-related code | The vendor rejected access, or the caller lacks permission. Inspect errorCode and detail; check permissions and re-authenticate with the vendor when required. |
404 | Resource-specific code | A requested user, home or vendor resource could not be found. Verify the identifiers. No matching connection alone returns an empty 200 result. |
409 | Conflict-specific code | A conflict specific to this discovery request must be resolved before retrying; check errorCode and detail for the cause. This is distinct from the pending-OCPP-connection conflict on POST .../connections (Step 4), which applies to creating a connection, not to listing devices. |
500 | internalError | An unexpected internal failure prevented discovery. Keep the traceId when contacting support. |
502 | vendorCommunicationError | Communication with the vendor failed or timed out, its response could not be used, or the vendor rate-limited the request. This includes temporary failures while renewing an OAuth login; the connection is kept. Retry later with increasing delays; do not request new credentials solely because of this error. |
Application errors use application/problem+json. For example:
Code
Multiple connections and partial results
Omitting connectionId queries all of the user's connections for that vendor. If one connection fails authentication or communication (including a vendor timeout) but another discovers devices, the discovered candidates are retained, regardless of which connection is queried first. This includes discovery of unsupported models: the response is 206 when unsupported catalog models were found and 200 otherwise. The response contains no per-connection error list, so a successful aggregate response does not prove that every connection was queried successfully. Query each known connectionId separately when the UI needs to show which connection needs attention.
If no connection discovers any devices and at least one fails authentication or communication, the first encountered failure is returned. A successful empty result from another connection does not hide that failure. Unexpected internal errors abort the request even if another connection already discovered devices.
A connection whose OAuth login the vendor rejected does not count as a failed connection here; see Rejected OAuth login. A 206 response describes omitted models; it is not a signal that a connection failed.
Rejected OAuth login
This applies to connections created with the oidcProxy or oidc flow or through Connect UI. clever-PV renews the vendor login of such a connection automatically. If the vendor rejects the renewal, for example because the user revoked the access or the vendor invalidated the login, the connection cannot be used again without a new login by the user.
When discovery hits such a connection:
- The connection itself returns no candidates and contributes no error. When you query it by
connectionId, the response is an empty200. WithoutconnectionId, the other connections of that vendor are aggregated as described in Multiple connections and partial results: devices found elsewhere are returned with200(or206when catalog models were omitted), and if no connection discovers devices, a failure from another connection (for example401or502) is still returned. - If no linked device uses the connection, clever-PV removes it. It no longer appears in
GET .../vendors/connections, and itsconnectionIdcan no longer be used. Start a new vendor login (Step 3 or a regular Connect UI session), create the connection and list its devices again. - If at least one linked device uses the connection, it is kept. Repair it with the re-authorization flow instead of creating a new connection; one login covers all devices of that connection. The linked devices show an
authentication-requiredintervention as soon as clever-PV detects the rejection while communicating with them.
Temporary failures while renewing the login (network errors, timeouts, vendor server errors, rate limiting) never remove a connection. They count as a communication failure of that connection (502 vendorCommunicationError) and follow the rules in Multiple connections and partial results: when querying a single connectionId, or when no connection discovers devices and no other failure was encountered first, the response is 502; retry later.
Recognizing the case: an empty 200 for a specific connectionId can mean that the vendor account has no devices, or that the login was rejected. Call GET .../vendors/connections?vendorId={vendorId} afterwards: if the connection is gone, start a new vendor login; if it is still listed and has linked devices, check those devices for an authentication-required intervention.
Changed behavior: Previously a rejected OAuth login could make discovery return
401invalidCredentialsor403authenticationFailed, and the connection stayed in place. Temporary renewal failures could also be returned as401. Individual vendors can still return401invalidCredentialsfor a rejected login; handle it as described in the table above.
Step 8: Link Device
Only offer devices with available: true from Step 7 for linking. Availability can change between listing and linking, so a successful list response does not guarantee that the following request will succeed.
Code
Response Similar to result of step "Get Linked Devices"
If linking fails, inspect the HTTP status and error response, including errorCode, and refresh the device list before offering another attempt. Only offer devices that are still listed with available: true, and address the reported error before retrying. 409 Conflict with duplicateDevice means the device is already linked — possibly in the clever-PV app or in another partner's app, not only in your own. The user has to disconnect it there before it can be linked here.
Always send the connectionId under which the VendorDevice was listed. Without it, the device is attached to the user's first connection of that vendor, which is not necessarily the account the device belongs to. Other failures can involve authentication or vendor communication; they do not by themselves identify firmware or model incompatibility. There is no single HTTP status for every cause of available: false.
Device linking can return the authentication and communication errors described for connection creation. A 502 / vendorCommunicationError means that vendor communication failed; retry later with increasing delays.
Step 9: Get Linked Devices
Code
Note: For push-style devices, the
connectcapability'sdatacarries aflowOptionsarray mirroring the connection-levelflowOptions(pushUrl,apiKey). OCPP devices behave the same way — theirconnectcapability surfacesocppUrlso you can recover the WebSocket URL from the device alone without re-fetching the connection. See Push Meter Onboarding → Step 7 for the push shape.
Response:
Code
Step 10: Delete Device
Unlinks a device. Some devices run a full vendor facing reset path (eg.: SG-Ready back to Normal if applicable) that honours force. force does ignore errors on some vendors here.
Code
| Parameter | Default | Meaning |
|---|---|---|
force (query) | false | If true, only delete locally even when the vendor reset fails. Honoured by a subset of vendors. |
Responses:
| Status | When |
|---|---|
204 No Content | Deleted (always returned when force=true, unless the device doesn't exist). |
404 Not Found | No such device for this user. |
409 Conflict | force=false and vendor reset failed — device was NOT deleted. |
409 response: a problem-details body with errorCode: "internalError"; the reason is in extensions.vendorErrorCode:
extensions.vendorErrorCode | Meaning |
|---|---|
ConnectionExpired | Refresh token invalid. An authentication-required intervention is added to the device's core capability. |
DeviceUnreachable | Vendor server unreachable. Safe to retry. |
ResetFailed | Any other vendor error during reset/delete notification. |
Code
When to use force=true: eg: the vendor account is gone, the hardware is removed, the connection cannot be restored, or the user has confirmed deletion after a 409. Default to force=false and surface the 409 message so the user can make that choice.
Deleting a whole connection: connections cannot be deleted while devices are linked. Delete each device first (Step 10), then the connection (Step 5).