EBXv1

API reference

Control Tests

Endpoints tagged “Control Tests” in the API specification.

9 endpoints
GET/v1/assets/{asset_id}/betriebsfahrt

Betriebsfahrt status of the asset

dispatch.read

Required scopes: dispatch.read

Whether a Betriebsfahrt can be driven on this asset outside an onboarding, which preconditions still fail, and the session being worked on.

Path parameters

asset_idREQUIRED
stringAsset identifier, e.g. DE_50HZ_WEM_PAS_1.
Example value
curl "https://api.ebx.energy/v1/assets/DE_BESS_01/betriebsfahrt" \
  -H "Authorization: Bearer $EBX_TOKEN"
Example response200
{
  "enabled": false,
  "server_now": "2026-10-22T20:30:00Z",
  "preconditions": [
    {
      "key": "<string>",
      "label": "<string>",
      "status": "ok",
      "detail": "<string>"
    }
  ],
  "can_create_session": false,
  "dry_run_allowed": false,
  "default_capacity_mw": "<string>",
  "default_planned_start": "2026-10-22T20:30:00Z",
  "session": {
    "id": "<string>",
    "onboarding_id": "<string>",
    "purpose": "onboarding",
    "asset_id": "<string>",
    "status": "draft",
    "execution_mode": "real",
    "supersedes_session_id": "<string>",
    "parameters": {
      "first_direction": "positive",
      "single_direction": false,
      "extended_stroke_minutes": 0,
      "extended_stroke_min_minutes": 0,
      "extended_stroke_max_minutes": 0,
      "second_run_extended_stroke_minutes": 0,
      "capacity_mw": {
        "positive": "<string>",
        "negative": "<string>"
      },
      "products": {
        "positive": [
          "<string>"
        ],
        "negative": [
          "<string>"
        ]
      },
      "product_capacity_mw": "<string>",
      "usable_energy_mwh": "<string>",
      "energy_safety_margin": "<string>",
      "energy_per_run_mwh": {
        "positive": "<string>",
        "negative": "<string>"
      },
      "soc_energy_margin": "0.05",
      "ramp_mw_per_s": {
        "positive": "<string>",
        "negative": "<string>"
      },
      "fcr_ramp_required_mw_per_s": {
        "positive": "<string>",
        "negative": "<string>"
      },
      "measurement_point": "<string>",
      "retention_minutes": 0,
      "stroke_minutes": 0,
      "stated_products": [
        "<string>"
      ],
      "stated_capacity_mw": "<string>"
    },
    "findings": [
      {
        "code": "<string>",
        "severity": "blocker",
        "message": "<string>"
      }
    ],
    "planned_start": "2026-10-22T20:30:00Z",
    "planned_end": "2026-10-22T20:30:00Z",
    "plan_sha256": "<string>",
    "plan": "<string>",
    "runs": [
      {
        "index": 0,
        "direction": "positive",
        "products": [
          "<string>"
        ],
        "requested_capacity_mw": "<string>",
        "phases": [
          {
            "index": 0,
            "kind": "retention",
            "start": "2026-10-22T20:30:00Z",
            "end": "2026-10-22T20:30:00Z",
            "setpoint_mw": "<string>",
            "window_id": "<string>",
            "actual_start": "2026-10-22T20:30:00Z",
            "actual_end": "2026-10-22T20:30:00Z"
          }
        ],
        "status": "pending",
        "follow_checks": [
          {
            "phase_index": 0,
            "checked_at": "2026-10-22T20:30:00Z",
            "expected_mw": "<string>",
            "measured_mw": "<string>",
            "passed": false,
            "detail": "<string>"
          }
        ],
        "proofs": "<string>",
        "workbooks": "<string>",
        "uploads": "<string>",
        "verdicts": "<string>",
        "overrides": [
          {
            "product": "<string>",
            "reason": "<string>",
            "by_user_id": "<string>",
            "by_user_name": "<string>",
            "at": "2026-10-22T20:30:00Z"
          }
        ],
        "error": "<string>",
        "actual_start": "2026-10-22T20:30:00Z",
        "actual_end": "2026-10-22T20:30:00Z"
      }
    ],
    "driver": {
      "request_id": "<string>",
      "run_id": "<string>",
      "status": "<string>",
      "journal_written_at": "2026-10-22T20:30:00Z",
      "tracking_source": "<string>",
      "events": [
        "<string>"
      ]
    },
    "progress": {
      "current_run_index": 0,
      "current_phase_index": 0,
      "confidence": "confirmed",
      "remaining_seconds": 0
    },
    "actual_start": "2026-10-22T20:30:00Z",
    "actual_end": "2026-10-22T20:30:00Z",
    "confirmed_by_user_name": "<string>",
    "manual_zero_offered": false,
    "manual_action_required": "<string>",
    "handoff_at": "2026-10-22T20:30:00Z",
    "alarms": [
      {
        "rule_id": "TELEMETRY-001",
        "severity": "INFO",
        "message": "<string>",
        "opened_at": "2026-10-22T20:30:00Z",
        "resolved_at": "2026-10-22T20:30:00Z"
      }
    ],
    "state_of_charge": {
      "key": "<string>",
      "label": "<string>",
      "status": "ok",
      "detail": "<string>"
    },
    "confirmed_at": "2026-10-22T20:30:00Z",
    "aborted_at": "2026-10-22T20:30:00Z",
    "abort_reason": "<string>",
    "last_error": "<string>",
    "last_error_at": "2026-10-22T20:30:00Z",
    "row_version": 0,
    "created_at": "2026-10-22T20:30:00Z",
    "updated_at": "2026-10-22T20:30:00Z"
  },
  "history_count": 0
}
Can raise
  • 401no valid token
  • 403scope missing
  • 404unknown or not visible
  • 429rate limited
