API reference
Battery health scores over HTTP.
Calibrated battery health scores over HTTP: SoH bands, degradation, residual, risk flags, drift monitoring. Authenticated with a bearer key, metered per tier, and errored in RFC7807 problem+json. This page renders from the committed OpenAPI document, so it stays in step with the live contract.
- API
- Ionscore API
- Version
- 0.1.0
- Surface
- /v1
- Media
- application/json
Authentication
Bearer keys, sandbox and production.
An Ionscore API key presented as a bearer token: 'Authorization: Bearer <key>' (bk_ / bk_sbx_ prefixes). Present it on every call to a protected endpoint; the health check and model card need no key.
Present the key
Authorization: Bearer bk_sbx_your_sandbox_keyA missing or unknown key returns 401 with a urn:ionscore:unauthorized body. Sandbox keys carry the bk_sbx_ prefix; production keys carry bk_.
Sandbox vs production
Scores the built-in demo fleet. Pass a packId to score a seeded pack; no telemetry of your own required.
Scores your packs from inline telemetry (identity plus observations). A packId lookup is refused with 403 urn:ionscore:sandbox-only.
Getting a key. Keys are issued by the Ionscore team today, not self-serve: tell us the tenant and tier and we mint one with the admin CLI. There is no key dashboard yet.
Monthly quota tiers
A key carries a tier that caps billable scores per UTC month; crossing it returns 429 with a urn:ionscore:quota-exceeded body. Caps are published defaults and are operator-overridable per deployment. Drift is metered separately and never counts against this quota.
| Tier | Key prefix | Scores / month | Use |
|---|---|---|---|
| sandbox | bk_sbx_ | 1,000 | Isolated demo tier; score the seeded fleet by packId. |
| pilot | bk_ | 10,000 | An evaluating customer scoring real telemetry. |
| production | bk_ | 100,000 | A live customer in steady-state use. |
Quickstart
Three calls against https://api.ionscore.dev: confirm the surface is live, score a demo pack in sandbox, then score your own telemetry in production.
Check the surface is live (public)
curl https://api.ionscore.dev/v1/healthzScore a demo pack with a sandbox key
curl -X POST https://api.ionscore.dev/v1/score \
-H "Authorization: Bearer bk_sbx_your_sandbox_key" \
-H "Content-Type: application/json" \
-d '{"packId":"ABCDE12345FGHIJ67890K"}'Score your own telemetry in production
curl -X POST https://api.ionscore.dev/v1/score \
-H "Authorization: Bearer bk_your_production_key" \
-H "Content-Type: application/json" \
-d '{"identity":{"packId":"ABCDE12345FGHIJ67890K","chemistry":"NMC","segment":"4W","ratedCapacityKwh":40.0},"observations":[{"months":12,"equivalentFullCycles":180.0,"meanDod":0.6,"fastChargeFraction":0.3,"resistanceProxyOhm":0.02,"resistanceRatio":1.1,"coulombicEfficiency":0.99,"meanPackTempC":30.0}]}'Errors: problem+json
Every failure is an RFC7807 document served as application/problem+json. The type is a stable urn:ionscore:* token you can branch on; each endpoint below lists the statuses it returns.
{
"type": "urn:ionscore:quota-exceeded",
"title": "Too Many Requests",
"status": 429,
"detail": "monthly score quota reached for this tier"
}Clients and tools
Typed clients mirror the endpoints method for method; the raw spec and a Postman collection are in the repo.
- OpenAPI 3.1 document/openapi.json
- Postman collectionservices/api/postman_collection.json
- TypeScript SDKsdks/typescript
- Python SDKsdks/python
Endpoints
The /v1 surface.
Four operations: two public reads and two authenticated scoring calls.
/v1/healthzPublicHealth check
Liveness and readiness for the /v1 surface. Public, so a probe never needs a key. Returns status ok while the process is up and ready true once the scoring model has loaded.
Example request
curl https://api.ionscore.dev/v1/healthz/v1/model-cardPublicModel card
The published model card: training setup, held-out error, band coverage, and calibration. Public on purpose, so you can judge the model before you hold a key. The full card is returned under card.
Example request
curl https://api.ionscore.dev/v1/model-cardErrors
| Status | Type | Title | Example detail |
|---|---|---|---|
| 503 | urn:ionscore:auth-backend-unavailable | Service Unavailable | model card is not available in this deployment |
/v1/scoreBearer requiredScore a pack
Score one pack and return its state-of-health band, forward degradation, residual value, risk flags, and the derived decision lenses (a PackScore). A sandbox key may score a seeded demo pack by packId; a production key posts inline telemetry.
Request body
application/json - Send packId (a sandbox-only lookup against the seeded fleet) OR an inline identity plus its observation history.
PackIdentityIn
| Field | Type | Required | Constraints |
|---|---|---|---|
| chemistry | string | required | - |
| climateZone | string | optional | default "TEMPERATE" |
| packId | string | required | pattern ^[0-9A-Z]{21}$ |
| ratedCapacityKwh | number | required | > 0 |
| region | string | optional | default "Unknown" |
| segment | string | required | - |
ObservableRowIn
| Field | Type | Required | Constraints |
|---|---|---|---|
| coulombicEfficiency | number | required | - |
| cumulativeChargeKwh | number | optional | default 0 |
| cumulativeDischargeKwh | number | optional | default 0 |
| cycleCount | number | optional | default 0 |
| equivalentFullCycles | number | required | - |
| fastChargeFraction | number | required | - |
| hotHoursCumulative | number | optional | default 0 |
| meanDod | number | required | - |
| meanPackTempC | number | required | - |
| months | integer | required | >= 0 |
| naiveSohProxy | number | optional | default 100 |
| resistanceProxyOhm | number | required | - |
| resistanceRatio | number | required | - |
Example request
curl -X POST https://api.ionscore.dev/v1/score \
-H "Authorization: Bearer bk_sbx_your_sandbox_key" \
-H "Content-Type: application/json" \
-d '{"packId":"ABCDE12345FGHIJ67890K"}'Errors
| Status | Type | Title | Example detail |
|---|---|---|---|
| 401 | urn:ionscore:unauthorized | Unauthorized | missing credentials: supply 'Authorization: Bearer <key>' |
| 403 | urn:ionscore:sandbox-only | Forbidden | packId scoring runs against the built-in demo fleet and is a sandbox-only affordance; a non-sandbox key must post inline telemetry |
| 413 | urn:ionscore:payload-too-large | Payload Too Large | observations list exceeds the configured maximum |
| 429 | urn:ionscore:quota-exceeded | Too Many Requests | monthly score quota reached for this tier |
| 503 | urn:ionscore:auth-backend-unavailable | Service Unavailable | auth backend not configured |
/v1/driftBearer requiredFeature drift
A feature-drift report for a batch of inline packs, PSI-compared against the model's training distribution. Metered for monitoring only: it does not draw down the scores quota. Sandbox and production keys are both accepted.
Request body
application/json - A non-empty packs array; each pack is the same identity plus observations shown under Score a pack.
Example request
curl -X POST https://api.ionscore.dev/v1/drift \
-H "Authorization: Bearer bk_your_production_key" \
-H "Content-Type: application/json" \
-d '{"packs":[{"identity":{"packId":"ABCDE12345FGHIJ67890K","chemistry":"NMC","segment":"4W","ratedCapacityKwh":40.0},"observations":[{"months":12,"equivalentFullCycles":180.0,"meanDod":0.6,"fastChargeFraction":0.3,"resistanceProxyOhm":0.02,"resistanceRatio":1.1,"coulombicEfficiency":0.99,"meanPackTempC":30.0}]}]}'Errors
| Status | Type | Title | Example detail |
|---|---|---|---|
| 401 | urn:ionscore:unauthorized | Unauthorized | missing credentials: supply 'Authorization: Bearer <key>' |
| 413 | urn:ionscore:payload-too-large | Payload Too Large | observations list exceeds the configured maximum |
| 429 | urn:ionscore:rate-limited | Too Many Requests | burst rate limit exceeded; retry after the window resets |
| 503 | urn:ionscore:auth-backend-unavailable | Service Unavailable | auth backend not configured |
Score your fleet.
A pilot gets you a key and scores a sample of your packs end to end, with the same published error discipline.