API REFERENCE · v0.1.0

EV Network Intelligence API

Built for CPOs, CPMS providers & E-roaming hubs – integrate without replacing your stack.
Push OCPP meter values, get anomaly verdicts back. No ML expertise required.

BASE URL https://api.solidstudio.ai
AUTH Bearer <token>
FORMAT JSON
LLM-FRIENDLY llms.txt
GET /v1/sessions

List Sessions

List analyzed sessions with pagination and filters. Returns all sessions for the authenticated tenant, most-recent first. Each item includes the latest inference result when available.

Headers

Authorization *
string Bearer token with embedded tenant context

Query Parameters

page
integer Page
pageSize
integer Pagesize
chargingStationId
string Chargingstationid
evseId
string Evseid
isAnomaly
boolean Isanomaly
minScore
number Minscore
minConfidence
number Minconfidence
dateFrom
string Datefrom
dateTo
string Dateto

Response 200

content *
object[] Sessions on the current page
sessionId *
string Client-provided session identifier
chargingStationId *
string Charging station identifier
isAnomaly *
boolean | null Anomaly flag from latest inference (null if not yet analyzed)
anomalyScore *
number | null Latest anomaly score (null if not yet analyzed)
anomalyCount *
integer Number of anomaly categories detected in latest inference
status *
string Session lifecycle status: pending → active → failed
createdAt *
string Session creation timestamp (UTC)
lastAnalyzedAt *
string | null Last successful analysis timestamp (UTC)
pagination *
object Pagination metadata
totalCount *
integer Total number of items matching the query
page *
integer Current page number (1-based)
size *
integer Number of items per page
Response · 200 JSON
{
  "content": [
    {
      "anomalyCount": 2,
      "anomalyScore": 0.85,
      "chargingStationId": "CP-NL-AMS-0042",
      "createdAt": "2026-02-27T10:00:00Z",
      "isAnomaly": true,
      "lastAnalyzedAt": "2026-02-27T10:31:02Z",
      "sessionId": "sess-abc-001",
      "status": "active"
    }
  ],
  "pagination": {
    "totalCount": 0,
    "page": 0,
    "size": 0
  }
}
POST /v1/sessions

Create Session

Create a charging session and optionally run anomaly analysis. IR-372: the SQLAlchemy session is opened inside the handler body rather than via ``Depends(get_saas_db)`` so the pool slot is not held while the request queues on the anyio threadpool. See ``docs/plans/2026-05-18-saas-db-session-decoupling-design.md``. Meter values are optional — session can be created empty and populated later via PUT or PATCH. If >= 3 meter values are provided, the CSAR-2 pipeline runs automatically and returns analysis results.

Headers

Authorization *
string Bearer token with embedded tenant context

Request Body

sessionId *
string Client's unique session identifier. Used for upsert (find-or-create)
chargingStationId *
string Charging station identifier (EVSE location)
connectorId
string | null Connector identifier within the charging station
evseId
string | null EVSE identifier (EU standard)
meterValues
object[] Initial meter readings. Optional — session can be created empty and populated later via PATCH or PUT.
timestamp *
string UTC timestamp of the meter reading (OCPP MeterValues timestamp)
value *
number Measured value in the specified unit (0 to 10,000,000,000)
measurand
string | null OCPP measurand type (e.g. Energy.Active.Import.Register, Power.Active.Import, SoC)
unit
string | null OCPP unit of measure (e.g. kWh, kW, Percent, A, V)
phase
string | null OCPP phase (e.g. L1, L2, L3, L1-N)
location
string | null OCPP meter value location (e.g. Outlet, EV, Cable)
reconstructed
boolean True if value was reconstructed by SORC model
metadata
object | null Optional client metadata for the session
status
string | null Optional initial session status (active, pending, completed, or invalid)
stopReason
string | null OCPP stop reason (e.g. Local, Remote, EVDisconnected)

Response 200

sessionId *
string Session identifier
chargingStationId *
string Charging station identifier
connectorId
string | null Connector identifier within the charging station
evseId
string | null EVSE identifier (EU standard)
status *
string Session status: pending, active, or failed
isAnomaly
boolean | null Whether any anomaly was detected (null if pending)
anomalyScore
number | null Overall anomaly score (null if pending)
anomalyConfidence
number | null Overall model confidence (null if pending)
isIncident
boolean | null Confirmed incident (null if pending)
isRecurring
boolean | null Recurring pattern (null if pending)
anomalies
object[] Detected anomalies (empty if pending)
category *
string Anomaly classification category
score *
number Anomaly severity score (0.0 = normal, 1.0 = extreme)
bucketRange
object | null Affected meter value range (bucket indexes, null when not available)
startUnit *
integer Start bucket index (0-based, 15-second slot offset from session start)
endUnit *
integer End bucket index (inclusive, 15-second slot offset from session start)
timeRange
object | null Affected time range (start/end timestamps, null if not available)
startTimestamp
string | null Start of the anomaly time range
endTimestamp
string | null End of the anomaly time range
confidence *
number Model confidence in this detection (0.0–1.0)
analyzedAt
string | null Analysis timestamp (null if pending)
socReconstructed
boolean Whether SoC was reconstructed by SORC model
message
string | null Informational message about the analysis status (e.g. why inference was not performed)
stopReason
string | null OCPP stop reason (e.g. Local, Remote, EVDisconnected)
createdAt
string | null Session creation timestamp (null if unavailable)
Request JSON
{
  "chargingStationId": "CP-NL-AMS-0042",
  "connectorId": "1",
  "meterValues": [
    {
      "measurand": "Energy.Active.Import.Register",
      "timestamp": "2026-02-27T10:00:00Z",
      "unit": "kWh",
      "value": 0
    },
    {
      "measurand": "Power.Active.Import",
      "timestamp": "2026-02-27T10:00:00Z",
      "unit": "kW",
      "value": 0
    },
    {
      "measurand": "SoC",
      "timestamp": "2026-02-27T10:00:00Z",
      "unit": "Percent",
      "value": 80
    },
    {
      "measurand": "Energy.Active.Import.Register",
      "timestamp": "2026-02-27T10:15:00Z",
      "unit": "kWh",
      "value": 5.5
    },
    {
      "measurand": "Power.Active.Import",
      "timestamp": "2026-02-27T10:15:00Z",
      "unit": "kW",
      "value": 22
    },
    {
      "measurand": "SoC",
      "timestamp": "2026-02-27T10:15:00Z",
      "unit": "Percent",
      "value": 65
    },
    {
      "measurand": "Energy.Active.Import.Register",
      "timestamp": "2026-02-27T10:30:00Z",
      "unit": "kWh",
      "value": 11.1
    },
    {
      "measurand": "Power.Active.Import",
      "timestamp": "2026-02-27T10:30:00Z",
      "unit": "kW",
      "value": 22
    },
    {
      "measurand": "SoC",
      "timestamp": "2026-02-27T10:30:00Z",
      "unit": "Percent",
      "value": 50
    }
  ],
  "sessionId": "sess-abc-001"
}
Response · 200 JSON
{
  "analyzedAt": "2026-02-27T10:31:02Z",
  "anomalies": [
    {
      "bucketRange": {
        "endUnit": 7,
        "startUnit": 4
      },
      "category": "KWH_DECREASE",
      "confidence": 0.92,
      "score": 0.87
    }
  ],
  "anomalyConfidence": 0.92,
  "anomalyScore": 0.85,
  "chargingStationId": "CP-NL-AMS-0042",
  "connectorId": "1",
  "evseId": "NL*ABC*E12345",
  "isAnomaly": true,
  "isIncident": false,
  "isRecurring": true,
  "sessionId": "sess-abc-001",
  "status": "active"
}
GET /v1/sessions/{session_id}

