Skip to content

Workspace

Working with Projects

Endpoint: project(s)

With the workspace/projects endpoint, the user can get a list of all available projects in the workspace or create a new project to be stored in the workspace. Adding a scenario to an existing project can be achieved with the workspace/scenarios endpoint.

Example Code
import requests

with requests.Session() as session:
    # Login and update the http header with the access token (see above)

    # Retrieve a list of all projects existing projects
    response = session.get("https://sesam.co4e.com/api/v1/workspace/projects")
    all_projects = response.json()

    # Create a new project
    data = {"name": "A new project", "comment": "An example project"}
    response = session.post("https://sesam.co4e.com/api/v1/workspace/projects", data=data)

The schema for the json response (all_projects) is described in the schema file.

The workspace/projects endpoint supports an optional search by project name using a query parameter ?name=<pattern>. The <pattern> is interpreted as a (partial) case-insensitive regular expression. If you omit the name parameter, the endpoint returns all existing projects.

HTTP Examples
1
2
3
4
5
# Finds all projects containing "Test" in their name
GET https://sesam.co4e.com/api/v1/workspace/projects?name=.*Test.*

# Finds projects that match "MyProject" or "myproject" (case-insensitive)
GET https://sesam.co4e.com/api/v1/workspace/projects?name=^MyProject$

The workspace/project/{project_id} endpoint is intended for getting project properties (e.g. name or scenarios), modifying properties and deleting an existing project from the workspace. The project id can be obtained from the list of all projects provided by the workspace/projects endpoint.

Example Code
import requests

with requests.Session() as session:
    # Login and update the http header with the access token (see above)

    # Get the properties of project with id = 12 (for example)
    project_id = 12
    response = session.get("https://sesam.co4e.com/api/v1/workspace/projects/" + project_id)
    project = response.json()

    # Modify a project (rename the project)
    data = {"name": "New name"}
    response = session.patch("https://sesam.co4e.com/api/v1/workspace/projects/" + project_id, data=data)

    # Delete a project
    response = session.delete("https://sesam.co4e.com/api/v1/workspace/projects/" + project_id)

Working with Scenarios

Similar to the projects, the workspace endpoints allow to work with available scenarios. They can be retrieved, modified and deleted.

Note

New scenarios are not created with the workspace endpoints. The creation of a scenario can be done with the builder endpoints instead.

Endpoint: scenario(s)

The workspace/scenarios endpoint provides a list of all available scenarios with their properties.

sequenceDiagram
    participant C as Client
    participant S as SESAM API
    Note over C,S: Retrieve scenarios from the workspace
    C->>+S: GET workspace/scenarios
    S->>-C: list of all scenarios
Example Code
1
2
3
4
5
6
7
8
import requests

with requests.Session() as session:
    # Login and update the http header with the access token (see above)

    # Retrieve a list of all scenarios
    response = session.get("https://sesam.co4e.com/api/v1/workspace/scenarios")
    all_scenarios = response.json()

Refining your interaction with a specific scenario is made possible through the workspace/scenario/{scenario_id} endpoint. By supplying the scenario ID as a URL parameter, you gain access to a spectrum of actions including retrieving properties, updating them, and deleting the scenario altogether.

sequenceDiagram
    participant C as Client
    participant S as SESAM API
    Note over C,S: Retrieve scenario with id = 37 from the workspace
    C->>+S: GET workspace/scenario/37
    S->>-C: properties of scenario 37
    C->>+S: PATCH workspace/scenario/37 { ... }
    S->>-C: updated properties of scenario 37
    C->>+S: DELETE workspace/scenario/37
    S->>-C: OK
Example Code
import requests

with requests.Session() as session:
    # Login and update the http header with the access token (see above)

    # Retrieve properties of scenario 37
    response = session.get("https://sesam.co4e.com/api/v1/workspace/scenario/37")
    scenario = response.json()

    # Update the name of scenario 37
    data = {"name": "A new scenario name"}
    response = session.patch("https://sesam.co4e.com/api/v1/workspace/scenario/37", json=data)
    scenario = response.json()

    # Rerouting is read-only in Workspace; edits use the Editor API's rerouting.set operation.
    rerouting = scenario["rerouting"]

    # Delete scenario 37
    response = session.delete("https://sesam.co4e.com/api/v1/workspace/scenario/37")