ALL CODES →
GET/v1/assets/{asset_id}/betriebsfahrt/sessions

Betriebsfahrt history of the asset

dispatch.read

Required scopes: dispatch.read

The asset's earlier standalone sessions, newest first, superseded and ended ones included. The session at hand is not among them: it is the status document's.

Path parameters

asset_idREQUIRED
stringAsset identifier, e.g. DE_50HZ_WEM_PAS_1.
Example value
curl "https://api.ebx.energy/v1/assets/DE_BESS_01/betriebsfahrt/sessions" \
  -H "Authorization: Bearer $EBX_TOKEN"
Example response200
[
  {
    "id": "<string>",
    "onboarding_id": "<string>",
    "purpose": "onboarding",
    "asset_id": "<string>",
    "status": "draft",
    "execution_mode": "real",
    "supersedes_session_id": "<string>",
    "parameters": {
      "first_direction": "positive",
      "single_direction": false,
      "extended_stroke_minutes": 0,
      "extended_stroke_min_minutes": 0,
      "extended_stroke_max_minutes": 0,
      "second_run_extended_stroke_minutes": 0,
      "capacity_mw": {
        "positive": "<string>",
        "negative": "<string>"
      },
      "products": {
        "positive": [
          "<string>"
        ],
        "negative": [
          "<string>"
        ]
      },
      "product_capacity_mw": "<string>",
      "usable_energy_mwh": "<string>",
      "energy_safety_margin": "<string>",
      "energy_per_run_mwh": {
        "positive": "<string>",
        "negative": "<string>"
      },
      "soc_energy_margin": "0.05",
      "ramp_mw_per_s": {
        "positive": "<string>",
        "negative": "<string>"
      },
      "fcr_ramp_required_mw_per_s": {
        "positive": "<string>",
        "negative": "<string>"
      },
      "measurement_point": "<string>",
      "retention_minutes": 0,
      "stroke_minutes": 0,
      "stated_products": [
        "<string>"
      ],
      "stated_capacity_mw": "<string>"
    },
    "findings": [
      {
        "code": "<string>",
        "severity": "blocker",
        "message": "<string>"
      }
    ],
    "planned_start": "2026-10-22T20:30:00Z",
    "planned_end": "2026-10-22T20:30:00Z",
    "plan_sha256": "<string>",
    "plan": "<string>",
    "runs": [
      {
        "index": 0,
        "direction": "positive",
        "products": [
          "<string>"
        ],
        "requested_capacity_mw": "<string>",
        "phases": [
          {
            "index": 0,
            "kind": "retention",
            "start": "2026-10-22T20:30:00Z",
            "end": "2026-10-22T20:30:00Z",
            "setpoint_mw": "<string>",
            "window_id": "<string>",
            "actual_start": "2026-10-22T20:30:00Z",
            "actual_end": "2026-10-22T20:30:00Z"
          }
        ],
        "status": "pending",
        "follow_checks": [
          {
            "phase_index": 0,
            "checked_at": "2026-10-22T20:30:00Z",
            "expected_mw": "<string>",
            "measured_mw": "<string>",
            "passed": false,
            "detail": "<string>"
          }
        ],
        "proofs": "<string>",
        "workbooks": "<string>",
        "uploads": "<string>",
        "verdicts": "<string>",
        "overrides": [
          {
            "product": "<string>",
            "reason": "<string>",
            "by_user_id": "<string>",
            "by_user_name": "<string>",
            "at": "2026-10-22T20:30:00Z"
          }
        ],
        "error": "<string>",
        "actual_start": "2026-10-22T20:30:00Z",
        "actual_end": "2026-10-22T20:30:00Z"
      }
    ],
    "driver": {
      "request_id": "<string>",
      "run_id": "<string>",
      "status": "<string>",
      "journal_written_at": "2026-10-22T20:30:00Z",
      "tracking_source": "<string>",
      "events": [
        "<string>"
      ]
    },
    "progress": {
      "current_run_index": 0,
      "current_phase_index": 0,
      "confidence": "confirmed",
      "remaining_seconds": 0
    },
    "actual_start": "2026-10-22T20:30:00Z",
    "actual_end": "2026-10-22T20:30:00Z",
    "confirmed_by_user_name": "<string>",
    "manual_zero_offered": false,
    "manual_action_required": "<string>",
    "handoff_at": "2026-10-22T20:30:00Z",
    "alarms": [
      {
        "rule_id": "TELEMETRY-001",
        "severity": "INFO",
        "message": "<string>",
        "opened_at": "2026-10-22T20:30:00Z",
        "resolved_at": "2026-10-22T20:30:00Z"
      }
    ],
    "state_of_charge": {
      "key": "<string>",
      "label": "<string>",
      "status": "ok",
      "detail": "<string>"
    },
    "confirmed_at": "2026-10-22T20:30:00Z",
    "aborted_at": "2026-10-22T20:30:00Z",
    "abort_reason": "<string>",
    "last_error": "<string>",
    "last_error_at": "2026-10-22T20:30:00Z",
    "row_version": 0,
    "created_at": "2026-10-22T20:30:00Z",
    "updated_at": "2026-10-22T20:30:00Z"
  }
]
Can raise
  • 401no valid token
  • 403scope missing
  • 404unknown or not visible
  • 429rate limited
ALL CODES →
POST/v1/assets/{asset_id}/betriebsfahrt/sessions

Plan a Betriebsfahrt on the asset

dispatch.write

Required scopes: dispatch.write

Generates a draft from the products and the power the operator states: one run per direction the products lie in, each with three retention phases, two 15-minute delivery strokes and an extended third stroke sized from the asset's usable energy. Replaces an existing draft. Nothing reaches the asset until the session is confirmed.