Get Session Detail

Get full session details including meter values, analysis result, and anomaly categories.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

session_id *
string Session Id

Response 200

sessionId *
string Session identifier
chargingStationId *
string Charging station identifier
connectorId
string | null Connector identifier within the charging station
evseId
string | null EVSE identifier (EU standard)
status *
string Session lifecycle status: pending → active → failed
isAnomaly
boolean | null Whether any anomaly was detected (null if pending)
anomalyScore
number | null Overall anomaly score (null if pending)
anomalyConfidence
number | null Overall model confidence (null if pending)
isIncident
boolean | null Confirmed incident (null if pending)
isRecurring
boolean | null Recurring pattern (null if pending)
anomalies
object[] Detected anomalies (empty if pending)
category *
string Anomaly classification category
score *
number Anomaly severity score (0.0 = normal, 1.0 = extreme)
bucketRange
object | null Affected meter value range (bucket indexes, null when not available)
startUnit *
integer Start bucket index (0-based, 15-second slot offset from session start)
endUnit *
integer End bucket index (inclusive, 15-second slot offset from session start)
timeRange
object | null Affected time range (start/end timestamps, null if not available)
startTimestamp
string | null Start of the anomaly time range
endTimestamp
string | null End of the anomaly time range
confidence *
number Model confidence in this detection (0.0–1.0)
analyzedAt
string | null Analysis timestamp (null if pending)
socReconstructed
boolean Whether SoC was reconstructed by SORC model
message
string | null Informational message about the analysis status (e.g. why inference was not performed)
stopReason
string | null OCPP stop reason (e.g. Local, Remote, EVDisconnected)
createdAt *
string Session creation timestamp (UTC)
meterValues *
object[] All meter readings received for this session
timestamp *
string UTC timestamp of the meter reading (OCPP MeterValues timestamp)
value *
number Measured value in the specified unit (0 to 10,000,000,000)
measurand
string | null OCPP measurand type (e.g. Energy.Active.Import.Register, Power.Active.Import, SoC)
unit
string | null OCPP unit of measure (e.g. kWh, kW, Percent, A, V)
phase
string | null OCPP phase (e.g. L1, L2, L3, L1-N)
location
string | null OCPP meter value location (e.g. Outlet, EV, Cable)
reconstructed
boolean True if value was reconstructed by SORC model
reconstructedSoc
object[] SoC points predicted by the SORC model when raw OCPP SoC was insufficient. Provided as a separate overlay; not part of meter_values used for inference.
timestamp *
string UTC timestamp matching the OCPP bucket
value *
number Predicted SoC in percent (0-100)
sorcConfidence
number | null Confidence of the SORC prediction (only set when reconstructed_soc is non-empty)
Response · 200 JSON
{
  "analyzedAt": "2026-02-27T10:31:02Z",
  "anomalies": [
    {
      "bucketRange": {
        "endUnit": 7,
        "startUnit": 4
      },
      "category": "KWH_DECREASE",
      "confidence": 0.92,
      "score": 0.87
    }
  ],
  "anomalyConfidence": 0.92,
  "anomalyScore": 0.85,
  "chargingStationId": "CP-NL-AMS-0042",
  "connectorId": "1",
  "evseId": "NL*ABC*E12345",
  "isAnomaly": true,
  "isIncident": false,
  "isRecurring": true,
  "sessionId": "sess-abc-001",
  "status": "active"
}
PUT /v1/sessions/{session_id}

Replace Session

Replace all meter values for a session. IR-372: session opened inline. Same rationale as ``create_session``. Deletes existing meter values and sets new ones. Requires at least 1 reading. If >= 3 meter values after replacement, CSAR-2 inference runs automatically.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

session_id *
string Session Id

Request Body

meterValues *
object[] Complete set of meter readings (replaces all previous)
timestamp *
string UTC timestamp of the meter reading (OCPP MeterValues timestamp)
value *
number Measured value in the specified unit (0 to 10,000,000,000)
measurand
string | null OCPP measurand type (e.g. Energy.Active.Import.Register, Power.Active.Import, SoC)
unit
string | null OCPP unit of measure (e.g. kWh, kW, Percent, A, V)
phase
string | null OCPP phase (e.g. L1, L2, L3, L1-N)
location
string | null OCPP meter value location (e.g. Outlet, EV, Cable)
reconstructed
boolean True if value was reconstructed by SORC model
metadata
object | null Optional client metadata to set/update
status
string | null Optional session status update (completed or invalid)
stopReason
string | null OCPP stop reason (e.g. Local, Remote, EVDisconnected)

Response 200

sessionId *
string Session identifier
chargingStationId *
string Charging station identifier
connectorId
string | null Connector identifier within the charging station
evseId
string | null EVSE identifier (EU standard)
status *
string Session status: pending, active, or failed
isAnomaly
boolean | null Whether any anomaly was detected (null if pending)
anomalyScore
number | null Overall anomaly score (null if pending)
anomalyConfidence
number | null Overall model confidence (null if pending)
isIncident
boolean | null Confirmed incident (null if pending)
isRecurring
boolean | null Recurring pattern (null if pending)
anomalies
object[] Detected anomalies (empty if pending)
category *
string Anomaly classification category
score *
number Anomaly severity score (0.0 = normal, 1.0 = extreme)
bucketRange
object | null Affected meter value range (bucket indexes, null when not available)
startUnit *
integer Start bucket index (0-based, 15-second slot offset from session start)
endUnit *
integer End bucket index (inclusive, 15-second slot offset from session start)
timeRange
object | null Affected time range (start/end timestamps, null if not available)
startTimestamp
string | null Start of the anomaly time range
endTimestamp
string | null End of the anomaly time range
confidence *
number Model confidence in this detection (0.0–1.0)
analyzedAt
string | null Analysis timestamp (null if pending)
socReconstructed
boolean Whether SoC was reconstructed by SORC model
message
string | null Informational message about the analysis status (e.g. why inference was not performed)
stopReason
string | null OCPP stop reason (e.g. Local, Remote, EVDisconnected)
createdAt
string | null Session creation timestamp (null if unavailable)
Request JSON
{
  "meterValues": [
    {
      "measurand": "Energy.Active.Import.Register",
      "timestamp": "2026-02-27T10:00:00Z",
      "unit": "kWh",
      "value": 0
    },
    {
      "measurand": "Energy.Active.Import.Register",
      "timestamp": "2026-02-27T10:15:00Z",
      "unit": "kWh",
      "value": 5.5
    },
    {
      "measurand": "Energy.Active.Import.Register",
      "timestamp": "2026-02-27T10:30:00Z",
      "unit": "kWh",
      "value": 11.1
    }
  ]
}
Response · 200 JSON
{
  "analyzedAt": "2026-02-27T10:31:02Z",
  "anomalies": [
    {
      "bucketRange": {
        "endUnit": 7,
        "startUnit": 4
      },
      "category": "KWH_DECREASE",
      "confidence": 0.92,
      "score": 0.87
    }
  ],
  "anomalyConfidence": 0.92,
  "anomalyScore": 0.85,
  "chargingStationId": "CP-NL-AMS-0042",
  "connectorId": "1",
  "evseId": "NL*ABC*E12345",
  "isAnomaly": true,
  "isIncident": false,
  "isRecurring": true,
  "sessionId": "sess-abc-001",
  "status": "active"
}
PATCH /v1/sessions/{session_id}