The workspace/scenarios endpoint supports an optional search by scenario name using a query parameter name (string, optional). The value is interpreted as a (partial) case-insensitive regular expression. If you omit the name parameter, the endpoint returns all existing scenarios.

Usage of the Parameter 'name'
1
2
3
4
5
# Finds all scenarios containing "Test" in their name
GET https://sesam.co4e.com/api/v1/workspace/scenarios?name=.*Test.*

# Finds scenarios that match "MyScenario" or "myscenario" (case-insensitive)
GET https://sesam.co4e.com/api/v1/workspace/scenarios?name=^MyScenario$

The endpoints workspace/scenarios and workspace/scenario/{scenario_id} also support the following query parameter include_simulations (boolean, optional). When set to true, the response will include full details of simulations associated with the scenario, including any simulation runs. When omitted or set to false, the response will only include the IDs of the simulations associated with the scenario.

Usage of the Parameter 'include_simulations'
# Retrieve information about simulations of all scenarios of current user
GET https://sesam.co4e.com/api/v1/workspace/scenarios?include_simulations=true

Traffic-light descriptor

The workspace/scenario/{scenario_id}/tls-descriptor endpoint returns the semantic traffic-light (LSA) descriptor of a scenario as JSON (content type application/json). It is available to every authenticated user for the scenarios the user owns; reading it does not require the Scenario Editor feature of the plan. Built-in scenarios are excluded and the endpoint returns 404 for scenarios that do not exist, belong to another user or have no descriptor file.

The descriptor carries the semantics of the scenario's traffic lights: which traffic-light controller controls which junctions, the complete signal-controlled lane-to-lane connection mapping with authoritative tlIndex values, and the controller's programs (signal plans) with their phases. It contains no geometry — the tls_connection bar geometry stays in the detailed network GeoParquet. Its purpose is to make traffic-light detection and targeted editor synchronization reliable, in particular for joined traffic lights, where a single controller governs several junctions and the controller id differs from the junction id.

The current scenario version is delivered in the X-Sesam-Scenario-Version response header; the descriptor file on the volume is a static, version-agnostic artifact. The descriptor describes the current state of the scenario. The Analyzer API returns the descriptor as it was when a simulation was configured.

HTTP Example
GET https://sesam.co4e.com/api/v1/workspace/scenario/37/tls-descriptor
Traffic-light descriptor
{
  "traffic_lights": [
    {
      "id": "209",
      "defaultProgramID": "0",
      "junctions": [
        {
          "id": "63",
          "connectionCount": 1,
          "connections": [
            { "fromLane": "edge-a_0", "toLane": "edge-b_0", "tlIndex": 0 }
          ]
        }
      ],
      "programs": [
        {
          "programID": "0",
          "type": "static",
          "offset": 0,
          "cycleTime": 90,
          "cycleTimeIsVariable": false,
          "cycleTimeParameter": null,
          "extendMaxDur": null,
          "editable": true,
          "editabilityReason": null,
          "linkCount": 13,
          "phases": [
            { "index": 0, "name": "", "duration": 37, "minDur": 37, "maxDur": 37, "next": [], "state": "GrGgGGgrGrGrr" },
            { "index": 1, "name": "", "duration": 3, "minDur": 3, "maxDur": 3, "next": [], "state": "yryyyyyryryrr" }
          ]
        }
      ]
    }
  ]
}
  • traffic_lights[].id – SUMO traffic-light controller id (may differ from the junction ids for joined TLS).
  • traffic_lights[].junctions[].id – SUMO junction id controlled by that controller.
  • traffic_lights[].junctions[].connectionCount – number of signal-controlled connections (link indices) of the controller at that junction.
  • traffic_lights[].junctions[].connections[] – the complete signal-controlled lane-to-lane connections with their authoritative tlIndex; absent in legacy descriptors.
  • traffic_lights[].defaultProgramID – program selected after the network and ordered additional files are loaded, before WAUT or TraCI runtime switching.
  • traffic_lights[].programs[] – effective signal-plan programs from the network and ordered additional files; an empty list when no program is available. Deterministically ordered by programID.
  • traffic_lights[].programs[].programID – SUMO program id (free-form; always a string).
  • traffic_lights[].programs[].type – SUMO program type (e.g. static, actuated, delay_based).
  • traffic_lights[].programs[].offset – program offset in seconds.
  • traffic_lights[].programs[].cycleTime – sum of phase durations; exact for static programs, a nominal value otherwise.
  • traffic_lights[].programs[].cycleTimeIsVariable – true when the cycle time may vary (actuated / delay_based), else false.
  • traffic_lights[].programs[].cycleTimeParameter – explicit SUMO cycleTime parameter, or null when absent.
  • traffic_lights[].programs[].extendMaxDur – effective delay-based extension setting, or null when not applicable.
  • traffic_lights[].programs[].editable / editabilityReason – whether the basic timing editor supports the program and, if not, why.
  • traffic_lights[].programs[].linkCount – number of signal-state positions (length of the phase state strings). This is not the number of exported tls_connection geometries.
  • traffic_lights[].programs[].phases[] – ordered phases; each has index (zero-based), name, duration (s), minDur/maxDur (duration for static programs, null when unspecified for variable ones), next (successor phase indices), and state (raw SUMO signal-state string).