Path parameters

asset_idREQUIRED
stringAsset identifier, e.g. DE_50HZ_WEM_PAS_1.

Request body · required

productsREQUIRED
array[enum]The products the workbooks are for. The directions driven are the ones these lie in: name only positive products and the drive is one run.
capacity_mw
number | stringThe power the recording steps to, in MW; defaults to the asset's usable power. Above the usable power the plan is refused.
first_direction
enumpositivenegativeDirection of the first run: positive (discharge) needs the run's energy plus the margin in the battery, negative (charge) that much room. Default: the order the energy favours.
extended_stroke_minutes
integerThe first run's third delivery stroke, a multiple of 15 min; default the longest the usable energy allows.
planned_start
string<date-time>UTC start of run 1 on a quarter hour; defaults to the next quarter hour after the submission lead time.
execution_mode
enumrealdry_run
Example value
curl -X POST "https://api.ebx.energy/v1/assets/DE_BESS_01/betriebsfahrt/sessions" \
  -H "Authorization: Bearer $EBX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"products":["fcr_positive"],"capacity_mw":0,"first_direction":"positive","extended_stroke_minutes":0,"planned_start":"2026-10-22T20:30:00Z","execution_mode":"real"}'
Example response201
{
  "id": "<string>",
  "onboarding_id": "<string>",
  "purpose": "onboarding",
  "asset_id": "<string>",
  "status": "draft",
  "execution_mode": "real",
  "supersedes_session_id": "<string>",
  "parameters": {
    "first_direction": "positive",
    "single_direction": false,
    "extended_stroke_minutes": 0,
    "extended_stroke_min_minutes": 0,
    "extended_stroke_max_minutes": 0,
    "second_run_extended_stroke_minutes": 0,
    "capacity_mw": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "products": {
      "positive": [
        "<string>"
      ],
      "negative": [
        "<string>"
      ]
    },
    "product_capacity_mw": "<string>",
    "usable_energy_mwh": "<string>",
    "energy_safety_margin": "<string>",
    "energy_per_run_mwh": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "soc_energy_margin": "0.05",
    "ramp_mw_per_s": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "fcr_ramp_required_mw_per_s": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "measurement_point": "<string>",
    "retention_minutes": 0,
    "stroke_minutes": 0,
    "stated_products": [
      "<string>"
    ],
    "stated_capacity_mw": "<string>"
  },
  "findings": [
    {
      "code": "<string>",
      "severity": "blocker",
      "message": "<string>"
    }
  ],
  "planned_start": "2026-10-22T20:30:00Z",
  "planned_end": "2026-10-22T20:30:00Z",
  "plan_sha256": "<string>",
  "plan": "<string>",
  "runs": [
    {
      "index": 0,
      "direction": "positive",
      "products": [
        "<string>"
      ],
      "requested_capacity_mw": "<string>",
      "phases": [
        {
          "index": 0,
          "kind": "retention",
          "start": "2026-10-22T20:30:00Z",
          "end": "2026-10-22T20:30:00Z",
          "setpoint_mw": "<string>",
          "window_id": "<string>",
          "actual_start": "2026-10-22T20:30:00Z",
          "actual_end": "2026-10-22T20:30:00Z"
        }
      ],
      "status": "pending",
      "follow_checks": [
        {
          "phase_index": 0,
          "checked_at": "2026-10-22T20:30:00Z",
          "expected_mw": "<string>",
          "measured_mw": "<string>",
          "passed": false,
          "detail": "<string>"
        }
      ],
      "proofs": "<string>",
      "workbooks": "<string>",
      "uploads": "<string>",
      "verdicts": "<string>",
      "overrides": [
        {
          "product": "<string>",
          "reason": "<string>",
          "by_user_id": "<string>",
          "by_user_name": "<string>",
          "at": "2026-10-22T20:30:00Z"
        }
      ],
      "error": "<string>",
      "actual_start": "2026-10-22T20:30:00Z",
      "actual_end": "2026-10-22T20:30:00Z"
    }
  ],
  "driver": {
    "request_id": "<string>",
    "run_id": "<string>",
    "status": "<string>",
    "journal_written_at": "2026-10-22T20:30:00Z",
    "tracking_source": "<string>",
    "events": [
      "<string>"
    ]
  },
  "progress": {
    "current_run_index": 0,
    "current_phase_index": 0,
    "confidence": "confirmed",
    "remaining_seconds": 0
  },
  "actual_start": "2026-10-22T20:30:00Z",
  "actual_end": "2026-10-22T20:30:00Z",
  "confirmed_by_user_name": "<string>",
  "manual_zero_offered": false,
  "manual_action_required": "<string>",
  "handoff_at": "2026-10-22T20:30:00Z",
  "alarms": [
    {
      "rule_id": "TELEMETRY-001",
      "severity": "INFO",
      "message": "<string>",
      "opened_at": "2026-10-22T20:30:00Z",
      "resolved_at": "2026-10-22T20:30:00Z"
    }
  ],
  "state_of_charge": {
    "key": "<string>",
    "label": "<string>",
    "status": "ok",
    "detail": "<string>"
  },
  "confirmed_at": "2026-10-22T20:30:00Z",
  "aborted_at": "2026-10-22T20:30:00Z",
  "abort_reason": "<string>",
  "last_error": "<string>",
  "last_error_at": "2026-10-22T20:30:00Z",
  "row_version": 0,
  "created_at": "2026-10-22T20:30:00Z",
  "updated_at": "2026-10-22T20:30:00Z"
}
Can raise
  • 400malformed request
  • 401no valid token
  • 403scope missing
  • 404unknown or not visible
  • 409state conflict
  • 422validation failed
  • 429rate limited