Update Session

Append meter values to an existing session (OCPI-like incremental push). IR-372: session opened inline. Same rationale as ``create_session``. Empty meter_values list = no changes, returns current state. If >= 3 accumulated meter values after append, CSAR-2 inference runs automatically.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

session_id *
string Session Id

Request Body

meterValues
object[] Meter readings to append to the session
timestamp *
string UTC timestamp of the meter reading (OCPP MeterValues timestamp)
value *
number Measured value in the specified unit (0 to 10,000,000,000)
measurand
string | null OCPP measurand type (e.g. Energy.Active.Import.Register, Power.Active.Import, SoC)
unit
string | null OCPP unit of measure (e.g. kWh, kW, Percent, A, V)
phase
string | null OCPP phase (e.g. L1, L2, L3, L1-N)
location
string | null OCPP meter value location (e.g. Outlet, EV, Cable)
reconstructed
boolean True if value was reconstructed by SORC model
metadata
object | null Optional client metadata to set/update
status
string | null Optional session status update (completed or invalid)
stopReason
string | null OCPP stop reason (e.g. Local, Remote, EVDisconnected)

Response 200

sessionId *
string Session identifier
chargingStationId *
string Charging station identifier
connectorId
string | null Connector identifier within the charging station
evseId
string | null EVSE identifier (EU standard)
status *
string Session status: pending, active, or failed
isAnomaly
boolean | null Whether any anomaly was detected (null if pending)
anomalyScore
number | null Overall anomaly score (null if pending)
anomalyConfidence
number | null Overall model confidence (null if pending)
isIncident
boolean | null Confirmed incident (null if pending)
isRecurring
boolean | null Recurring pattern (null if pending)
anomalies
object[] Detected anomalies (empty if pending)
category *
string Anomaly classification category
score *
number Anomaly severity score (0.0 = normal, 1.0 = extreme)
bucketRange
object | null Affected meter value range (bucket indexes, null when not available)
startUnit *
integer Start bucket index (0-based, 15-second slot offset from session start)
endUnit *
integer End bucket index (inclusive, 15-second slot offset from session start)
timeRange
object | null Affected time range (start/end timestamps, null if not available)
startTimestamp
string | null Start of the anomaly time range
endTimestamp
string | null End of the anomaly time range
confidence *
number Model confidence in this detection (0.0–1.0)
analyzedAt
string | null Analysis timestamp (null if pending)
socReconstructed
boolean Whether SoC was reconstructed by SORC model
message
string | null Informational message about the analysis status (e.g. why inference was not performed)
stopReason
string | null OCPP stop reason (e.g. Local, Remote, EVDisconnected)
createdAt
string | null Session creation timestamp (null if unavailable)
Request JSON
{
  "meterValues": [
    {
      "measurand": "Energy.Active.Import.Register",
      "timestamp": "2026-02-27T10:45:00Z",
      "unit": "kWh",
      "value": 16.5
    }
  ]
}
Response · 200 JSON
{
  "analyzedAt": "2026-02-27T10:31:02Z",
  "anomalies": [
    {
      "bucketRange": {
        "endUnit": 7,
        "startUnit": 4
      },
      "category": "KWH_DECREASE",
      "confidence": 0.92,
      "score": 0.87
    }
  ],
  "anomalyConfidence": 0.92,
  "anomalyScore": 0.85,
  "chargingStationId": "CP-NL-AMS-0042",
  "connectorId": "1",
  "evseId": "NL*ABC*E12345",
  "isAnomaly": true,
  "isIncident": false,
  "isRecurring": true,
  "sessionId": "sess-abc-001",
  "status": "active"
}
POST /v1/sessions/{session_id}/ask

Ask Session

Ask a natural language question about a specific session.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

session_id *
string Session Id

Request Body

question *
string Natural language question about the session
lang
string | null Response language (e.g. 'en', 'pl'). If omitted, LLM responds in question language.

Response 200

sessionId *
string Session identifier
answer *
string Answer to the question about this session
Request JSON
{
  "lang": "en",
  "question": "Why did the SoC drop unexpectedly?"
}
Response · 200 JSON
{
  "sessionId": "example",
  "answer": "example"
}
GET /v1/sessions/{session_id}/explain

Get Session Explanation

Return cached LLM explanation if available. Legacy CPMS frontend may request refresh.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

session_id *
string Session Id

Query Parameters

lang
string Lang
refresh
boolean Refresh
style
string Style

Response 200

Response · 200 JSON
{
  "sessionId": "example",
  "explanation": "example",
  "cached": false
}
POST /v1/sessions/{session_id}/explain

Explain Session

Get an LLM-generated explanation of session anomalies.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

session_id *
string Session Id

Request Body

Response 200

sessionId *
string Session identifier
explanation *
string Human-readable explanation of the detected anomalies
cached
boolean Whether this explanation was served from cache
Request JSON
{
  "lang": "en",
  "regenerate": false
}
Response · 200 JSON
{
  "sessionId": "example",
  "explanation": "example",
  "cached": false
}
POST /v1/sessions/batch

Submit Batch

Submit multiple sessions for batch analysis. Creates a batch record and enqueues background processing. Returns batch_id for polling via GET /sessions/batch/{batch_id}.

Headers

Authorization *
string Bearer token with embedded tenant context

Request Body