The Editor UI displays only the program identified by defaultProgramID, and tls.program.set modifies only that program. Other programs remain available as read-only descriptor data.

The program-related fields are additive: legacy topology-only descriptors remain valid, and existing consumers that only read id, junctions, and connectionCount are unaffected.

Scenario rerouting properties

GET workspace/scenario/{scenario_id} and scenario lists include a nullable nested rerouting property. Built-in and guest scenarios expose the same read-only representation. Workspace PATCH rejects a supplied rerouting field with HTTP 400, including null; use the Editor API to change it. The seven underlying rerouting_* database properties are not separate API fields.

JSON
{
  "rerouting": {
    "mode": 0,
    "probability": 1.0,
    "pre_period": 60,
    "period": 300,
    "adaptation_interval": 10,
    "adaptation_steps": 36,
    "adaptation_weight": null
  }
}

If no device.rerouting.* option exists in the scenario's .sumocfg, the response is "rerouting": null and all seven database fields are NULL. Any option with that prefix establishes configuration presence, including options not exposed by SESAM. Missing modeled options then take the SUMO 1.27.1 defaults below. Reading, importing and reconciling metadata does not rewrite the XML.

API property SUMO option Unit / accepted values Default
rerouting.mode device.rerouting.mode Integer mode 0–4 or 8–12 (see below) 0
rerouting.probability device.rerouting.probability −1 or a probability from 0 to 1 −1
rerouting.pre_period device.rerouting.pre-period Nonnegative numeric seconds 60
rerouting.period device.rerouting.period Nonnegative numeric seconds 0
rerouting.adaptation_interval device.rerouting.adaptation-interval Nonnegative numeric seconds 1
rerouting.adaptation_steps device.rerouting.adaptation-steps Integer 0–2147483647, or null when weight is selected 180
rerouting.adaptation_weight device.rerouting.adaptation-weight Number 0–1, or null when steps are selected null

Time values are numeric seconds and may include fractions. The active averaging property is numeric; the inactive one is null. The Editor API validates changes, including ranges and the mutually exclusive averaging options.

SUMO uses rerouting devices to choose routes based on traffic conditions. Probability controls random device assignment; −1 and 0 assign no devices randomly. Trips with incomplete routes can receive devices independently. Configuration presence does not imply periodic en-route rerouting: period=0 disables periodic rerouting after departure. pre_period controls repeated routing before departure; 0 disables repetition. adaptation_interval controls updates to edge-weight estimates; 0 disables updates. adaptation_steps controls the moving-average sample count; 0 disables moving averaging. The averaging window spans interval × steps seconds.

The API reports probability −1 both when the option is absent and when it is explicitly set to −1. SUMO distinguishes these cases for implicit trip devices: an omitted option permits their configured en-route period, while an explicit −1 disables that implicit periodic assignment. Editor updates send only changed properties; an omitted probability stays absent unless explicitly supplied in the patch.

The Editor displays probability as a percentage, including values below 1%, with Disabled (0%) for 0 or −1; the API representation remains unchanged. Editor rerouting edits are staged in its Changes list and applied by the shared Save action. Its configuration switch stages creation or removal (rerouting: null), rather than directly enabling periodic rerouting.

The advanced mode selects SUMO routing flags: 0 uses default routing weights, 1 aggregated travel times, 2 loaded efforts, 3 combined costs, and 4 aggregated travel times with custom weights. Adding 8 (modes 8–12) ignores temporary permission changes while routing. Vehicles can then wait at a closed edge. Mode does not enable periodic rerouting. See the SUMO routing documentation and automatic routing options.

