Diagnostic Service
The Diagnostic Service exposes vehicle State of Health (SOH) diagnostics for EV batteries — a battery health score (0–100 %) together with the provider's report (PDF and image).
To activate the diagnostic service for your software, please contact us at https://openhive.eu/contact.
How It Works
There are two ways to get a diagnostic:
- 📖 Read — for everything that already exists. Look up a vehicle's diagnostics with
GET /v1/diagnostic/soh-reports, filtered by VIN, status, type or date. - 🔔 Subscribe to the webhook — to receive every new diagnostic. A measurement is started out in the field by the customer, with or without a partner device plugged into the vehicle. When it is ready, the partner pushes it to OpenHive, OpenHive calls your webhook URI, and you read the report back.
Your application never triggers a measurement, and never waits on one. Both are scoped to your entitlement: you only ever see diagnostics attached to your own customer subscription.
The original flow rolled everything into one call: you submitted a VIN through POST /v1/diagnostic/soh-requests and waited on the answer, whether the vehicle had already been measured or not. That model is deprecated.
Use GET /v1/diagnostic/soh-reports to look up a pre-existing diagnostic, and rely on the webhook to pick up a diagnostic that has just been performed.
The endpoint still answers for existing integrations, but it will be removed — do not build on it. See Legacy flow below.
Looking up a diagnostic
GET /v1/diagnostic/soh-reports returns the diagnostics your subscription is entitled to, most useful when filtered by VIN:
curl "https://api.openhive.eu/v1/diagnostic/soh-reports?vin=WVWZZZ1JZXW000001" \
-H "Authorization: Bearer <access_token>"
Filters
| Query parameter | Description |
|---|---|
vin / vin[] | Exact VIN, or any of several VINs. |
status / status[] | Exact status — success or error. |
type / type[] | Exact diagnostic type, or any of several. |
performedAt[after] / performedAt[before] | Measured on or after / on or before this date. |
performedAt[strictly_after] / [strictly_before] | Measured strictly after / strictly before this date. |
Fetch a single diagnostic with GET /v1/diagnostic/soh-reports/{uid}.
Response fields
| Field | Description |
|---|---|
uid | OpenHive identifier of the diagnostic. |
vin | Vehicle VIN. |
status | success or error. |
sohValue | Battery health score (0–100 %). Only on success. |
pdfUrl / imageUrl | Provider report and illustration. Only on success. |
errorReason | Why the diagnostic failed. Only on error. |
provider | Partner that performed the measurement. |
type | Diagnostic type. |
externalId | The provider's own reference for this report. |
performedAt | When the measurement was taken. |
expiresAt | When the diagnostic stops being considered current, if applicable. |
createdAt | When OpenHive received it. |
Webhook notification
When a partner pushes a diagnostic for one of your vehicles, OpenHive sends an HTTP POST to your software's configured webhook URI:
{
"event": "diagnostic_soh.created",
"uid": "550e8400-e29b-41d4-a716-446655440000",
"vin": "WVWZZZ1JZXW000001",
"status": "success",
"url": "https://api.openhive.eu/v1/diagnostic/soh-reports/550e8400-e29b-41d4-a716-446655440000"
}
The webhook is a notification, not the report: it tells you a diagnostic exists and where to read it. Call the url it carries (or GET /v1/diagnostic/soh-reports/{uid}) to get the score, the PDF and the image.
Answer 2xx quickly. A non-2xx response is retried, so treat the delivery as at-least-once and make your handler idempotent on uid.
Statuses
| Status | Description |
|---|---|
success | Measurement completed — sohValue, pdfUrl and imageUrl are set. |
error | Measurement failed — errorReason explains the cause. |
Sandbox toolkit
POST /v1/diagnostic/soh-reports/sandbox is integration tooling, not a business endpoint: it lets you simulate the arrival of a diagnostic so you can exercise your integration without a partner and a real vehicle.
OpenHive performs a genuine push through the very same connector a partner uses — so your webhook fires and the diagnostic becomes readable exactly as it would in production. The call is asynchronous and answers 202.
Sandbox starts out empty: there are no pre-seeded diagnostics, so this endpoint is what makes them exist. Trigger one, let your webhook fire, then read it back with GET /v1/diagnostic/soh-reports?vin=… — that exercises both halves of the integration in one go.
curl -X POST https://api.openhive.eu/v1/diagnostic/soh-reports/sandbox \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"vin": "SNDBXSUCCES95PUSH"}'
The VIN selects the scenario to simulate:
| VIN | Simulated result |
|---|---|
SNDBXSUCCES95PUSH | success — score 95, with PDF and image. |
SNDBXSUCCES70PUSH | success — score 70, with PDF and image. |
SNDBXERRPRVDRPUSH | error — provider error. |
SNDBXUNKNVEHCPUSH | error — vehicle not recognized. |
Every diagnostic carries an externalId — the reference the provider puts on its own report, which in the real flow you only ever read back (see Response fields). Here you stand in for the provider, so you may set it yourself; omit it and OpenHive generates one for you.
Setting it is only useful to rehearse idempotent replay: pushing the same externalId again with the same VIN is treated as a retry rather than a new diagnostic. Beware that every sandbox subscription shares a single provider identity, so this namespace is shared between integrators — an externalId already used with a different VIN is rejected with 409.
This endpoint requires an OpenHive Sandbox subscription — any other subscription gets a 403.
Putting it together
Integration Steps
- 1️⃣ Get your API credentials from OpenHive.
- 2️⃣ Obtain a JWT token from the OpenHive IDP.
- 3️⃣ Expose a webhook endpoint and give us its URI.
- 4️⃣ Look up existing diagnostics by VIN, and handle incoming webhook notifications.
- 5️⃣ Rehearse the whole thing with the sandbox toolkit.
Legacy flow (deprecated)
The original model went through a single call, which both looked up and waited:
- Your application submitted a
POST /v1/diagnostic/soh-requestswith the vehicle VIN. - You got the diagnostic straight back when the vehicle had already been measured, otherwise a record in state
NEW. - For a pending one, the result then reached you by webhook — carrying the full payload (
state,score,pdfUri,imageUri) — or the diagnostic ended asERRORif none ever arrived.
Calling it never caused a measurement to be taken: the vehicle still had to be measured in the field, exactly as today.
That flow used its own states — NEW, PENDING, DONE, ERROR — which are not the statuses of the current API.
It is kept working for existing integrations only. New integrations must use the lookup + webhook model described above.