sessions *
object[] Sessions
sessionId *
string Client's unique session identifier. Used for upsert (find-or-create)
chargingStationId *
string Charging station identifier (EVSE location)
connectorId
string | null Connector identifier within the charging station
evseId
string | null EVSE identifier (EU standard)
meterValues
object[] Initial meter readings. Optional — session can be created empty and populated later via PATCH or PUT.
timestamp *
string UTC timestamp of the meter reading (OCPP MeterValues timestamp)
value *
number Measured value in the specified unit (0 to 10,000,000,000)
measurand
string | null OCPP measurand type (e.g. Energy.Active.Import.Register, Power.Active.Import, SoC)
unit
string | null OCPP unit of measure (e.g. kWh, kW, Percent, A, V)
phase
string | null OCPP phase (e.g. L1, L2, L3, L1-N)
location
string | null OCPP meter value location (e.g. Outlet, EV, Cable)
reconstructed
boolean True if value was reconstructed by SORC model
metadata
object | null Optional client metadata for the session
status
string | null Optional initial session status (active, pending, completed, or invalid)
stopReason
string | null OCPP stop reason (e.g. Local, Remote, EVDisconnected)

Response 200

batchId *
string Batchid
totalSessions *
integer Totalsessions
status *
string Processing status of a batch upload.
Request JSON
{
  "sessions": [
    {
      "chargingStationId": "CP-NL-AMS-0042",
      "connectorId": "1",
      "meterValues": [
        {
          "measurand": "Energy.Active.Import.Register",
          "timestamp": "2026-02-27T10:00:00Z",
          "unit": "kWh",
          "value": 0
        },
        {
          "measurand": "Power.Active.Import",
          "timestamp": "2026-02-27T10:00:00Z",
          "unit": "kW",
          "value": 0
        },
        {
          "measurand": "SoC",
          "timestamp": "2026-02-27T10:00:00Z",
          "unit": "Percent",
          "value": 80
        },
        {
          "measurand": "Energy.Active.Import.Register",
          "timestamp": "2026-02-27T10:15:00Z",
          "unit": "kWh",
          "value": 5.5
        },
        {
          "measurand": "Power.Active.Import",
          "timestamp": "2026-02-27T10:15:00Z",
          "unit": "kW",
          "value": 22
        },
        {
          "measurand": "SoC",
          "timestamp": "2026-02-27T10:15:00Z",
          "unit": "Percent",
          "value": 65
        },
        {
          "measurand": "Energy.Active.Import.Register",
          "timestamp": "2026-02-27T10:30:00Z",
          "unit": "kWh",
          "value": 11.1
        },
        {
          "measurand": "Power.Active.Import",
          "timestamp": "2026-02-27T10:30:00Z",
          "unit": "kW",
          "value": 22
        },
        {
          "measurand": "SoC",
          "timestamp": "2026-02-27T10:30:00Z",
          "unit": "Percent",
          "value": 50
        }
      ],
      "sessionId": "sess-abc-001"
    }
  ]
}
Response · 200 JSON
{
  "batchId": "example",
  "totalSessions": 0,
  "status": "pending"
}
GET /v1/sessions/batch/{batch_id}

Get Batch Status

Get batch processing status and results (paginated).

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

batch_id *
string Batch Id

Query Parameters

page
integer Page
pageSize
integer Pagesize

Response 200

batchId *
string Batchid
status *
string Processing status of a batch upload.
totalSessions *
integer Totalsessions
processedSessions *
integer Processedsessions
failedSessions *
integer Failedsessions
results *
object[] Results
sessionId *
string Session identifier
chargingStationId *
string Charging station identifier
connectorId
string | null Connector identifier within the charging station
evseId
string | null EVSE identifier (EU standard)
status *
string Session status: pending, active, or failed
isAnomaly
boolean | null Whether any anomaly was detected (null if pending)
anomalyScore
number | null Overall anomaly score (null if pending)
anomalyConfidence
number | null Overall model confidence (null if pending)
isIncident
boolean | null Confirmed incident (null if pending)
isRecurring
boolean | null Recurring pattern (null if pending)
anomalies
object[] Detected anomalies (empty if pending)
category *
string Anomaly classification category
score *
number Anomaly severity score (0.0 = normal, 1.0 = extreme)
bucketRange
object | null Affected meter value range (bucket indexes, null when not available)
timeRange
object | null Affected time range (start/end timestamps, null if not available)
confidence *
number Model confidence in this detection (0.0–1.0)
analyzedAt
string | null Analysis timestamp (null if pending)
socReconstructed
boolean Whether SoC was reconstructed by SORC model
message
string | null Informational message about the analysis status (e.g. why inference was not performed)
stopReason
string | null OCPP stop reason (e.g. Local, Remote, EVDisconnected)
createdAt
string | null Session creation timestamp (null if unavailable)
page *
integer Page
pageSize *
integer Pagesize
createdAt *
string Createdat
completedAt *
string | null Completedat
Response · 200 JSON
{
  "batchId": "example",
  "status": "pending",
  "totalSessions": 0,
  "processedSessions": 0,
  "failedSessions": 0,
  "results": [
    {
      "analyzedAt": "2026-02-27T10:31:02Z",
      "anomalies": [
        {
          "bucketRange": {
            "endUnit": 7,
            "startUnit": 4
          },
          "category": "KWH_DECREASE",
          "confidence": 0.92,
          "score": 0.87
        }
      ],
      "anomalyConfidence": 0.92,
      "anomalyScore": 0.85,
      "chargingStationId": "CP-NL-AMS-0042",
      "connectorId": "1",
      "evseId": "NL*ABC*E12345",
      "isAnomaly": true,
      "isIncident": false,
      "isRecurring": true,
      "sessionId": "sess-abc-001",
      "status": "active"
    }
  ],
  "page": 0,
  "pageSize": 0,
  "createdAt": "2026-01-01T00:00:00Z",
  "completedAt": "2026-01-01T00:00:00Z"
}
GET /v1/stations

List Stations

List tenant's charging stations with aggregated anomaly statistics. Reads from ``charging_stations_aggregated_mv`` materialized view (refreshed ~60 s) for pre-aggregated session/anomaly counts per station.

Headers

Authorization *
string Bearer token with embedded tenant context

Query Parameters

page
integer Page
pageSize
integer Pagesize
limit
integer Limit
ocpp_charging_station_id
string Filter by external station id
occurrenceFrom
string Last anomaly lower bound
occurrenceTo
string Last anomaly upper bound
sortByAnomalies
string Sort by total anomalies: asc or desc
sortByScore
string Sort by max anomaly score: asc or desc

Response 200

Response · 200 JSON
{
  "content": [
    {
      "aiScore": 0.91,
      "chargingStationId": "ST-NL-AMS-01",
      "id": "019c...",
      "lastAnomalyDate": "2026-02-27T09:45:00Z",
      "ocppChargingStationId": "ST-NL-AMS-01",
      "totalAnomalies": 7
    }
  ],
  "pagination": {
    "totalCount": 0,
    "page": 0,
    "size": 0
  }
}
GET /v1/stations/{charging_station_id}

Get Station Detail

Get station details: connectors, anomaly statistics, metadata. Uses ``charging_stations_aggregated_mv`` materialized view (refreshed ~60 s) for station-level aggregates.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

charging_station_id *
string Charging Station Id

Response 200