Changes use PATCH /api/v1/editor/scenario/{scenario_id} with a required base_version and a rerouting.set operation. The Editor returns HTTP 202 and a task status URL. After successful completion, retrieve the stored values with the Workspace scenario GET. See Scenario rerouting in a shared Editor patch for creation, partial updates, averaging-method changes, removal and failure handling. The existing Editor authentication and plan restrictions apply.

Workspace PATCH continues to update ordinary scenario metadata such as name, comment and project. It does not dispatch rerouting tasks or increment the scenario version. A request combining metadata with rerouting is rejected entirely, so the metadata is not partially saved.

Endpoint: builtin-scenario(s)

In addition to the scenarios built by a user, SESAM also ships with built-in scenarios, which were contributed by external parties. These scenarios are also visible in the workspace of registered users, but they can be neither modified nor deleted or downloaded. The workspace/builtin-scenarios endpoint provides a list of all available built-in scenarios (similar to the workspace/scenarios endpoint).

Example Code
1
2
3
4
5
6
7
8
import requests

with requests.Session() as session:
    # Login and update the http header with the access token (see above)

    # Retrieve a list of all built-in scenarios
    response = session.get("https://sesam.co4e.com/api/v1/workspace/builtin-scenarios")
    all_builtin_scenarios = response.json()

The workspace/builtin-scenario/{scenario_id} endpoint is similar to the workspace/scenarios/{scenario_id} endpoint, as it takes a scenario id as a parameter in the url and provides a list of all properties of the builtin scenario as a result.

Example Code
1
2
3
4
5
6
7
8
import requests

with requests.Session() as session:
    # Login and update the http header with the access token (see above)

    # Retrieve properties of built-in scenario 4
    response = session.get("https://sesam.co4e.com/api/v1/workspace/builtin-scenarios/4")
    builtin_scenario = response.json()

The workspace/builtin-scenarios endpoint now also supports an optional search by scenario name using a query parameter ?name=<pattern> (see above).

Endpoint: duplicate-scenario

You may need to duplicate a scenario to modify and simulate it, enabling you to observe variations in the simulation results. This duplication functionality is facilitated through the workspace/duplicate-scenario/{scenario_id} endpoint. It takes a scenario id as a parameter in the url and allows to provide a name for the new scenario as part of the POST request body. The duplication is only allowed for scenarios owned by the current user.

Endpoint: scenario-zip

The workspace/scenario-zip/{scenario_id} endpoints allows to download a scenario from the workspace as a ZIP archive. Calling this endpoint with the scenario id as an url parameter triggers a background task, which is responsible for creating the archive and providing the download link.

Note

The scenario download as a ZIP archive is only supported for user generated scenarios. Built-in scenarios cannot be downloaded as a ZIP archive.

The execution of the background task may take some time and depends on the size of the scenario to be prepared for download. Clients can request the status of this task with the workspace/scenario-zip-status endpoint.

After the background task finished its execution, it will signal its success with a state: "SUCCESS" in the response. It will also provide the download url in the download_url field in the response.

sequenceDiagram
    participant C as Client
    participant S as SESAM API
    Note over C,S: Download scenario with id = 13 as a ZIP archive
    C->>+S: GET workspace/scenario-zip/13
    S->>-C: status_url for task status
    loop until state == "SUCCESS"
        C->>+S: GET status_url
        S->>-C: { ... state, download_url, ...}
    end

Here is an example python code for creating a zip archive of an existing scenario with the id 13.

Example Code
import time

import requests

with requests.Session() as session:
    # Login and update the http header with the access token (see above)

    # Trigger zip creation for scenario 13
    response = session.get("https://sesam.co4e.com/api/v1/workspace/scenario-zip/13")

    # Retrieve the endpoint to query the task status
    status_url = response.json().get("status_url")

    # Check if zip has been created
    download_url = None
    while not download_url:
        response = session.get(status_url)
        # Check if zip creation task finished
        if response.json().get("state", "") == "SUCCESS":
            download_url = response.json().get("download_url")
        else:
            # Delay the next polling
            time.sleep(0.5)

    # Zip archive can be retrieved from URL in download_url

Endpoint: upload-scenario

The workspace/upload-scenario endpoint allows users to upload a new scenario as a ZIP archive into the workspace. This enables the import of pre-created scenarios into the system, making them available for further editing or simulation.

The upload is performed using a multipart/form-data request, where the ZIP archive and scenario metadata are sent together. After the upload, a background task is started to process the uploaded data.

