forio Toggle navigation

Model Run API

The Model Run API provides create, read, update, and delete (CRUD) capabilities for runs of a project.

A run is a collection of interactions with the project and its model. Every time you want to interact with a project, you need to create a new run.

The Model Run API supports the following methods:

The Model Run API operates on the following resources / data structures:

POST

Use the Model Run API POST method to create a new run.

Create a New Run


Method: POST

URI:

  • /v2/model/run

Headers:

Body: JSON object with the required fields:

  • account: The Account ID. This is the Team ID (for team projects) or User ID (for personal projects).
  • project: The Project ID.
  • model: The primary model file.
  • For a complete list of fields, see details on the run record.

Return Status:

  • 200: Successfully created run
  • 400: Invalid request (e.g. invalid account or project)
  • 500: Server error while starting the run (e.g. syntax errors in the model)

Return Body:

The new run record (JSON object) just created.


Example:

curl -X POST \
    'https://api.forio.com/v2/model/run/' \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
    --data '{"account": "acme", "project": "supply-chain-game", "model": "model.py"}'

Example Response:

{
    "user": {
        "id": "d730a1b5-5451-4627-b16d-f3a7ed63f039",
        "userName": "jsmith@acme.com",
        "firstName": "j",
        "lastName": "smith"
    },
    "files": null,
    "morphology": "MANY",
    "created": "2016-03-07T21:29:04.244Z",
    "lastModified": "2016-03-07T21:29:04.244Z",
    "id": "000001533965543534cd21a606beb8feb9c7",
    "account": "acme",
    "project": "supply-chain-game",
    "model": "model.py",
    "saved": false,
    "active": true,
    "initialized": true,
    "scope": null
}

Notes:

  • See the error record for more information on how to interpret possible errors.

Create a New Run Using an Existing Run ("Reset")

Sometimes you know that you will be creating the same kind of run — a run with the same account, project, and model — many times. In this case, you can use a variant of the Model Run API POST method to help optimize performance and speed up the creation of the new run: you can create a new run based on an existing run. The new run reuses the existing model session on the Epicenter backend server.


Method: POST

URI:

  • /v2/model/run/{original run id}

Headers:

Body: {}

Return Status:

  • 200: Successfully created run
  • 400: Invalid request (e.g. invalid account or project)
  • 500: Server error while starting the run (e.g. syntax errors in the model)

Return Body: The new run record (JSON object) just created.


Example:

curl -X POST \
    'https://api.forio.com/v2/model/run/00000152a9aa44e228363a623c14ed07ba34' \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
    --data '{}'

Example Response:

{
    "user": {
        "id": "d730a1b5-5451-4627-b16d-f3a7ed63f039",
        "userName": "jsmith@acme.com",
        "firstName": "j",
        "lastName": "smith"
    },
    "files": null,
    "morphology": "MANY",
    "created": "2016-03-07T21:29:04.244Z",
    "lastModified": "2016-03-07T21:33:52.443Z",
    "id": "000001533965543534cd21a606beb8feb9d6",
    "account": "acme",
    "project": "supply-chain-game",
    "model": "model.py",
    "saved": false,
    "active": true,
    "initialized": true,
    "scope": {}
}

Notes:

  • This request is valid both for existing runs that are currently in memory and for existing runs that are currently only in the database. (See more information on run persistence.)

  • This request:

    • Removes the original run id (the run id in the URI) from memory.
    • Calls a reset function, if your model subscribes to one (for example, see details for Python or R).
    • Creates a new run (returned in the response), reusing the existing model session on the Epicenter backend server to do so.
  • Note that relevant, existing run properties are copied from the original run to the new run. For example, scope.group is copied, but saved and initialized have their values set as for a new run created through POST /v2/model/run. See more information on the run record.

  • Optionally, you can pass in any of the same fields you pass in when creating a new run from scratch. For example, if you want to have the run in a different group, pass in {"scope": {"group": "newGroup"}} instead of {} in the body of this request.

  • See the error record for more information on how to interpret possible errors.

Retrieve Many Runs

Most of the time when you retrieve one or more run records, you use the GET request, described below.