chargingStationId *
string Client-provided station identifier
connectors *
object[] Connectors at this station with per-connector statistics
connectorId *
string Connector identifier within the charging point
totalSessions *
integer Total charging sessions on this connector
anomalousSessions *
integer Sessions with detected anomalies on this connector
totalSessions *
integer Total charging sessions at this station
anomalousSessions *
integer Sessions with at least one detected anomaly
metadata
object | null Station metadata (address, operator, etc.) as provided by client
Response · 200 JSON
{
  "anomalousSessions": 7,
  "chargingStationId": "ST-NL-AMS-01",
  "connectors": [
    {
      "anomalousSessions": 3,
      "connectorId": "1",
      "totalSessions": 80
    },
    {
      "anomalousSessions": 4,
      "connectorId": "2",
      "totalSessions": 62
    }
  ],
  "metadata": {
    "address": "Keizersgracht 100, Amsterdam",
    "operator": "FastNed"
  },
  "totalSessions": 142
}
GET /v1/stations/{charging_station_id}/anomalies

List Station Anomalies

Get station-level anomaly history (SHADE detection results).

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

charging_station_id *
string Charging Station Id

Query Parameters

page
integer Page
pageSize
integer Pagesize
limit
integer Limit

Response 200

Response · 200 JSON
{
  "content": [
    {
      "inferenceId": "example",
      "isAnomaly": false,
      "anomalyScore": 0,
      "detectionDetails": {},
      "analyzedAt": "2026-01-01T00:00:00Z"
    }
  ],
  "pagination": {
    "totalCount": 0,
    "page": 0,
    "size": 0
  }
}
GET /v1/stations/{charging_station_id}/connectors

Get Station Connectors

Get station connectors with per-connector anomaly category breakdown.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

charging_station_id *
string Charging Station Id

Response 200

chargingStationId *
string Station identifier
connectors *
object[] Connectors with anomaly statistics
connectorId *
string Connector identifier
totalSessions *
integer Total sessions on this connector
anomalousSessions *
integer Anomalous sessions on this connector
anomalyCategories *
object Anomaly count per category (e.g. KWH_DECREASE: 2)
Response · 200 JSON
{
  "chargingStationId": "example",
  "connectors": [
    {
      "anomalousSessions": 3,
      "anomalyCategories": {
        "ENERGY_PIT": 1,
        "KWH_DECREASE": 2
      },
      "connectorId": "1",
      "totalSessions": 80
    }
  ]
}
GET /v1/stations/{charging_station_id}/energy

Get Station Energy

Get per-connector and aggregated energy timelines with SHADE anomaly markers.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

charging_station_id *
string Charging Station Id

Query Parameters

dateTo
string Dateto
anomalyId
string Anomalyid

Response 200

Response · 200 JSON
{
  "anomalyOccurrences": [
    "2026-04-05T22:30:00Z"
  ],
  "chargingStationId": "ST-NL-AMS-01",
  "energyConsumptionConnectors": [
    {
      "connectorId": "1",
      "energy": [
        {
          "energy": 5.1,
          "timestamp": "2026-04-05T17:00:00Z"
        }
      ]
    }
  ],
  "energyConsumptionStation": [
    {
      "energy": 0,
      "timestamp": "2026-04-05T17:00:00Z"
    },
    {
      "energy": 12.5,
      "timestamp": "2026-04-05T18:00:00Z"
    }
  ],
  "energyDelivered": 38
}
GET /v1/stations/{charging_station_id}/inference

Get Station Inference

Get latest SHADE inference result for a station.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

charging_station_id *
string Charging Station Id

Response 200

chargingStationId *
string Analyzed station identifier
isAnomaly *
boolean Whether a station-level anomaly was detected
anomalyScore *
number Station anomaly severity score (SHADE reconstruction error)
detectionDetails *
object SHADE detection breakdown (anomaly type, affected period, metrics)
analyzedAt *
string Analysis completion timestamp (UTC)
Response · 200 JSON
{
  "analyzedAt": "2026-02-27T12:00:00Z",
  "anomalyScore": 0.72,
  "chargingStationId": "ST-NL-AMS-01",
  "detectionDetails": {
    "actual_energy_kwh": 980.2,
    "affected_period": "2026-02-27",
    "anomaly_type": "energy_drop",
    "expected_energy_kwh": 1200
  },
  "isAnomaly": true
}
GET /v1/stations/{charging_station_id}/shade-overview

Get Shade Overview

Get SHADE station overview: cumulative energy timeline with anomaly markers.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

charging_station_id *
string Charging Station Id

Response 200

chargingStationId *
string Station identifier
dayScore *
number Overall day anomaly score
isAnomaly *
boolean Whether the station has active anomalies
energyTimeline *
object[] Cumulative kWh over the analysis day
timestamp *
string Point in time (UTC)
cumulativeKwh *
number Cumulative energy delivered up to this point (kWh)
anomalyMarkers *
object[] SHADE-detected anomaly time ranges
startMinute *
integer Minute offset from day start (0-1439)
timestamp *
string Absolute timestamp of the anomaly bucket (UTC)
score *
number Normalized anomaly score for this bucket (0-1)
analyzedAt *
string When the SHADE inference was run (UTC)
Response · 200 JSON
{
  "chargingStationId": "example",
  "dayScore": 0,
  "isAnomaly": false,
  "energyTimeline": [
    {
      "timestamp": "2026-01-01T00:00:00Z",
      "cumulativeKwh": 0
    }
  ],
  "anomalyMarkers": [
    {
      "startMinute": 0,
      "timestamp": "2026-01-01T00:00:00Z",
      "score": 0
    }
  ],
  "analyzedAt": "2026-01-01T00:00:00Z"
}
GET /v1/stations/lookup

Lookup Station Ids

Return distinct station IDs for filter dropdowns. Reads from the ``charging_stations`` base table (no MV dependency).

Headers

Authorization *
string Bearer token with embedded tenant context

Response 200

items *
string[] Distinct station identifiers for this tenant
Response · 200 JSON
{
  "items": [
    "example"
  ]
}
GET /v1/anomalies

List Anomalies

List individual anomalies with pagination and optional filters.

Headers

Authorization *
string Bearer token with embedded tenant context

Query Parameters

page
integer Page
pageSize
integer Pagesize
limit
integer Limit
anomalyType
string[] Filter by anomaly category
connectorId
string Filter by connector
chargingSessionId
string Filter by session
chargingPointId
string[] Filter by charging point(s)
evseId
string[] Filter by EVSE(s)
ocpp_charging_station_id
string Ocpp Charging Station Id
occurrenceFrom
string Detection date lower bound
occurrenceTo
string Detection date upper bound
updateFrom
string Last update date lower bound
updateTo
string Last update date upper bound
sortByScore
string Sort by score: asc or desc
anomalyIssuesStatus
string[] Filter by issue status(es)
assignedTo
string[] Filter by assignee email(s) (use 'me' for current user)

Response 200