Once the request is successfully submitted, the API returns a status_url, which allows clients to track the progress of the upload. When the processing is complete, the scenario is available in the workspace for further use.

Constraints for ZIP Archives:

  • The ZIP archive must not contain subfolders. All files should be stored in the root directory of the ZIP file.
  • The uploaded scenario can only contain SUMO-related scenario files with the following allowed extensions: .bat, .diff, .duarcfg, .gz, .md, .netccfg, .polycfg, .rtcfg, .sh, .sumocfg, .txt, .xml

Any ZIP archive containing unsupported files or subdirectories will be rejected by the API.

sequenceDiagram
    participant C as Client
    participant S as SESAM API
    Note over C,S: Upload scenario as ZIP archive
    C->>+S: POST workspace/upload-scenario (multipart)
    S->>-C: status_url for task status
    loop until state == "SUCCESS"
        C->>+S: GET status_url
        S->>-C: { ... state, scenario_id, ...}
end

Here is an example python code for uploading a zip archive of a scenario to SESAM. Make sure to set the Content-Type of the request to multipart/form-data and not to application/json.

Example Code
import time

import requests

with requests.Session() as session:
    # Login and update the HTTP header with the access token (see above)
    # ...

    # Remove the default "application/json"
    session.headers.pop("Content-Type", None)

    # Define the path to the scenario (modify your path accordingly)
    zip_file_path = "folder/scenario.zip"

    # Prepare the multipart form-data request
    with open(zip_file_path, "rb") as zip_file:

        # Define the metadata of the scenario (modify according to you scenario)
        data = {
            "scenario_name": "Example Upload Scenario",
            "begin": 0,
            "duration": 600,
            "disable_fcd_output": True,
            "allowed_time_step_lengths": [1, 0.1],
            "allowed_lateral_resolutions": [1.6, -1],
        }

        # Add the scenario zip in the section "zipfile" of the request
        files = {"zipfile": ("scenario.zip", zip_file, "application/zip")}

        # Trigger the upload request
        response = session.post("https://sesam.co4e.com/api/v1/workspace/upload-scenario", files=files, data=data)

    status_url = response.json().get("status_url")

    # Poll the status endpoint until success
    scenario_id = None
    while not scenario_id:
        response = session.get(status_url)
        status_data = response.json()
        if status_data.get("state") == "SUCCESS":
            scenario_id = status_data.get("scenario_id")
        else:
            time.sleep(0.5)

    print(f"Scenario successfully uploaded with ID: {scenario_id}")

If you want to use an API tool, such as RapidAPI, please confer to the following image to see how the request can be configured.

Triggering a scenario upload with RapidAPI

Please note, how multiple values for allowed_time_step_lengths are supplied as multiple parts in the request (see allowed_time_step_length[0] and allowed_time_step_length[1] in the screenshot) to be properly recognized by the API. The file content can be added by creating the zipfile part in the request, followed by a right click in the value field and then selecting File and File Content. This allows to browse the local computer for the ZIP archive with the scenario to be uploaded.

Working with Simulations

Similar to the projects and scenario, there are also endpoints to retrieve, modify and delete simulations.

Note

New simulations are not created with the workspace endpoints. The creation of a simulation can be done with the simulator endpoints instead.

Endpoint: simulations

The workspace/simulations endpoints provides a list of all available simulations with their properties.

sequenceDiagram
    participant C as Client
    participant S as SESAM API
    Note over C,S: Retrieve simulations from the workspace
    C->>+S: GET workspace/simulations
    S->>-C: list of all simulations
Example Code
1
2
3
4
5
6
7
8
import requests

with requests.Session() as session:
    # Login and update the http header with the access token (see above)

    # Retrieve a list of all scenarios
    response = session.get("https://sesam.co4e.com/api/v1/workspace/simulations")
    all_simulations = response.json()

A more fined grained interaction with a single, existing simulation can be achieved with the workspace/simulations/{simulation_id} endpoint. It requires the simulation id as an url parameter and offers to retrieve the properties, update its properties and delete the simulation.

sequenceDiagram
    participant C as Client
    participant S as SESAM API
    Note over C,S: Retrieve simulation with id = 37 from the workspace
    C->>+S: GET workspace/simulations/37
    S->>-C: properties of simulation 37
    C->>+S: PATCH workspace/simulations/37 { ... }
    S->>-C: updated properties of simulation 37
    C->>+S: DELETE workspace/simulations/37
    S->>-C: OK