However, sometimes when you would like to use the GET method for an API, your request may require a very long URI, for example: https://api.forio.com/v2/model/run?id=000001533965543534cd21a606beb8feb9d6&id=000002734969543534cd21a606beb8feb31c&id=....

For these situations, Epicenter APIs support the option of using a POST method with additional parameters in place of the GET method.


Method: POST

URI:

  • /v2/model/run?_method=GET

Headers:

Body: JSON object describing the query. For example:

{"id": ["000001533965543534cd21a606beb8feb9d6", "000002734969543534cd21a606beb8feb31c"]}

Return Status:

  • 200: Successfully retrieved runs

Return Body: An array of records (JSON objects) returned by the query.


Example:

curl -X POST \
    'https://api.forio.com/v2/model/run?_method=GET' \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
    --data '{"id": ["000001533965543534cd21a606beb8febb03", "000001533965543534cd21a606beb8febb07"] }'

Example Response:

[
    {
        "user": null,
        "files": null,
        "morphology": "MANY",
        "created": "2016-03-07T23:38:53.850Z",
        "lastModified": "2016-03-07T23:38:53.850Z",
        "id": "000001533965543534cd21a606beb8febb03",
        "account": "acme",
        "project": "supply-chain-game",
        "model": "model.py",
        "saved": false,
        "initialized": true,
        "scope": null
    },
            {
        "user": null,
        "files": null,
        "morphology": "MANY",
        "created": "2016-02-08T21:18:49.434Z",
        "lastModified": "2016-02-08T21:18:49.434Z",
        "id": "000001533965543534cd21a606beb8febb07",
        "account": "acme",
        "project": "supply-chain-game",
        "model": "model.py",
        "saved": false,
        "initialized": true,
        "scope": null
    }

]

GET

You can retrieve the run record for any run using the Run API GET method.

Retrieve One Run


Method: GET

URI:

  • /v2/model/run/{run id}

Headers:

Body: None

Return Status:

  • 200: Successful response
  • 400: Invalid request

Return Body: The run record (JSON object) for this run.


Example:

curl -G \
    'https://api.forio.com/v2/model/run/000001533965543534cd21a606beb8feb9d6' \
    --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \

Example Response:

{
    "user": {
        "id": "d730a1b5-5451-4627-b16d-f3a7ed63f039",
        "userName": "jsmith@acme.com",
        "firstName": "j",
        "lastName": "smith"
    },
    "files": null,
    "morphology": "MANY",
    "created": "2016-03-07T21:29:04.244Z",
    "lastModified": "2016-03-07T21:33:52.443Z",
    "id": "000001533965543534cd21a606beb8feb9d6",
    "account": "acme",
    "project": "supply-chain-game",
    "model": "model.py",
    "saved": false,
    "active": true,
    "initialized": true,
    "scope": {}
}

Notes:

Retrieve One or More Runs

When you retrieve runs using filters and sorts, all runs are retrieved from the database.


Method: GET

URI:

  • /v2/model/run/{filter, sort}

URI Optional Parameters:

  • The {filter} is a set of query parameters, and takes the format: ?field1=value1&field2=value2.

    Fields available for filtering include: id, account, project, model, saved, scope.worldId.

  • The {sort} is a query parameter indicating the field by which to sort the runs before they are returned, and a second query parameter with the direction of the sort. This takes the format: ?sort=field1&direction=dir.

    Fields available for sorting include: account, project, model, created, lastModified. The default is lastModified.

    The direction can be asc (ascending) or desc (descending). The default is desc.

  • See more information on the run record for a complete description of these fields.

Headers:

  • Authorization: Bearer{access token}

  • (Optional) Range: records {i}-{j}

    • Depending on your filter, this request may return many run records. The default page size is 100. You can limit the number of records returned by adding the Range header.

Body: None

Return Status:

  • 200: Successful response
  • 206: Successfully retrieved the partially complete response (for example if you request records 0-20 with the Range header and there are 35 records)
  • 400: Invalid request
  • 416: No records are found in a given search range (for example if you request records 10-15 with the Range header and there are only 8 records)