Response · 200 JSON
{
  "content": [
    {
      "id": "example",
      "anomalyType": "example",
      "anomalyTypeId": "example",
      "aiRiskScore": 0,
      "connectorId": "example",
      "chargingPointId": "example",
      "ocppChargingStationId": "example",
      "evseId": "example",
      "chargingSessionId": "example",
      "dateOfAnomalyOccurrence": "example",
      "dateOfLastUpdate": "example",
      "issues": [
        {}
      ]
    }
  ],
  "pagination": {
    "totalCount": 0,
    "page": 0,
    "size": 0
  }
}
GET /v1/anomalies/connectors

List Anomaly Connectors

List connectors with anomalies, aggregated by connector.

Headers

Authorization *
string Bearer token with embedded tenant context

Query Parameters

page
integer Page
pageSize
integer Pagesize
limit
integer Limit
connectorId
string Filter by connector
anomalyType
string[] Filter by anomaly category
occurrenceFrom
string Detection date lower bound
occurrenceTo
string Detection date upper bound
sortBy
string Sort: count_asc, count_desc

Response 200

Response · 200 JSON
{
  "content": [
    {
      "id": "example",
      "connectorId": "example",
      "anomalyCount": 0,
      "chargingPointId": "example",
      "evseId": "example",
      "detectionDate": "example",
      "lastUpdate": "example",
      "anomalyTypes": [
        {}
      ]
    }
  ],
  "pagination": {
    "totalCount": 0,
    "page": 0,
    "size": 0
  }
}
PUT /v1/anomalies/issues/{issue_id}

Update Issue

Update an anomaly issue status and/or assignment.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

issue_id *
string Issue Id

Request Body

status *
string New issue status
assignedTo
string | null Email of the assignee

Response 200

Request JSON
{
  "status": "OPEN",
  "assignedTo": "example"
}
Response · 200 JSON
{
  "id": "example",
  "statusName": "example",
  "assignedTo": "example"
}
GET /v1/anomalies/sessions

List Anomaly Sessions

List sessions with anomalies, aggregated by session.

Headers

Authorization *
string Bearer token with embedded tenant context

Query Parameters

page
integer Page
pageSize
integer Pagesize
limit
integer Limit
anomalyType
string[] Filter by anomaly category
chargingSessionId
string Filter by session
occurrenceFrom
string Detection date lower bound
occurrenceTo
string Detection date upper bound
sortBy
string Sort: score_asc, score_desc, count_asc, count_desc

Response 200

Response · 200 JSON
{
  "content": [
    {
      "id": "example",
      "chargingSessionId": "example",
      "anomalyCount": 0,
      "detectionDate": "example",
      "lastUpdate": "example",
      "aiRiskScore": 0,
      "anomalyTypes": [
        {}
      ]
    }
  ],
  "pagination": {
    "totalCount": 0,
    "page": 0,
    "size": 0
  }
}
GET /v1/anomalies/sessions/{session_id}/categories/{category_id}/details

Get Anomaly Detail

Get full anomaly detail for a specific session and category.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

session_id *
string Session Id
category_id *
string Category Id

Response 200

Response · 200 JSON
{
  "sessionId": "example",
  "clientId": "example",
  "connectorId": "example",
  "chargingPointId": "example",
  "ocppChargingStationId": "example",
  "evseId": "example",
  "detectionLevel": "example",
  "meterValues": [
    {
      "timestamp": "example",
      "energy": 0,
      "stateOfCharge": 0,
      "power": 0
    }
  ],
  "currentRiskScore": 0,
  "firstDetectionDate": "example",
  "lastUpdateDate": "example",
  "anomalyCategory": {
    "id": "example",
    "name": "example",
    "description": "example",
    "maxScore": 0
  },
  "riskScoreTimeline": [
    {
      "timestamp": "example",
      "riskScore": 0
    }
  ],
  "anomalyPeriod": {
    "start": "example",
    "end": "example"
  },
  "anomalyPeriods": [
    {
      "start": "example",
      "end": "example"
    }
  ],
  "issues": [
    {
      "id": "example",
      "statusName": "example",
      "assignedTo": "example"
    }
  ]
}
GET /v1/models

List Models

List available models: base SaaS models + tenant's fine-tuned models.

Headers

Authorization *
string Bearer token with embedded tenant context

Response 200

models *
object[] Models
id *
string Id
name *
string Name
type *
string Type of ML model.
version *
string Version
isBase *
boolean Isbase
baseModel
string | null Basemodel
metrics *
object | null Metrics
status *
string Lifecycle status of an ML model.
createdAt *
string Createdat
Response · 200 JSON
{
  "models": [
    {
      "id": "example",
      "name": "example",
      "type": "csar_2",
      "version": "example",
      "isBase": false,
      "baseModel": "example",
      "metrics": {},
      "status": "active",
      "createdAt": "2026-01-01T00:00:00Z"
    }
  ]
}
GET /v1/models/{model_id}

Get Model Detail

Get model details: version, metrics, training date.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

model_id *
string Model Id

Response 200

id *
string Id
name *
string Name
type *
string Type of ML model.
version *
string Version
isBase *
boolean Isbase
baseModel
string | null Basemodel
metrics *
object | null Metrics
status *
string Lifecycle status of an ML model.
createdAt *
string Createdat
s3Path
string | null S3Path
description
string | null Description
Response · 200 JSON
{
  "id": "example",
  "name": "example",
  "type": "csar_2",
  "version": "example",
  "isBase": false,
  "baseModel": "example",
  "metrics": {},
  "status": "active",
  "createdAt": "2026-01-01T00:00:00Z",
  "s3Path": "example",
  "description": "example"
}
POST /v1/models/fine-tune

Start Fine Tune

Trigger model fine-tuning. Client specifies base model and training data source (previously submitted sessions or direct upload).

Headers

Authorization *
string Bearer token with embedded tenant context

Request Body

baseModelId *
string Basemodelid
name *
string Name
trainingConfig
object Trainingconfig
dataSource *
object FineTuneDataSource
type *
string 'sessions' or 'upload'
sessionFilter
object | null Sessionfilter

Response 200

jobId *
string Jobid
status *
string Processing status of a fine-tuning job.
baseModelId *
string Basemodelid
createdAt *
string Createdat
Request JSON
{
  "baseModelId": "example",
  "name": "example",
  "trainingConfig": {},
  "dataSource": {
    "type": "example",
    "sessionFilter": {}
  }
}
Response · 200 JSON
{
  "jobId": "example",
  "status": "queued",
  "baseModelId": "example",
  "createdAt": "2026-01-01T00:00:00Z"
}
GET /v1/models/fine-tune/{job_id}

Get Fine Tune Status

Get fine-tuning job status and progress.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

job_id *
string Job Id

Response 200