Example Code
import requests

with requests.Session() as session:
    # Login and update the http header with the access token (see above)

    # Retrieve properties of simulation 37
    response = session.get("https://sesam.co4e.com/api/v1/workspace/simulations/37")
    simulation = response.json()

    # Update the name of simulation 37
    data = {"name": "A new simulation name"}
    response = session.patch("https://sesam.co4e.com/api/v1/workspace/simulations/37", data=data)
    simulation = response.json()

    # Delete simulation 37
    response = session.delete("https://sesam.co4e.com/api/v1/workspace/simulations/37")

The workspace/simulations endpoint supports an optional search by simulation name using a query parameter ?name=<pattern>. The <pattern> is interpreted as a (partial) case-insensitive regular expression. If you omit the name parameter, the endpoint returns all existing simulations.

HTTP Examples
1
2
3
4
5
# Finds all simulations containing "Test" in their name
GET https://sesam.co4e.com/api/v1/workspace/simulations?name=.*Test.*

# Finds simulations that match "MySimulation" or "mysimulation" (case-insensitive)
GET https://sesam.co4e.com/api/v1/workspace/simulations?name=^MySimulation$

Endpoint: simulation-run-zip

Similar to the download of a scenario as a ZIP archive via the workspace/scenario-zip endpoint, raw outputs and other results from a single simulation run can also be retrieved as a ZIP archive from the workspace. This can be achieved by the workspace/simulation-run-zip/{simulation_run_id} endpoint. It works in a similar fashion as the workspace/scenario-zip endpoint, as it triggers a background task to collect the output files and build the archive. The workspace/simulation-run-zip-status endpoint can be used in inquire about the execution status of the background task and retrieve the download uri after its successful completion.

sequenceDiagram
    participant C as Client
    participant S as SESAM API
    Note over C,S: Download outputs of simulation with id = 13
    C->>+S: GET workspace/simulation-run-zip/13
    S->>-C: status_url for task status
    loop until state == "SUCCESS"
        C->>+S: GET status_url
        S->>-C: { ... state, download_url, ...}
    end

Here is an example python code for creating a zip archive of the outputs of a simulation with the id 13.

Example Code
import time

import requests

with requests.Session() as session:
    # Login and update the http header with the access token (see above)

    # Trigger zip creation for simulation 13
    response = session.get("https://sesam.co4e.com/api/v1/workspace/simulation-run-zip/13")

    # Retrieve the endpoint to query the task status
    status_url = response.json().get("status_url")

    # Check if zip has been created
    download_url = None
    while not download_url:
        response = session.get(status_url)
        # Check if zip creation task finished
        if response.json().get("state", "") == "SUCCESS":
            download_url = response.json().get("download_url")
        else:
            # Delay the next polling
            time.sleep(0.5)

    # Zip archive can be retrieved from URL in download_url

Scenario and simulation vTypes

Scenario details (workspace/scenario/{id}, workspace/guest-scenario/{id}, and workspace/builtin-scenario/{id}) expose a relational, read-only vtypes list. ScenarioVType.scale is the current effective demand scaling factor in the scenario files, including demand edits. It is not a separate original-scale or multiplier value, and is null when the vType has no explicit scale (the SUMO default applies). The list also includes SUMO's built-in default types (DEFAULT_*); those are not scenario-defined and cannot be scaled through the Editor.

Simulation details (workspace/simulation/{id} and workspace/guest-simulation/{id}) expose independent vtypes snapshots copied from the scenario when the simulation is configured. Ownership and plan checks apply to both endpoints.

Each entry contains vtype_id, vehicle_class, accel, decel, height, width, length, max_speed, min_gap, tau, scale, time_to_teleport, and time_to_teleport_bidi. Scenario scale is null when unset; simulation snapshots resolve it to the effective factor (1.0 when the scenario left it unset). Teleport values are null when they cannot be resolved reliably from the definition, inheritance, or explicit scenario configuration.

Scenario responses also include demand_vehicle_count, demand_trip_count, demand_flow_count, demand_person_count, and demand_person_flow_count. These count source definitions, not the number of entities SUMO will insert. Missing discovery information is represented as null.

The Analyzer endpoint analyzer/ds/vtypes/{simulation_run_id} resolves SimulationRun -> Simulation -> SimulationVType. Its compatible dictionary is keyed by vType ID and requires no run-specific metadata artifact.