ALL CODES →
GET/v1/assets/{asset_id}/betriebsfahrt/sessions/{session_id}

Get one standalone Betriebsfahrt session

dispatch.read

Required scopes: dispatch.read

Path parameters

asset_idREQUIRED
stringAsset identifier, e.g. DE_50HZ_WEM_PAS_1.
session_idREQUIRED
string<uuid>Betriebsfahrt session identifier from the status response.
Example value
curl "https://api.ebx.energy/v1/assets/DE_BESS_01/betriebsfahrt/sessions/00000000-0000-0000-0000-000000000000" \
  -H "Authorization: Bearer $EBX_TOKEN"
Example response200
{
  "id": "<string>",
  "onboarding_id": "<string>",
  "purpose": "onboarding",
  "asset_id": "<string>",
  "status": "draft",
  "execution_mode": "real",
  "supersedes_session_id": "<string>",
  "parameters": {
    "first_direction": "positive",
    "single_direction": false,
    "extended_stroke_minutes": 0,
    "extended_stroke_min_minutes": 0,
    "extended_stroke_max_minutes": 0,
    "second_run_extended_stroke_minutes": 0,
    "capacity_mw": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "products": {
      "positive": [
        "<string>"
      ],
      "negative": [
        "<string>"
      ]
    },
    "product_capacity_mw": "<string>",
    "usable_energy_mwh": "<string>",
    "energy_safety_margin": "<string>",
    "energy_per_run_mwh": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "soc_energy_margin": "0.05",
    "ramp_mw_per_s": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "fcr_ramp_required_mw_per_s": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "measurement_point": "<string>",
    "retention_minutes": 0,
    "stroke_minutes": 0,
    "stated_products": [
      "<string>"
    ],
    "stated_capacity_mw": "<string>"
  },
  "findings": [
    {
      "code": "<string>",
      "severity": "blocker",
      "message": "<string>"
    }
  ],
  "planned_start": "2026-10-22T20:30:00Z",
  "planned_end": "2026-10-22T20:30:00Z",
  "plan_sha256": "<string>",
  "plan": "<string>",
  "runs": [
    {
      "index": 0,
      "direction": "positive",
      "products": [
        "<string>"
      ],
      "requested_capacity_mw": "<string>",
      "phases": [
        {
          "index": 0,
          "kind": "retention",
          "start": "2026-10-22T20:30:00Z",
          "end": "2026-10-22T20:30:00Z",
          "setpoint_mw": "<string>",
          "window_id": "<string>",
          "actual_start": "2026-10-22T20:30:00Z",
          "actual_end": "2026-10-22T20:30:00Z"
        }
      ],
      "status": "pending",
      "follow_checks": [
        {
          "phase_index": 0,
          "checked_at": "2026-10-22T20:30:00Z",
          "expected_mw": "<string>",
          "measured_mw": "<string>",
          "passed": false,
          "detail": "<string>"
        }
      ],
      "proofs": "<string>",
      "workbooks": "<string>",
      "uploads": "<string>",
      "verdicts": "<string>",
      "overrides": [
        {
          "product": "<string>",
          "reason": "<string>",
          "by_user_id": "<string>",
          "by_user_name": "<string>",
          "at": "2026-10-22T20:30:00Z"
        }
      ],
      "error": "<string>",
      "actual_start": "2026-10-22T20:30:00Z",
      "actual_end": "2026-10-22T20:30:00Z"
    }
  ],
  "driver": {
    "request_id": "<string>",
    "run_id": "<string>",
    "status": "<string>",
    "journal_written_at": "2026-10-22T20:30:00Z",
    "tracking_source": "<string>",
    "events": [
      "<string>"
    ]
  },
  "progress": {
    "current_run_index": 0,
    "current_phase_index": 0,
    "confidence": "confirmed",
    "remaining_seconds": 0
  },
  "actual_start": "2026-10-22T20:30:00Z",
  "actual_end": "2026-10-22T20:30:00Z",
  "confirmed_by_user_name": "<string>",
  "manual_zero_offered": false,
  "manual_action_required": "<string>",
  "handoff_at": "2026-10-22T20:30:00Z",
  "alarms": [
    {
      "rule_id": "TELEMETRY-001",
      "severity": "INFO",
      "message": "<string>",
      "opened_at": "2026-10-22T20:30:00Z",
      "resolved_at": "2026-10-22T20:30:00Z"
    }
  ],
  "state_of_charge": {
    "key": "<string>",
    "label": "<string>",
    "status": "ok",
    "detail": "<string>"
  },
  "confirmed_at": "2026-10-22T20:30:00Z",
  "aborted_at": "2026-10-22T20:30:00Z",
  "abort_reason": "<string>",
  "last_error": "<string>",
  "last_error_at": "2026-10-22T20:30:00Z",
  "row_version": 0,
  "created_at": "2026-10-22T20:30:00Z",
  "updated_at": "2026-10-22T20:30:00Z"
}
Can raise
  • 401no valid token
  • 403scope missing
  • 404unknown or not visible
  • 429rate limited
ALL CODES →
PATCH/v1/assets/{asset_id}/betriebsfahrt/sessions/{session_id}

Adjust a standalone Betriebsfahrt draft

dispatch.write

Required scopes: dispatch.write

Regenerates the draft with the given products, power, run order, extended stroke, start or execution mode. Only drafts can be adjusted.

Path parameters

asset_idREQUIRED
stringAsset identifier, e.g. DE_50HZ_WEM_PAS_1.
session_idREQUIRED
string<uuid>Betriebsfahrt session identifier from the status response.

Request body · required