Return Body: An array of JSON objects with the run records matching the filter. If you have specified a Range header in the request, or if your request returns more than 100 run records, this may not be all of the run records matching your filter. The array includes only those records indicated in the Content-Range header.


Example (filtering):

curl -G \
    'https://api.forio.com/v2/model/run/?id=00000152a9aa44e228363a623c14ed07ba34' \
    --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \

Example Response:

[
    {
        "user": null,
        "files": null,
        "morphology": "MANY",
        "created": "2016-02-08T21:18:49.434Z",
        "lastModified": "2016-02-08T21:18:49.434Z",
        "id": "00000152a9aa44e228363a623c14ed07ba34",
        "account": "acme",
        "project": "supply-chain-game",
        "model": "model.py",
        "saved": false,
        "initialized": true,
        "scope": null
    }
]

Example (filtering and sorting):

curl -G \
    'https://api.forio.com/v2/model/run/?account=acme&project=supply-chain-game&sort=created&direction=asc' \
    --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \

Example Response:

[
    {
        "user": null,
        "files": null,
        "morphology": "MANY",
        "created": "2016-02-08T21:18:49.434Z",
        "lastModified": "2016-02-08T21:18:49.434Z",
        "id": "00000152a9aa44e228363a623c14ed07ba34",
        "account": "acme",
        "project": "supply-chain-game",
        "model": "model.py",
        "saved": false,
        "initialized": true,
        "scope": null
    },
    ... // other run records matching the filter, if any
        // ordered by created, ascending
]