jobId *
string Jobid
status *
string Processing status of a fine-tuning job.
baseModelId *
string Basemodelid
resultModelId *
string | null Resultmodelid
config *
object Config
createdAt *
string Createdat
startedAt *
string | null Startedat
completedAt *
string | null Completedat
errorMessage *
string | null Errormessage
Response · 200 JSON
{
  "jobId": "example",
  "status": "queued",
  "baseModelId": "example",
  "resultModelId": "example",
  "config": {},
  "createdAt": "2026-01-01T00:00:00Z",
  "startedAt": "2026-01-01T00:00:00Z",
  "completedAt": "2026-01-01T00:00:00Z",
  "errorMessage": "example"
}
GET /v1/statistics

Get Statistics

Get tenant statistics summary: sessions, anomalies, stations. Queries charging session and inference tables to compute tenant-wide aggregated metrics.

Headers

Authorization *
string Bearer token with embedded tenant context

Query Parameters

occurrenceFrom
string Detection date lower bound
occurrenceTo
string Detection date upper bound

Response 200

activeAnomaliesCount *
integer Number of currently active (unresolved) anomalies
sessionsWithAnomaliesCount *
integer Sessions with at least one detected anomaly
connectorsWithAnomaliesCount *
integer Connectors with at least one detected anomaly
totalAnomaliesCount *
integer Total anomalies detected across all sessions
chargingStationsWithAnomaliesCount *
integer Charging stations with at least one anomalous session
uptimePercentage *
number Overall system uptime percentage
uptimeDelta *
number Change in uptime percentage compared to previous period
totalSessions *
integer Total charging sessions for this tenant
totalRevenue *
number Total revenue across all sessions
revenueAtRisk *
number Revenue associated with anomalous sessions
revenueLeakEstimate *
number Estimated revenue loss due to anomalies
dataQuality
object | null Data quality summary across 7d/30d/all ranges; None until first daemon run.
generatedAt *
string Generatedat
ranges *
object Three named time-window snapshots.
7d
object | null
30d
object | null
all
object | null
Response · 200 JSON
{
  "activeAnomaliesCount": 12,
  "chargingStationsWithAnomaliesCount": 4,
  "connectorsWithAnomaliesCount": 8,
  "revenueAtRisk": 1200,
  "revenueLeakEstimate": 380.25,
  "sessionsWithAnomaliesCount": 47,
  "totalAnomaliesCount": 134,
  "totalRevenue": 45200.5,
  "totalSessions": 1250,
  "uptimeDelta": 0.3,
  "uptimePercentage": 98.5
}
GET /v1/webhooks

List Webhooks

List tenant's webhooks (secrets are not included).

Headers

Authorization *
string Bearer token with embedded tenant context

Query Parameters

page
integer Page number (1-based)
pageSize
integer Items per page
events
string[] Filter by subscribed event type(s). Multi-select: webhooks subscribing to ANY of the given events match.

Response 200

content *
object[] Content
id *
string Id
url *
string Url
events *
string[] Events
description
string | null Description
enabled *
boolean Enabled
failureCount *
integer Failurecount
disabledAt
string | null Disabledat
createdAt
string | null Createdat
updatedAt
string | null Updatedat
pagination *
object Pagination metadata returned alongside list content.
totalCount *
integer Total number of items matching the query
page *
integer Current page number (1-based)
size *
integer Number of items per page
Response · 200 JSON
{
  "content": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "url": "example",
      "events": [
        {}
      ],
      "description": "example",
      "enabled": false,
      "failureCount": 0,
      "disabledAt": "2026-01-01T00:00:00Z",
      "createdAt": "2026-01-01T00:00:00Z",
      "updatedAt": "2026-01-01T00:00:00Z"
    }
  ],
  "pagination": {
    "totalCount": 0,
    "page": 0,
    "size": 0
  }
}
POST /v1/webhooks

Create Webhook

Register a new webhook. Secret is returned only once.

Headers

Authorization *
string Bearer token with embedded tenant context

Request Body

url *
string Webhook target URL (must be HTTPS)
events *
string[] Event types to subscribe to
description
string | null Optional description

Response 200

id *
string Id
url *
string Url
events *
string[] Events
description
string | null Description
enabled *
boolean Enabled
failureCount *
integer Failurecount
disabledAt
string | null Disabledat
createdAt
string | null Createdat
updatedAt
string | null Updatedat
secret *
string Secret
Request JSON
{
  "url": "example",
  "events": [
    "example"
  ],
  "description": "example"
}
Response · 200 JSON
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "url": "example",
  "events": [
    "example"
  ],
  "description": "example",
  "enabled": false,
  "failureCount": 0,
  "disabledAt": "2026-01-01T00:00:00Z",
  "createdAt": "2026-01-01T00:00:00Z",
  "updatedAt": "2026-01-01T00:00:00Z",
  "secret": "example"
}
GET /v1/webhooks/{webhook_id}

Get Webhook

Get webhook details with recent delivery history.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

webhook_id *
string Webhook Id

Response 200

id *
string Id
url *
string Url
events *
string[] Events
description
string | null Description
enabled *
boolean Enabled
failureCount *
integer Failurecount
disabledAt
string | null Disabledat
createdAt
string | null Createdat
updatedAt
string | null Updatedat
recentDeliveries
object[] Recentdeliveries
id *
string Id
eventType *
string Eventtype
status *
string Status
httpStatus
integer | null Httpstatus
attemptCount *
integer Attemptcount
createdAt
string | null Createdat
completedAt
string | null Completedat
Response · 200 JSON
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "url": "example",
  "events": [
    "example"
  ],
  "description": "example",
  "enabled": false,
  "failureCount": 0,
  "disabledAt": "2026-01-01T00:00:00Z",
  "createdAt": "2026-01-01T00:00:00Z",
  "updatedAt": "2026-01-01T00:00:00Z",
  "recentDeliveries": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "eventType": "example",
      "status": "example",
      "httpStatus": 0,
      "attemptCount": 0,
      "createdAt": "2026-01-01T00:00:00Z",
      "completedAt": "2026-01-01T00:00:00Z"
    }
  ]
}
PATCH /v1/webhooks/{webhook_id}

Update Webhook

Update webhook URL, events, or enabled state.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

webhook_id *
string Webhook Id

Request Body

url
string | null Url
events
string[] | null Events
description
string | null Description
enabled
boolean | null Enabled

Response 200

id *
string Id
url *
string Url
events *
string[] Events
description
string | null Description
enabled *
boolean Enabled
failureCount *
integer Failurecount
disabledAt
string | null Disabledat
createdAt
string | null Createdat
updatedAt
string | null Updatedat
Request JSON
{
  "url": "example",
  "events": [
    "example"
  ],
  "description": "example",
  "enabled": false
}
Response · 200 JSON
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "url": "example",
  "events": [
    "example"
  ],
  "description": "example",
  "enabled": false,
  "failureCount": 0,
  "disabledAt": "2026-01-01T00:00:00Z",
  "createdAt": "2026-01-01T00:00:00Z",
  "updatedAt": "2026-01-01T00:00:00Z"
}
DELETE /v1/webhooks/{webhook_id}

Delete Webhook

Delete a webhook and all its delivery records.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