products
array[enum]
capacity_mw
number | string
first_direction
enumpositivenegative
extended_stroke_minutes
integer
planned_start
string<date-time>
execution_mode
enumrealdry_run
Example value
curl -X PATCH "https://api.ebx.energy/v1/assets/DE_BESS_01/betriebsfahrt/sessions/00000000-0000-0000-0000-000000000000" \
  -H "Authorization: Bearer $EBX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"products":["fcr_positive"],"capacity_mw":0,"first_direction":"positive","extended_stroke_minutes":0,"planned_start":"2026-10-22T20:30:00Z","execution_mode":"real"}'
Example response200
{
  "id": "<string>",
  "onboarding_id": "<string>",
  "purpose": "onboarding",
  "asset_id": "<string>",
  "status": "draft",
  "execution_mode": "real",
  "supersedes_session_id": "<string>",
  "parameters": {
    "first_direction": "positive",
    "single_direction": false,
    "extended_stroke_minutes": 0,
    "extended_stroke_min_minutes": 0,
    "extended_stroke_max_minutes": 0,
    "second_run_extended_stroke_minutes": 0,
    "capacity_mw": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "products": {
      "positive": [
        "<string>"
      ],
      "negative": [
        "<string>"
      ]
    },
    "product_capacity_mw": "<string>",
    "usable_energy_mwh": "<string>",
    "energy_safety_margin": "<string>",
    "energy_per_run_mwh": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "soc_energy_margin": "0.05",
    "ramp_mw_per_s": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "fcr_ramp_required_mw_per_s": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "measurement_point": "<string>",
    "retention_minutes": 0,
    "stroke_minutes": 0,
    "stated_products": [
      "<string>"
    ],
    "stated_capacity_mw": "<string>"
  },
  "findings": [
    {
      "code": "<string>",
      "severity": "blocker",
      "message": "<string>"
    }
  ],
  "planned_start": "2026-10-22T20:30:00Z",
  "planned_end": "2026-10-22T20:30:00Z",
  "plan_sha256": "<string>",
  "plan": "<string>",
  "runs": [
    {
      "index": 0,
      "direction": "positive",
      "products": [
        "<string>"
      ],
      "requested_capacity_mw": "<string>",
      "phases": [
        {
          "index": 0,
          "kind": "retention",
          "start": "2026-10-22T20:30:00Z",
          "end": "2026-10-22T20:30:00Z",
          "setpoint_mw": "<string>",
          "window_id": "<string>",
          "actual_start": "2026-10-22T20:30:00Z",
          "actual_end": "2026-10-22T20:30:00Z"
        }
      ],
      "status": "pending",
      "follow_checks": [
        {
          "phase_index": 0,
          "checked_at": "2026-10-22T20:30:00Z",
          "expected_mw": "<string>",
          "measured_mw": "<string>",
          "passed": false,
          "detail": "<string>"
        }
      ],
      "proofs": "<string>",
      "workbooks": "<string>",
      "uploads": "<string>",
      "verdicts": "<string>",
      "overrides": [
        {
          "product": "<string>",
          "reason": "<string>",
          "by_user_id": "<string>",
          "by_user_name": "<string>",
          "at": "2026-10-22T20:30:00Z"
        }
      ],
      "error": "<string>",
      "actual_start": "2026-10-22T20:30:00Z",
      "actual_end": "2026-10-22T20:30:00Z"
    }
  ],
  "driver": {
    "request_id": "<string>",
    "run_id": "<string>",
    "status": "<string>",
    "journal_written_at": "2026-10-22T20:30:00Z",
    "tracking_source": "<string>",
    "events": [
      "<string>"
    ]
  },
  "progress": {
    "current_run_index": 0,
    "current_phase_index": 0,
    "confidence": "confirmed",
    "remaining_seconds": 0
  },
  "actual_start": "2026-10-22T20:30:00Z",
  "actual_end": "2026-10-22T20:30:00Z",
  "confirmed_by_user_name": "<string>",
  "manual_zero_offered": false,
  "manual_action_required": "<string>",
  "handoff_at": "2026-10-22T20:30:00Z",
  "alarms": [
    {
      "rule_id": "TELEMETRY-001",
      "severity": "INFO",
      "message": "<string>",
      "opened_at": "2026-10-22T20:30:00Z",
      "resolved_at": "2026-10-22T20:30:00Z"
    }
  ],
  "state_of_charge": {
    "key": "<string>",
    "label": "<string>",
    "status": "ok",
    "detail": "<string>"
  },
  "confirmed_at": "2026-10-22T20:30:00Z",
  "aborted_at": "2026-10-22T20:30:00Z",
  "abort_reason": "<string>",
  "last_error": "<string>",
  "last_error_at": "2026-10-22T20:30:00Z",
  "row_version": 0,
  "created_at": "2026-10-22T20:30:00Z",
  "updated_at": "2026-10-22T20:30:00Z"
}
Can raise
  • 400malformed request
  • 401no valid token
  • 403scope missing
  • 404unknown or not visible
  • 409state conflict
  • 422validation failed
  • 429rate limited
ALL CODES →
POST/v1/assets/{asset_id}/betriebsfahrt/sessions/{session_id}/abort

Abort a standalone Betriebsfahrt

dispatch.write

Required scopes: dispatch.write

Ends the session and sends the driver's kill switch (zero every product on the asset; cancel the run when known). Aborting again resends an undelivered kill switch.

Path parameters

asset_idREQUIRED
stringAsset identifier, e.g. DE_50HZ_WEM_PAS_1.
session_idREQUIRED
string<uuid>Betriebsfahrt session identifier from the status response.

Request body · required

reasonREQUIRED
string
Example value
curl -X POST "https://api.ebx.energy/v1/assets/DE_BESS_01/betriebsfahrt/sessions/00000000-0000-0000-0000-000000000000/abort" \
  -H "Authorization: Bearer $EBX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason":"<string>"}'