Notes:

  • All runs are retrieved from the database.
  • If the sort parameter is not specified in the URI, the default sort is by lastModified.
  • If the direction parameter is not specified in the URI, the default direction is desc.
  • Optionally, you can add the query parameter ?include=active to your request. Then, the response includes the active field of the run record. This is true for runs that are currently in memory and false for runs that are only in the database.

  • Whether or not you add the Range header to your request, the response header contains:

      Content-Range: records i-j/k

    where i is the index of the first record returned, j is the index of the last record returned, and k is the total number of records in the result set, or * if that number is computationally infeasible (for instance, because you are querying across multiple projects).

    For example, Content-Range: records 0-9/57 or Content-Range: records 20-29/*.

    If no records are returned, the response body is empty and the Content-Range header in the response is

      Content-Range: records -/0

    If you leave off the start index, this is considered an implied start index of 0 rather than an invalid range. The response header includes status code of 200 or 206 depending on the ending index.

    This use of the Range header is part of the RFC 2616 (see details in Section 14.16 and 14.35).

PATCH

You can update some of the data in the run record using the Model Run API PATCH method.

Update Run Data


Method: PATCH

URI:

  • /v2/model/run/{run id}

Headers:

Body: JSON object whose fields are variable names and whose values are the updated variable values, e.g. { "fieldName1": "fieldValue1", "fieldName2": "fieldValue2"}.

Return Status:

  • 200: Successful response, property updated
  • 400: Invalid property or property that is read-only (see the run record for complete list of properties)

Return Body: A JSON object with the updated data.


Example:

curl -X PATCH \
    'https://api.forio.com/v2/model/run/00000152fbfbeae5d4e225640aebaef9abd7' \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
    --data '{ "saved": true }'

Example Response:

{
    "saved": true
}

Notes:

  • Currently you can only update the saved and initialized properties. These are flags in every run record that you can use to mark runs. (They are not related to whether the run is persisted in the database.)

DELETE

If you no longer need a particular run, you can remove it from memory using the Run API DELETE method.

Runs must be in memory in order for you to update variables or call operations on them. Runs are automatically replayed, and brought back into memory, when you attempt to update a model variable or call a model operation.

Remove One Run from this Project


Method: DELETE

URI:

  • /v2/model/run/{run id}

Headers:

Body: None

Return Status:

  • 200: Successful response, run deleted from memory

Return Body: The deleted run record.


Example:

curl -X DELETE \
    'https://api.forio.com/v2/model/run/000001533965543534cd21a606beb8febaeb' \
    --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \

Example Response:

{
    "user": {
        "id": "d730a1b5-5451-4627-b16d-f3a7ed63f039",
        "userName": "jsmith@acme.com",
        "firstName": "j",
        "lastName": "smith"
    },
    "files": null,
    "morphology": "MANY",
    "created": "2016-03-07T23:29:48.704Z",
    "lastModified": "2016-03-07T23:29:48.704Z",
    "id": "000001533965543534cd21a606beb8febaeb",
    "account": "acme",
    "project": "supply-chain-game",
    "model": "model.py",
    "saved": false,
    "initialized": true,
    "scope": null
}

Notes:

  • IMPORTANT: Note that this request only removes the run from memory on the Epicenter servers; it does not remove the run from the Epicenter backend database. See more information on run persistence.

Remove Multiple Runs from this Project


Method: DELETE

URI:

  • /v2/model/run?id={run id1}&id={run id2}

Headers:

Body: None

Return Status:

  • 200: Successful response, run deleted from memory

Return Body: An array of the deleted run records.


Example:

curl -X DELETE \
    'https://api.forio.com/v2/model/run?id=000001533965543534cd21a606beb8febb03&id=000001533965543534cd21a606beb8febb07' \
    --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \

Example Response:

[
    {
        "user": {
            "id": "d730a1b5-5451-4627-b16d-f3a7ed63f039",
            "userName": "jsmith@acme.com",
            "firstName": "j",
            "lastName": "smith"
        },
        "files": null,
        "morphology": "MANY",
        "created": "2016-03-07T23:38:36.896Z",
        "lastModified": "2016-03-07T23:38:36.896Z",
        "id": "000001533965543534cd21a606beb8febb03",
        "account": "acme",
        "project": "supply-chain-game",
        "model": "model.py",
        "saved": false,
        "initialized": true,
        "scope": null
    },
    {
        "user": {
            "id": "d730a1b5-5451-4627-b16d-f3a7ed63f039",
            "userName": "jsmith@acme.com",
            "firstName": "j",
            "lastName": "smith"
        },
        "files": null,
        "morphology": "MANY",
        "created": "2016-03-07T23:38:53.850Z",
        "lastModified": "2016-03-07T23:38:53.850Z",
        "id": "000001533965543534cd21a606beb8febb07",
            "account": "acme",
            "project": "supply-chain-game",
            "model": "model.py",
        "saved": false,
        "initialized": true,
        "scope": null
    }
]

Notes:

  • IMPORTANT: Note that this request only removes the run from memory on the Epicenter servers; it does not remove the run from the Epicenter backend database. See more information on run persistence.

You can retrieve metadata about a run using the Model Run API HEAD method.

Retrieving Metadata about the Run Record


Method: HEAD

URI:

  • /v2/model/run/{run id}

Headers:

Body: None.

Return Status:

  • 200: Successful response, property updated

Return Body: None. Only headers are returned.


Example:

curl -X HEAD \
    'https://api.forio.com/v2/model/run/00000152fbfbeae5d4e225640aebaef9abd7' \
    --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \

Example Response:

Only headers are returned.

Notes:

  • This request allows you to retrieve information written in response headers, including server information and resource last modified information, without having to retrieve all the data associated with a GET request.

  • In particular, this is useful for verifying whether you are retrieving the run from memory or from the database:

    • The Pragma field in the response header is present and set to persistent if this run is persisted in the Epicenter backend database.
    • The Pragma field is not present in the response header if the run is only in memory on the Epicenter servers.

OPTIONS

For any Epicenter API, use the OPTIONS method to view reference information on properties and arguments of that API.


Method: OPTIONS

URI: /v2/model/run


Example:

curl -X OPTIONS 'https://api.forio.com/v2/model/run'

Data Structure

The Model Run API operates on the Run record data structure. When a run cannot be created, an error is returned.

Run Record

The Run record describes the run. It is returned in response to any POST request. Either a Run record or an array of Run Records is returned in response to any GET request.

Field Required? Description
id yes The identifier of the run. Always included in a response; should not be included as part of a POST request.
account yes The Account ID of the account for which the run is created. This is the Team ID (for team projects) or User ID (for personal projects). Required when creating a run and always included in a response.
project yes The Project ID of the project for which the run is created. Required when creating a run and always included in a response.
model yes The name of the primary model file. This is the one file in the project where model execution should begin, and that explicitly exposes variables and operations. Required when creating a run and always included in a response.
user no Information about the user that created the run, including id, userName, firstName, lastName. If the access token used to create the run was a user access token, the user information is included; if it was a project access token, the user information is null.
scope no A description of where the run is available. Typically you use this if your project includes end users and groups; for example, the scope should always be passed in if this run belongs to an end user of your project.
  • group: The name of any local group in the project.
  • role: The role of the end user with access to this run: standard or facilitator.
  • worldId: For multiplayer games, the identifier of the world in which this run was created.
  • trackingKey: A string identifier, so you can easily group runs together. This is most common when you have a public project, but want to track all runs associated with a particular user.
created yes When the run record was created, in ISO 8601 format. Always included in a response; should not be included as part of a POST request.
lastModified yes When the run record was most recently updated, in ISO 8601 format. Always included in a response; should not be included as part of a POST request.
files no Only relevant for Vensim models. If you are using a Vensim model and you have additional data to pass in to your model, pass a files object that includes name : value pairs. (Note that you'll also need to add this same files object to your Vensim Model Context file.) Each name can be any designation you like. Each value is name of the file to load. This file must be in your project's Model folder. For example: "files": {"data": "myData.xlsx"} or "files": {"file1": "myFirstFile.xlsx", "file2": "mySecondFile.xlsx"}. See a complete example in How To: Use External Data in Vensim.
active yes This field is true if the run is currently in memory, and false if the run is only in the database. (See more on run persistence.) Always included in a response; should not be included as part of a POST request.
saved no A flag in the run record, set to false when the run is created. You can set this field as needed; its value is not tied to run creation or run persistence.
initialized no A flag in the run record, set to true when the run is created. You can set this field as needed; its value is not tied to run creation or run persistence.
morphology no Read only and internal use only.

**Example Run Record**

An example Run record returned as a response to a POST request:

{
    "user": {
        "id": "d730a1b5-5451-4627-b16d-f3a7ed63f039",
        "userName": "jsmith@acme.com",
        "firstName": "j",
        "lastName": "smith"
    },
    "files": null,
    "morphology": "MANY",
    "created": "2016-03-07T21:29:04.244Z",
    "lastModified": "2016-03-07T21:29:04.244Z",
    "id": "000001533965543534cd21a606beb8feb9c7",
    "account": "acme",
    "project": "supply-chain-game",
    "model": "model.py",
    "saved": false,
    "active": true,
    "initialized": true,
    "scope": null
}

Error Record

The Error record describes the problem when a run cannot be created. It is returned in response to a POST request that cannot be completed.

Error: 400 Invalid Request

When the POST request cannot be completed because of a problem with the request body, the response is a 400 error.

Field Required? Description
fault yes The kind of fault, if available.
type yes Kind of error, if available.
run_id yes The identifier of the run, if it was created.
message yes The specific error message.
error yes Boolean, set to true for all errors.

**Example: 400 Error Record**
{
    "fault": null,
    "type": "model_not_found",
    "run_id": "000001533965543534cd21a606beb8fec3a0",
    "message": "Could not locate model(/opt/forio/files/projects/acme/supply-chain-game2/model/model.py)",
    "error": true
}

Error: 500 Server Error

When the POST request cannot be completed because of a problem with the model, the response is a 500 error.

Field Required? Description
cause yes Specific cause, if available.
context yes Additional detail, if available.
trace yes The stack trace of the error, in the
information yes Additional detail, if available.
type yes Kind of error, if available.
message yes The specific error message, as provided by the environment listed in type.
native yes Internal use only.

**Example: 500 Error Record**
{
    "cause": null,
    "context": null,
    "trace": [
        {
            "type": "python",
            "function": "__execute__",
            "file": "/usr/local/lib/python3.4/dist-packages/epicenter-py3.5.egg/epicenter/worker/python/python_worker.py",
            "line": 61
        }
    ],
    "information": null,
    "type": "python",
    "message": "SyntaxError: invalid syntax (model.py, line 7)",
    "native": null
}