webhook_id *
string Webhook Id

Response 200

Response · 200 JSON
POST /v1/webhooks/{webhook_id}/rotate-secret

Rotate Secret

Rotate webhook secret. Old secret valid for 24h grace period.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

webhook_id *
string Webhook Id

Response 200

id *
string Id
url *
string Url
events *
string[] Events
description
string | null Description
enabled *
boolean Enabled
failureCount *
integer Failurecount
disabledAt
string | null Disabledat
createdAt
string | null Createdat
updatedAt
string | null Updatedat
secret *
string Secret
Response · 200 JSON
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "url": "example",
  "events": [
    "example"
  ],
  "description": "example",
  "enabled": false,
  "failureCount": 0,
  "disabledAt": "2026-01-01T00:00:00Z",
  "createdAt": "2026-01-01T00:00:00Z",
  "updatedAt": "2026-01-01T00:00:00Z",
  "secret": "example"
}
POST /v1/webhooks/{webhook_id}/test

Test Webhook

Send a test event to the webhook URL.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

webhook_id *
string Webhook Id

Response 200

Response · 200 JSON
{}
GET /v1/api-keys

List Api Keys

List all API keys for the current tenant.

Headers

Authorization *
string Bearer token with embedded tenant context

Response 200

items *
object[] Items
id *
string Id
name *
string Name
description *
string Description
tenantId *
string Tenantid
createdAt *
string Createdat
expiresAt *
string Expiresat
lastUsedAt *
string | null Lastusedat
revokedAt *
string | null Revokedat
Response · 200 JSON
{
  "items": [
    {
      "id": "example",
      "name": "example",
      "description": "example",
      "tenantId": "example",
      "createdAt": "2026-01-01T00:00:00Z",
      "expiresAt": "2026-01-01T00:00:00Z",
      "lastUsedAt": "2026-01-01T00:00:00Z",
      "revokedAt": "2026-01-01T00:00:00Z"
    }
  ]
}
POST /v1/api-keys

Create Api Key

Create a new API key for the tenant. Returns the full key only once. IR-379: handler manages DB sessions itself rather than holding one across every Stripe HTTP round-trip, and every Stripe call is dispatched via ``run_in_threadpool`` so the worker's event loop is not blocked during the urllib3 round-trip. ``ensure_stripe_customer`` and ``create_setup_session`` still hold a session for one Stripe call each (BillingService boundary refactor is tracked separately) but ``list_payment_methods`` — the call that runs on every request — no longer pins a pool slot. Each phase that re-acquires a session re-verifies ``BillingAccount.stripe_customer_id`` and the user→tenant mapping (strict TOCTOU) so a concurrent customer rotation or admin revocation between phases fails the request instead of silently issuing a key against stale state.

Headers

Authorization *
string Bearer token with embedded tenant context

Request Body

name *
string Name
description
string Description

Response 200

id *
string Id
name *
string Name
key *
string Key
tenantId *
string Tenantid
expiresAt *
string Expiresat
createdAt *
string Createdat
Request JSON
{
  "name": "example",
  "description": "example"
}
Response · 200 JSON
{
  "id": "example",
  "name": "example",
  "key": "example",
  "tenantId": "example",
  "expiresAt": "2026-01-01T00:00:00Z",
  "createdAt": "2026-01-01T00:00:00Z"
}
DELETE /v1/api-keys/{key_id}

Revoke Api Key

Revoke an API key.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

key_id *
string Key Id

Response 200

Response · 200 JSON
GET /v1/organization

Get Organization

Get organization details for the current tenant.

Headers

Authorization *
string Bearer token with embedded tenant context

Response 200

id *
string Id
tenantId *
string Tenantid
name *
string Name
phone
string | null Phone
address
string | null Address
taxIdType
string | null Taxidtype
taxIdValue
string | null Taxidvalue
createdAt *
string Createdat
updatedAt
string | null Updatedat
Response · 200 JSON
{
  "id": "example",
  "tenantId": "example",
  "name": "example",
  "phone": "example",
  "address": "example",
  "taxIdType": "example",
  "taxIdValue": "example",
  "createdAt": "2026-01-01T00:00:00Z",
  "updatedAt": "2026-01-01T00:00:00Z"
}
PUT /v1/organization

Update Organization

Create or update organization details. Admin only. For open signup users (tenant_id=None): provisions org, billing, subscription, and tenant mapping, then refreshes session claims. For existing tenants: updates org fields. On first creation, also provisions billing.

Headers

Authorization *
string Bearer token with embedded tenant context

Request Body

name *
string Name
phone
string | null Phone
address
string | null Address
taxIdType
string | null Taxidtype
taxIdValue
string | null Taxidvalue

Response 200

id *
string Id
tenantId *
string Tenantid
name *
string Name
phone
string | null Phone
address
string | null Address
taxIdType
string | null Taxidtype
taxIdValue
string | null Taxidvalue
createdAt *
string Createdat
updatedAt
string | null Updatedat
Request JSON
{
  "name": "example",
  "phone": "example",
  "address": "example",
  "taxIdType": "example",
  "taxIdValue": "example"
}
Response · 200 JSON
{
  "id": "example",
  "tenantId": "example",
  "name": "example",
  "phone": "example",
  "address": "example",
  "taxIdType": "example",
  "taxIdValue": "example",
  "createdAt": "2026-01-01T00:00:00Z",
  "updatedAt": "2026-01-01T00:00:00Z"
}
GET /v1/members

List Members

List all members and pending invitations for the current tenant. Pending invitations are only visible to admin and super_admin callers. IR-379: a single DB session reads mappings and invitations, snapshots every field needed downstream into plain dataclasses, and is closed before any SuperTokens HTTP fan-out. Holding the session through ``asyncio.gather(N × SuperTokens)`` was the dashboard's largest pool-pin under load.

Headers

Authorization *
string Bearer token with embedded tenant context

Response 200

members *
object[] Members
userId *
string Userid
email *
string Email
role *
string Role
status *
string Status
joinedAt
string | null Joinedat
invitedAt
string | null Invitedat
expiresAt
string | null Expiresat
invitedBy
string | null Invitedby
invitationId
string | null Invitationid
Response · 200 JSON
{
  "members": [
    {
      "userId": "example",
      "email": "example",
      "role": "example",
      "status": "active",
      "joinedAt": "2026-01-01T00:00:00Z",
      "invitedAt": "2026-01-01T00:00:00Z",
      "expiresAt": "2026-01-01T00:00:00Z",
      "invitedBy": "example",
      "invitationId": "example"
    }
  ]
}
DELETE /v1/members/{user_id}

Remove Member

Remove a member from the tenant. Admin only.

Headers

Authorization *
string Bearer token with embedded tenant context

Path Parameters

user_id *
string User Id

Response 200

Response · 200 JSON
Talk to us

Register your interest today

Registration opens soon. We'll be in touch within a few hours to demonstrate our models.

By submitting, you agree to our Privacy Policy.