Example response200
{
  "id": "<string>",
  "onboarding_id": "<string>",
  "purpose": "onboarding",
  "asset_id": "<string>",
  "status": "draft",
  "execution_mode": "real",
  "supersedes_session_id": "<string>",
  "parameters": {
    "first_direction": "positive",
    "single_direction": false,
    "extended_stroke_minutes": 0,
    "extended_stroke_min_minutes": 0,
    "extended_stroke_max_minutes": 0,
    "second_run_extended_stroke_minutes": 0,
    "capacity_mw": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "products": {
      "positive": [
        "<string>"
      ],
      "negative": [
        "<string>"
      ]
    },
    "product_capacity_mw": "<string>",
    "usable_energy_mwh": "<string>",
    "energy_safety_margin": "<string>",
    "energy_per_run_mwh": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "soc_energy_margin": "0.05",
    "ramp_mw_per_s": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "fcr_ramp_required_mw_per_s": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "measurement_point": "<string>",
    "retention_minutes": 0,
    "stroke_minutes": 0,
    "stated_products": [
      "<string>"
    ],
    "stated_capacity_mw": "<string>"
  },
  "findings": [
    {
      "code": "<string>",
      "severity": "blocker",
      "message": "<string>"
    }
  ],
  "planned_start": "2026-10-22T20:30:00Z",
  "planned_end": "2026-10-22T20:30:00Z",
  "plan_sha256": "<string>",
  "plan": "<string>",
  "runs": [
    {
      "index": 0,
      "direction": "positive",
      "products": [
        "<string>"
      ],
      "requested_capacity_mw": "<string>",
      "phases": [
        {
          "index": 0,
          "kind": "retention",
          "start": "2026-10-22T20:30:00Z",
          "end": "2026-10-22T20:30:00Z",
          "setpoint_mw": "<string>",
          "window_id": "<string>",
          "actual_start": "2026-10-22T20:30:00Z",
          "actual_end": "2026-10-22T20:30:00Z"
        }
      ],
      "status": "pending",
      "follow_checks": [
        {
          "phase_index": 0,
          "checked_at": "2026-10-22T20:30:00Z",
          "expected_mw": "<string>",
          "measured_mw": "<string>",
          "passed": false,
          "detail": "<string>"
        }
      ],
      "proofs": "<string>",
      "workbooks": "<string>",
      "uploads": "<string>",
      "verdicts": "<string>",
      "overrides": [
        {
          "product": "<string>",
          "reason": "<string>",
          "by_user_id": "<string>",
          "by_user_name": "<string>",
          "at": "2026-10-22T20:30:00Z"
        }
      ],
      "error": "<string>",
      "actual_start": "2026-10-22T20:30:00Z",
      "actual_end": "2026-10-22T20:30:00Z"
    }
  ],
  "driver": {
    "request_id": "<string>",
    "run_id": "<string>",
    "status": "<string>",
    "journal_written_at": "2026-10-22T20:30:00Z",
    "tracking_source": "<string>",
    "events": [
      "<string>"
    ]
  },
  "progress": {
    "current_run_index": 0,
    "current_phase_index": 0,
    "confidence": "confirmed",
    "remaining_seconds": 0
  },
  "actual_start": "2026-10-22T20:30:00Z",
  "actual_end": "2026-10-22T20:30:00Z",
  "confirmed_by_user_name": "<string>",
  "manual_zero_offered": false,
  "manual_action_required": "<string>",
  "handoff_at": "2026-10-22T20:30:00Z",
  "alarms": [
    {
      "rule_id": "TELEMETRY-001",
      "severity": "INFO",
      "message": "<string>",
      "opened_at": "2026-10-22T20:30:00Z",
      "resolved_at": "2026-10-22T20:30:00Z"
    }
  ],
  "state_of_charge": {
    "key": "<string>",
    "label": "<string>",
    "status": "ok",
    "detail": "<string>"
  },
  "confirmed_at": "2026-10-22T20:30:00Z",
  "aborted_at": "2026-10-22T20:30:00Z",
  "abort_reason": "<string>",
  "last_error": "<string>",
  "last_error_at": "2026-10-22T20:30:00Z",
  "row_version": 0,
  "created_at": "2026-10-22T20:30:00Z",
  "updated_at": "2026-10-22T20:30:00Z"
}
Can raise
  • 400malformed request
  • 401no valid token
  • 403scope missing
  • 404unknown or not visible
  • 409state conflict
  • 422validation failed
  • 429rate limited
ALL CODES →
POST/v1/assets/{asset_id}/betriebsfahrt/sessions/{session_id}/confirm

Confirm a standalone Betriebsfahrt

dispatch.write

Required scopes: dispatch.write

Freezes the plan and hands it to the control-test driver: the typed asset id must match, the plan must still be the reviewed one, the asset's maintenance window must cover the drive, and the battery must hold the first run's energy plus the margin (positive run first) or have that much room (negative run first) with telemetry arriving. The drive starts at the planned quarter hour without further prompts; the plan is published to the driver ten minutes before. Nothing is filed with a TSO.

Path parameters

asset_idREQUIRED
stringAsset identifier, e.g. DE_50HZ_WEM_PAS_1.
session_idREQUIRED
string<uuid>Betriebsfahrt session identifier from the status response.

Request body · required

confirm_asset_idREQUIRED
stringThe asset id typed by the operator; must equal the session's asset.
row_versionREQUIRED
integerThe row version of the draft the operator reviewed; any adjustment since (plan, start, mode) is refused.
Example value
curl -X POST "https://api.ebx.energy/v1/assets/DE_BESS_01/betriebsfahrt/sessions/00000000-0000-0000-0000-000000000000/confirm" \
  -H "Authorization: Bearer $EBX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"confirm_asset_id":"<string>","row_version":0}'
Example response202
{
  "id": "<string>",
  "onboarding_id": "<string>",
  "purpose": "onboarding",
  "asset_id": "<string>",
  "status": "draft",
  "execution_mode": "real",
  "supersedes_session_id": "<string>",
  "parameters": {
    "first_direction": "positive",
    "single_direction": false,
    "extended_stroke_minutes": 0,
    "extended_stroke_min_minutes": 0,
    "extended_stroke_max_minutes": 0,
    "second_run_extended_stroke_minutes": 0,
    "capacity_mw": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "products": {
      "positive": [
        "<string>"
      ],
      "negative": [
        "<string>"
      ]
    },
    "product_capacity_mw": "<string>",
    "usable_energy_mwh": "<string>",
    "energy_safety_margin": "<string>",
    "energy_per_run_mwh": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "soc_energy_margin": "0.05",
    "ramp_mw_per_s": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "fcr_ramp_required_mw_per_s": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "measurement_point": "<string>",
    "retention_minutes": 0,
    "stroke_minutes": 0,
    "stated_products": [
      "<string>"
    ],
    "stated_capacity_mw": "<string>"
  },
  "findings": [
    {
      "code": "<string>",
      "severity": "blocker",
      "message": "<string>"
    }
  ],
  "planned_start": "2026-10-22T20:30:00Z",
  "planned_end": "2026-10-22T20:30:00Z",
  "plan_sha256": "<string>",
  "plan": "<string>",
  "runs": [
    {
      "index": 0,
      "direction": "positive",
      "products": [
        "<string>"
      ],
      "requested_capacity_mw": "<string>",
      "phases": [
        {
          "index": 0,
          "kind": "retention",
          "start": "2026-10-22T20:30:00Z",
          "end": "2026-10-22T20:30:00Z",
          "setpoint_mw": "<string>",
          "window_id": "<string>",
          "actual_start": "2026-10-22T20:30:00Z",
          "actual_end": "2026-10-22T20:30:00Z"
        }
      ],
      "status": "pending",
      "follow_checks": [
        {
          "phase_index": 0,
          "checked_at": "2026-10-22T20:30:00Z",
          "expected_mw": "<string>",
          "measured_mw": "<string>",
          "passed": false,
          "detail": "<string>"
        }
      ],
      "proofs": "<string>",
      "workbooks": "<string>",
      "uploads": "<string>",
      "verdicts": "<string>",
      "overrides": [
        {
          "product": "<string>",
          "reason": "<string>",
          "by_user_id": "<string>",
          "by_user_name": "<string>",
          "at": "2026-10-22T20:30:00Z"
        }
      ],
      "error": "<string>",
      "actual_start": "2026-10-22T20:30:00Z",
      "actual_end": "2026-10-22T20:30:00Z"
    }
  ],
  "driver": {
    "request_id": "<string>",
    "run_id": "<string>",
    "status": "<string>",
    "journal_written_at": "2026-10-22T20:30:00Z",
    "tracking_source": "<string>",
    "events": [
      "<string>"
    ]
  },
  "progress": {
    "current_run_index": 0,
    "current_phase_index": 0,
    "confidence": "confirmed",
    "remaining_seconds": 0
  },
  "actual_start": "2026-10-22T20:30:00Z",
  "actual_end": "2026-10-22T20:30:00Z",
  "confirmed_by_user_name": "<string>",
  "manual_zero_offered": false,
  "manual_action_required": "<string>",
  "handoff_at": "2026-10-22T20:30:00Z",
  "alarms": [
    {
      "rule_id": "TELEMETRY-001",
      "severity": "INFO",
      "message": "<string>",
      "opened_at": "2026-10-22T20:30:00Z",
      "resolved_at": "2026-10-22T20:30:00Z"
    }
  ],
  "state_of_charge": {
    "key": "<string>",
    "label": "<string>",
    "status": "ok",
    "detail": "<string>"
  },
  "confirmed_at": "2026-10-22T20:30:00Z",
  "aborted_at": "2026-10-22T20:30:00Z",
  "abort_reason": "<string>",
  "last_error": "<string>",
  "last_error_at": "2026-10-22T20:30:00Z",
  "row_version": 0,
  "created_at": "2026-10-22T20:30:00Z",
  "updated_at": "2026-10-22T20:30:00Z"
}
Can raise
  • 400malformed request
  • 401no valid token
  • 403scope missing
  • 404unknown or not visible
  • 409state conflict
  • 422validation failed
  • 429rate limited
ALL CODES →
POST/v1/assets/{asset_id}/betriebsfahrt/sessions/{session_id}/runs/{run_index}/rebuild-workbooks

Build a run's unusable workbooks again

dispatch.write

Required scopes: dispatch.write

Builds the workbooks of one run again from telemetry, for the products whose file the generator could not make a usable one of — a recording the telemetry store received late leaves gaps in it. A usable workbook is never rebuilt: its bytes are what was recorded. The files appear within the next poll cycle.

Path parameters

asset_idREQUIRED
stringAsset identifier, e.g. DE_50HZ_WEM_PAS_1.
session_idREQUIRED
string<uuid>Betriebsfahrt session identifier from the status response.
run_indexREQUIRED
integerRun index within the session: 0 = first run, 1 = second run.
Example value
curl -X POST "https://api.ebx.energy/v1/assets/DE_BESS_01/betriebsfahrt/sessions/00000000-0000-0000-0000-000000000000/runs/0/rebuild-workbooks" \
  -H "Authorization: Bearer $EBX_TOKEN"
Example response200
{
  "id": "<string>",
  "onboarding_id": "<string>",
  "purpose": "onboarding",
  "asset_id": "<string>",
  "status": "draft",
  "execution_mode": "real",
  "supersedes_session_id": "<string>",
  "parameters": {
    "first_direction": "positive",
    "single_direction": false,
    "extended_stroke_minutes": 0,
    "extended_stroke_min_minutes": 0,
    "extended_stroke_max_minutes": 0,
    "second_run_extended_stroke_minutes": 0,
    "capacity_mw": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "products": {
      "positive": [
        "<string>"
      ],
      "negative": [
        "<string>"
      ]
    },
    "product_capacity_mw": "<string>",
    "usable_energy_mwh": "<string>",
    "energy_safety_margin": "<string>",
    "energy_per_run_mwh": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "soc_energy_margin": "0.05",
    "ramp_mw_per_s": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "fcr_ramp_required_mw_per_s": {
      "positive": "<string>",
      "negative": "<string>"
    },
    "measurement_point": "<string>",
    "retention_minutes": 0,
    "stroke_minutes": 0,
    "stated_products": [
      "<string>"
    ],
    "stated_capacity_mw": "<string>"
  },
  "findings": [
    {
      "code": "<string>",
      "severity": "blocker",
      "message": "<string>"
    }
  ],
  "planned_start": "2026-10-22T20:30:00Z",
  "planned_end": "2026-10-22T20:30:00Z",
  "plan_sha256": "<string>",
  "plan": "<string>",
  "runs": [
    {
      "index": 0,
      "direction": "positive",
      "products": [
        "<string>"
      ],
      "requested_capacity_mw": "<string>",
      "phases": [
        {
          "index": 0,
          "kind": "retention",
          "start": "2026-10-22T20:30:00Z",
          "end": "2026-10-22T20:30:00Z",
          "setpoint_mw": "<string>",
          "window_id": "<string>",
          "actual_start": "2026-10-22T20:30:00Z",
          "actual_end": "2026-10-22T20:30:00Z"
        }
      ],
      "status": "pending",
      "follow_checks": [
        {
          "phase_index": 0,
          "checked_at": "2026-10-22T20:30:00Z",
          "expected_mw": "<string>",
          "measured_mw": "<string>",
          "passed": false,
          "detail": "<string>"
        }
      ],
      "proofs": "<string>",
      "workbooks": "<string>",
      "uploads": "<string>",
      "verdicts": "<string>",
      "overrides": [
        {
          "product": "<string>",
          "reason": "<string>",
          "by_user_id": "<string>",
          "by_user_name": "<string>",
          "at": "2026-10-22T20:30:00Z"
        }
      ],
      "error": "<string>",
      "actual_start": "2026-10-22T20:30:00Z",
      "actual_end": "2026-10-22T20:30:00Z"
    }
  ],
  "driver": {
    "request_id": "<string>",
    "run_id": "<string>",
    "status": "<string>",
    "journal_written_at": "2026-10-22T20:30:00Z",
    "tracking_source": "<string>",
    "events": [
      "<string>"
    ]
  },
  "progress": {
    "current_run_index": 0,
    "current_phase_index": 0,
    "confidence": "confirmed",
    "remaining_seconds": 0
  },
  "actual_start": "2026-10-22T20:30:00Z",
  "actual_end": "2026-10-22T20:30:00Z",
  "confirmed_by_user_name": "<string>",
  "manual_zero_offered": false,
  "manual_action_required": "<string>",
  "handoff_at": "2026-10-22T20:30:00Z",
  "alarms": [
    {
      "rule_id": "TELEMETRY-001",
      "severity": "INFO",
      "message": "<string>",
      "opened_at": "2026-10-22T20:30:00Z",
      "resolved_at": "2026-10-22T20:30:00Z"
    }
  ],
  "state_of_charge": {
    "key": "<string>",
    "label": "<string>",
    "status": "ok",
    "detail": "<string>"
  },
  "confirmed_at": "2026-10-22T20:30:00Z",
  "aborted_at": "2026-10-22T20:30:00Z",
  "abort_reason": "<string>",
  "last_error": "<string>",
  "last_error_at": "2026-10-22T20:30:00Z",
  "row_version": 0,
  "created_at": "2026-10-22T20:30:00Z",
  "updated_at": "2026-10-22T20:30:00Z"
}
Can raise
  • 400malformed request
  • 401no valid token
  • 403scope missing
  • 404unknown or not visible
  • 409state conflict
  • 429rate limited
ALL CODES →
GET/v1/assets/{asset_id}/betriebsfahrt/sessions/{session_id}/runs/{run_index}/workbooks/{product}

Download a Betriebsfahrt workbook

dispatch.read

Required scopes: dispatch.read

A time-limited link to one Doppelhubkurve workbook the drive produced (one per product of the run).

Path parameters

asset_idREQUIRED
stringAsset identifier, e.g. DE_50HZ_WEM_PAS_1.
session_idREQUIRED
string<uuid>Betriebsfahrt session identifier from the status response.
run_indexREQUIRED
integerRun index within the session: 0 = first run, 1 = second run.
productREQUIRED
enumfcr_positivefcr_negativeafrr_positiveafrr_negativeThe product whose workbook is wanted, named the way the drive was asked for it.
Example value
curl "https://api.ebx.energy/v1/assets/DE_BESS_01/betriebsfahrt/sessions/00000000-0000-0000-0000-000000000000/runs/0/workbooks/fcr_positive" \
  -H "Authorization: Bearer $EBX_TOKEN"
Example response200
{
  "filename": "<string>",
  "download_url": "<string>",
  "expires_at": "2026-10-22T20:30:00Z"
}
Can raise
  • 401no valid token
  • 403scope missing
  • 404unknown or not visible
  • 429rate limited
ALL CODES →

Send feedback

This goes straight to the docs team on Slack, with the page you are on. It is not attributed to you, so say who you are if you would like an answer.

0/2000