JSON API
========

Overview
--------

The OMERO JSON API described here provides create, read, update and delete
access to an underlying OMERO server. It is implemented as a Django app
named ``api`` in the OMERO.web framework.


Omero-marshal and Projection-based APIs
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The majority of the API URLs use `omero-marshal <https://github.com/ome/omero-marshal>`_
to generate JSON dictionaries from OMERO **model** objects.
All these URLs are under the ``m`` prefix:

::

    <server>/api/v0/m/


The webclient currently uses a small number of URLs to perform customized
queries for browsing Project, Dataset and Image hierarchies.
These queries use **projections** and typically load a subset of fields for
OMERO objects in order to improve performance for large data counts.
These will be made available under the ``p`` prefix in future releases
but are not yet supported.

::

    <server>/api/v0/p/


Versioning
^^^^^^^^^^

The JSON API uses major and minor version numbers to reflect breaking
and non-breaking changes respectively. Non-breaking changes include simple
addition of attributes to JSON data or addition of new URLs.
The API version is not tied to the version of OMERO.server.

The major version is included in the URL such as ``/v0/`` whereas the full
version number can be found in the header:

::

    X-OMERO-ApiVersion : 0.2


JSON format
^^^^^^^^^^^

The JSON objects generated by `omero-marshal <https://github.com/ome/omero-marshal>`_
are defined by the :model_doc:`OME-Model <ome-xml/>`. The OMERO model closely follows the
OME schema but is not identical. In the cases where OMERO-specific fields are included, these
will be prefixed by ``omero:``. For example, ``omero:details`` specifies the owner, group and
permissions of each object in OMERO.
JSON objects also include an ``@id`` of the object in the OMERO database and a ``@type`` that specifies
the OME Schema used to generate it such as ``http://www.openmicroscopy.org/Schemas/OME/2016-06#Project``.

All the fields of the OMERO model object will be included in the JSON except those that are ``null``,
which will be omitted.
Where supported, modifying the JSON object and saving this back to OMERO will update the object accordingly.


URLs in JSON
^^^^^^^^^^^^

URLs are included in JSON objects using keys with the ``url:`` prefix. URLs are added for
related objects to facilitate exploration of the API in a browser. You may find that a
JSON formatting plugin for your browser improves both the presentation and
navigation of JSON data.


Pagination
^^^^^^^^^^

Requests that return a list of items will be paginated, showing
a ``limit`` of the first 200 objects by default.
Pagination can be specified using the ``limit`` and ``offset`` query
parameters:

::

    # List the first 100 Projects (offset=0 by default)
    <server>/api/v0/m/projects/?limit=100

    # List the next 100 Projects
    <server>/api/v0/m/projects/?limit=100&offset=100


Pagination details will be returned in a ``meta`` JSON object, including
the ``totalCount`` of objects for that query, the current ``offset`` and
``limit`` as well as the ``maxLimit`` that you can use.

::

    "meta": {
        "totalCount": 13240,
        "maxLimit": 500,
        "limit": 200,
        "offset": 0
    },

Sysadmins can configure the default ``limit`` and ``maxLimit`` settings
for their server, for example:

::

    $ omero config set omero.web.api.limit 100
    $ omero config set omero.web.api.max_limit 300

The ``maxLimit`` setting prevents API consumers from requesting very
large amounts of data by limiting the number of top-level objects that
are loaded.


Loading of linked objects
^^^^^^^^^^^^^^^^^^^^^^^^^

In most cases the API loads only the requested objects along with
their ``omero:details``. For example, ``/api/v0/m/projects/`` loads
Projects but does not also load their child Datasets.
However, it is sometimes useful to load a number of closely related objects.
For example, loading Images also loads their Pixels data (but not Channels)
and loading Wells also loads WellSamples (fields) and Images (but not Pixels).
The number of objects loaded when listing Images or Wells is kept to
a minimum to avoid requesting too much data. This restriction is relaxed when
a single Image or Well is loaded. For example, loading a single Image will also
load Channels.



Normalizing Experimenters and Groups
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

When returning a list of JSON objects that each contain ``omero:details`` with
``owner`` and ``group`` data, these will typically be nested many times
within the list. In order to avoid this duplication, we can remove objects from
within each ``omero:details`` and place them under top-level ``experimenters``
and ``experimenterGroups`` lists.
You can specify this with the ``?normalize=true`` query parameter.
N.B.: Currently this normalizing will only apply to the top-level objects
being listed, such as Projects, Datasets and Images. Where child objects
are also loaded (for example Pixels within an Image), the ``omero:details``
of these objects will not be affected by the ``?normalize=true`` parameter.


Child counts
^^^^^^^^^^^^

For container objects such as Projects, Datasets and Screens it is
often useful to know the number of children within them. This can be
specified with ``?childCount=true`` parameter.
This will add an ``omero:childCount`` value to the JSON data.


Filtering by Owner and Group
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Most data in OMERO has an ``Owner`` and is assigned to a permissions
``Group``. By default, queries will return data from all owners
across all groups that are accessible to the current user.
Use the query strings to filter by owner and/or group:

::

    /api/v0/m/projects/?owner=3&group=5

When you are retrieving data using an object ID you will not need to
filter by ``group`` since all the data will be in the same group.
For example, Datasets in a specified Project will all be in the
same group as the Project.


Error handling
^^^^^^^^^^^^^^

Errors will result in responses with an appropriate status and may include
JSON content with a ``message`` to provide more information:

 -  **404 Not Found**: Caused by an invalid URL or when a specified
    object cannot be found in OMERO.

 -  **400 Bad Request**: May be caused by invalid query parameters or
    submitting invalid JSON content. For example,
    ``?limit=foo`` will give a response of:
    ::

        {"message": "invalid literal for int() with base 10: 'foo'"}

 -  **405 Method Not Allowed**: Returned if you try to use the
    wrong http method for a url, such as ``POST`` to ``/api/v0/m/projects/``.
    It can also be caused by trying to create or update an unsupported object,
    such as an Image.

 -  **500 Internal Server Error**: Generated from any unhandled exceptions.
    See the ``message`` returned and check whether a ``stacktrace`` is also included.



Getting started
---------------

You may find this
`example python script <https://github.com/ome/openmicroscopy/blob/develop/examples/Training/python/Json_Api/Login.py>`_ useful.
It uses the python ``requests`` library to connect to the JSON api, login, query data, create and delete Projects.
These steps are covered in more detail below.

For an example how to use the API with Java,
see :download:`JSONClient.java </examples/java/JSONClient.java>`.

See the following link for a JSON client example
:source:`examples/Training/javascript/index.html`.

List supported versions
^^^^^^^^^^^^^^^^^^^^^^^

You need to find which versions of the API are supported by your server,
as described above. These are provided by the base URL:

::

    GET     /api/


**Response**

::

    {
      "data": [
        {
          "version": "0",
          "url:base": "http://<server>/api/v0/"
        }
      ]
    }


List starting URLs
^^^^^^^^^^^^^^^^^^

The base URL for the chosen version will list a number of URLs for
logging on and getting started.

::

    GET     /api/v0/


**Response**

::

    {
      "url:login": "http://<server>/api/v0/login/",
      "url:save": "http://<server>/api/v0/m/save/",
      "url:projects": "http://<server>/api/v0/m/projects/",
      "url:plates": "http://<server>/api/v0/m/plates/",
      "url:datasets": "http://<server>/api/v0/m/datasets/",
      "url:token": "http://<server>/api/v0/token/",
      "url:schema": "http://www.openmicroscopy.org/Schemas/OME/2016-06",
      "url:screens": "http://<server>/api/v0/m/screens/",
      "url:servers": "http://<server>/api/v0/servers/",
      "url:images": "http://<server>/api/v0/m/images/"
    }


List available OMERO servers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Your API may allow you to connect to several different OMERO servers.

::

    GET     /api/v0/servers/


**Response**

::



    {
      "data": [
        {
          "host": "<server>",
          "server": "omero",
          "id": 1,
          "port": 4064
        }
      ]
    }


Get CSRF token
^^^^^^^^^^^^^^

In order to prevent CSRF attacks, CSRF tokens are required for any
POST, PUT and DELETE requests. You will need to obtain a CSRF token
for your session and use it for all subsequent requests in that session.
You can obtain this from the ``csrftoken``
cookie of any request or from the following URL:

::

    GET     /api/v0/token/


**Response**

::

    {
      "data": "eNoVq528bOqlhQqbCzKuviODTRX3PUO2"
    }

If you are using the API over HTTPS, you will also need to set the ``Referer`` key in 
request headers when supplying the CSRF token to other endpoints. The referer URI 
needs to be an address on the same domain as the server for the token to be accepted.


Login
^^^^^

You can login to create an OMERO session. You must also include the CSRF token,
either in the POST parameters as ``csrfmiddlewaretoken`` or in the session
header as ``X-CSRFToken``.

The EventContext for this session will be returned to you.

::

    POST    /api/v0/login/


**Parameters**

::

    Name                  Type        Description
    ------------------------------------------------------------------
    server                Number      ID of the server
    username              String      User's username
    password              String      User's password
    csrfmiddlewaretoken   String      CSRF token (can be provided in header)


**Response**

::

    {
      "eventContext": {
        "userName": "ben",
        "eventId": -1,
        "sessionUuid": "0b30ee4a-c0b2-4b0f-9c61-f48b31bcad8c",
        "eventType": "User",
        "userId": 3,
        "sessionId": 171319,
        "groupName": "Nevis Lab",
        "isAdmin": False,
        "memberOfGroups": [5, 1, 4],
        "leaderOfGroups": [],
        "groupId": 5
      },
      "success": true
    }


Projects, Datasets and Images
-----------------------------

OMERO organizes Images in two types of many-to-many hierarchy:
``screen/plate/[run]/well/image`` for HCS data and ``project/dataset/image``
for other data. Plates, Datasets and Images can also be ``Orphaned`` if not
contained within any parent container.


**Parameters**

These query parameters are used by many queries below:

::

    Name        Type        Description
    ------------------------------------------------------------------
    offset      Number      Pagination offset. The default is 0

    limit       Number      The size of each page. The default is 200

    normalize   Boolean     Place Experimenters and Groups into top-level lists instead
                            of nesting within objects
    childCount  Boolean     Use ?childCount=true to include an omero:childCount attribute
                            for container objects
    owner       Number      Filter by Experimenter ID

    group       Number      Filter by Group ID


List Projects
^^^^^^^^^^^^^

**Parameters**

::

    Name        Type        Description
    ------------------------------------------------------------------
    dataset     Number      Filter Projects by child Dataset ID


These query parameters are also supported (see above):

::

    offset, limit, owner, group, childCount, normalize


::

    GET     /api/v0/m/projects/


**Response**

::

    {
      "data": [
        {
          "Name": "New data",
          "Description": "Example Project",
          "url:project": "https://server.openmicroscopy.org/api/v0/m/projects/11601/",
          "url:datasets": "https://server.openmicroscopy.org/api/v0/m/projects/11601/datasets/",
          "@id": 11601,
          "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Project",
          "omero:details": {
            "owner": {
              "UserName": "ben",
              "FirstName": "Ben",
              "MiddleName": "",
              "omero:details": {
                "@type": "TBD#Details",
                "permissions": {
                  "isUserWrite": false,
                  "isWorldWrite": false,
                  "canDelete": false,
                  "isWorldRead": false,
                  "perm": "------",
                  "canEdit": false,
                  "canAnnotate": false,
                  "isGroupAnnotate": false,
                  "isGroupWrite": false,
                  "canLink": false,
                  "isUserRead": false,
                  "@type": "TBD#Permissions",
                  "isGroupRead": false
                }
              },
              "Email": "",
              "LastName": "Nevis",
              "@id": 0,
              "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Experimenter"
            },
            "group": {
              "omero:details": {
                "@type": "TBD#Details",
                "permissions": {
                  "isUserWrite": true,
                  "isWorldWrite": false,
                  "canDelete": false,
                  "isWorldRead": false,
                  "perm": "rwra--",
                  "canEdit": false,
                  "canAnnotate": false,
                  "isGroupAnnotate": true,
                  "isGroupWrite": false,
                  "canLink": false,
                  "isUserRead": true,
                  "@type": "TBD#Permissions",
                  "isGroupRead": true
                }
              },
              "@id": 5,
              "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#ExperimenterGroup",
              "Name": "read-ann"
            },
            "@type": "TBD#Details",
            "permissions": {
              "isUserWrite": true,
              "isWorldWrite": false,
              "canDelete": false,
              "isWorldRead": false,
              "perm": "rwra--",
              "canEdit": false,
              "canAnnotate": true,
              "isGroupAnnotate": true,
              "isGroupWrite": false,
              "canLink": false,
              "isUserRead": true,
              "@type": "TBD#Permissions",
              "isGroupRead": true
            }
          }
        }
      ]
    }


Get a single Project
^^^^^^^^^^^^^^^^^^^^

::

    GET   /api/v0/m/projects/{project_id}/


**Response**

::

    {
      "data": {
        "@id": 3872,
        "Name": "RNAi experiments",
        "Description": "Knockout assays",
        "url:datasets": "https://server.openmicroscopy.org/api/v0/m/projects/3872/datasets/",
        "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Project",
        "omero:details": {
          # omitted for brevity
        }
      }
    }

List Datasets
^^^^^^^^^^^^^

**Parameters**

::

    Name        Type        Description
    ------------------------------------------------------------------
    project     Number      Filter Datasets by parent Project ID

    image       Number      Filter Datasets by child Image ID

    orphaned    Boolean     Find Datasets that are not in any Project


These query parameters are also supported (see above):

::

    offset, limit, owner, group, childCount, normalize

::

    GET     /api/v0/m/datasets/

**Response**

::

    {
      "data": [
        {
          "Name": "Test data",
          "Description": "This is the Dataset description",
          "url:dataset": "https://server.openmicroscopy.org/api/v0/m/dataset/112/",
          "url:images": "https://server.openmicroscopy.org/api/v0/m/datasets/112/images/",
          "url:projects": "https://server.openmicroscopy.org/api/v0/m/datasets/112/projects/",
          "@id": 112,
          "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Project",
          "omero:details": {
            # omitted for brevity
          }
        }
      ]
    }


**Datasets in a Project**

Datasets can be filtered by parent Project using the ``?project=id`` query string but
you can also show Datasets in a Project using this URL:


::

    GET     /api/v0/m/projects/{project_id}/datasets/


Get a single Dataset
^^^^^^^^^^^^^^^^^^^^

::

    GET   /api/v0/m/datasets/{dataset_id}/

**Response**

::

    {
      "data": {
        "@id": 9702,
        "Name": "My data",
        "Description": "An example set",
        "url:images": "https://server.openmicroscopy.org/api/v0/m/datasets/9702/images/",
        "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Dataset",
        "omero:details": {
          # omitted for brevity
        }
      }
    }


List Images
^^^^^^^^^^^

When Images are listed, their ``Pixels`` object is also loaded, which
includes dimensions and pixel sizes of the Image.
When a single Image is retrieved, the ``Channels`` data is additionally
loaded.


**Parameters**

::

    Name        Type        Description
    ------------------------------------------------------------------
    dataset     Number      Filter Images by parent Dataset ID

    orphaned    Boolean     Find Images that are not in any Dataset or Well


These query parameters are also supported (see above):

::

    offset, limit, owner, group, normalize

::

    GET     /api/v0/m/images/


**Response**

::

    {
      "data": [
        {
          "@id": 16783,
          "Name": "CFP_AurB_R3D.dv",
          "AcquisitionDate": 1235730332000,
          "omero:details": {
            # omitted for brevity
          },
          "url:image": "https://server.openmicroscopy.org/api/v0/m/images/16783/",
          "Pixels": {
            "@id": 12801,
            "SizeX": 512,
            "SizeY": 512,
            "SizeZ": 29,
            "SizeC": 2,
            "SizeT": 1,
            "PhysicalSizeX": {
              "Symbol": "µm",
              "Value": 0.12698,
              "@type": "TBD#LengthI",
              "Unit": "MICROMETER"
            },
            "PhysicalSizeY": {
              "Symbol": "µm",
              "Value": 0.12698,
              "@type": "TBD#LengthI",
              "Unit": "MICROMETER"
            },
            "PhysicalSizeZ": {
              "Symbol": "µm",
              "Value": 0.2,
              "@type": "TBD#LengthI",
              "Unit": "MICROMETER"
            },
            "Type": {
              "omero:details": {
                # omitted for brevity
              },
              "@id": 6,
              "@type": "TBD#PixelsType",
              "value": "uint16"
            },
            "omero:sha1": "eae01c54191fd9cf4b09e3651e1899d677375b7d",
            "omero:details": {
              # omitted for brevity
            },
            "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Pixels",
            "SignificantBits": 16
          },
          "omero:series": 0,
          "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Image"
        }
      ]
    }


**Images in a Dataset**

Images can be filtered by parent Dataset using the ``?dataset=id`` query string but
you can also show Images in a Dataset using this URL:


::

    GET     /api/v0/m/datasets/{dataset_id}/images/


Get a single Image
^^^^^^^^^^^^^^^^^^

::

    GET   /api/v0/m/images/{image_id}/

**Response**

The response for a single Image is the same as for listing Images
above with the addition of ``Channels`` data.

::

    {
      "data": [
        {
          "@id": 16783,
          "Name": "CFP_AurB_R3D.dv",
          "AcquisitionDate": 1235730332000,
          "omero:details": {
            # omitted for brevity
          },
          "Pixels": {
            "@id": 12801,
            "Channels": [
              {
                "omero:photometricInterpretation": {
                  "omero:details": {},
                  "@id": 5,
                  "@type": "TBD#PhotometricInterpretation",
                  "value": "Monochrome"
                },
                "Name": "CFP_JP4",
                "Color": 65535,
                "omero:details": {},
                "ExcitationWavelength": {
                  "Symbol": "nm",
                  "Value": 436,
                  "@type": "TBD#LengthI",
                  "Unit": "NANOMETER"
                },
                "SamplesPerPixel": 1,
                "NDFilter": 1,
                "EmissionWavelength": {
                  "Symbol": "nm",
                  "Value": 470,
                  "@type": "TBD#LengthI",
                  "Unit": "NANOMETER"
                },
                "omero:LogicalChannelId": 12301,
                "@id": 14451,
                "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Channel"
              },
              {
                "omero:photometricInterpretation": {
                  "omero:details": {},
                  "@id": 5,
                  "@type": "TBD#PhotometricInterpretation",
                  "value": "Monochrome"
                },
                "Name": "RD_TR-PE",
                "Color": -16776961,
                "omero:details": {},
                "ExcitationWavelength": {
                  "Symbol": "nm",
                  "Value": 555,
                  "@type": "TBD#LengthI",
                  "Unit": "NANOMETER"
                },
                "SamplesPerPixel": 1,
                "NDFilter": 0,
                "EmissionWavelength": {
                  "Symbol": "nm",
                  "Value": 617,
                  "@type": "TBD#LengthI",
                  "Unit": "NANOMETER"
                },
                "omero:LogicalChannelId": 12303,
                "@id": 14453,
                "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Channel"
              }
            ],
            "SizeX": 512,
            "SizeY": 512,
            "SizeZ": 29,
            "SizeC": 2,
            "SizeT": 1,
            "PhysicalSizeX": {
              "Symbol": "µm",
              "Value": 0.12698,
              "@type": "TBD#LengthI",
              "Unit": "MICROMETER"
            },
            "PhysicalSizeY": {
              "Symbol": "µm",
              "Value": 0.12698,
              "@type": "TBD#LengthI",
              "Unit": "MICROMETER"
            },
            "PhysicalSizeZ": {
              "Symbol": "µm",
              "Value": 0.2,
              "@type": "TBD#LengthI",
              "Unit": "MICROMETER"
            },
            "Type": {
              "omero:details": {
                # omitted for brevity
              },
              "@id": 6,
              "@type": "TBD#PixelsType",
              "value": "uint16"
            },
            "omero:sha1": "eae01c54191fd9cf4b09e3651e1899d677375b7d",
            "omero:details": {
              # omitted for brevity
            },
            "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Pixels",
            "SignificantBits": 16
          },
          "omero:series": 0,
          "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Image"
        }
      ]
    }


Screens, Plates and Wells
-------------------------

For more information on the Screen, Plate, Well data model, please see the
:model_doc:`documentation page <developers/screen-plate-well.html>`.

List Screens
^^^^^^^^^^^^

**Parameters**

::

    Name        Type        Description
    ------------------------------------------------------------------
    plate       Number      Filter Datasets by child Plate ID


These query parameters are also supported (see above):

::

    offset, limit, owner, group, childCount, normalize

::

    GET     /api/v0/m/screens/

**Response**

::

    {
      "data": [
        {
          "@id": 582,
          "Name": "Test data",
          "Description": "This is the Screen description",
          "url:screen": "https://server.openmicroscopy.org/api/v0/m/screen/582/",
          "url:plates": "https://server.openmicroscopy.org/api/v0/m/screen/582/plates/",
          "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Screen",
          "omero:details": {
            # omitted for brevity
          }
        }
      ]
    }


Get a single Screen
^^^^^^^^^^^^^^^^^^^

::

    GET   /api/v0/m/screens/{screen_id}/

**Response**

::

    {
      "data": {
        "@id": 582,
        "Name": "Test data",
        "Description": "This is the Screen description",
        "url:plates": "https://server.openmicroscopy.org/api/v0/m/screen/582/plates/",
        "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Screen",
        "omero:details": {
          # omitted for brevity
        }
      }
    }


List Plates
^^^^^^^^^^^

**Parameters**

::

    Name        Type        Description
    ------------------------------------------------------------------
    screen      Number      Filter Plates by parent Screen ID

    well        Number      Filter Plates by child Well ID

    orphaned    Boolean     Find Plates that are not in any Screen


These query parameters are also supported (see above):

::

    offset, limit, owner, group, childCount, normalize

::

    GET     /api/v0/m/plates/

**Response**

::

    {
      "data": [
        {
          "@id": 5067,
          "Name": "Plate name",
          "Rows": 8,
          "Columns": 12,
          "RowNamingConvention": "letter",
          "ColumnNamingConvention": "number",
          "ExternalIdentifier": "003857",
          "url:plate": "https://server.openmicroscopy.org/api/v0/m/plates/5067/",
          "url:plateacquisitions": "https://server.openmicroscopy.org/api/v0/m/plates/5067/plateacquisitions/",
          "url:wells": "https://server.openmicroscopy.org/api/v0/m/plates/5067/wells/",
          "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Plate",
          "omero:details": {
            # omitted for brevity
          }
        },
      ]
    }


**Plates in a Screen**

Plates can be filtered by parent Screen using the ``?screen=id`` query string but
you can also show Plates in a Screen using this URL:


::

    GET     /api/v0/m/screens/{screen_id}/plates/


Get a single Plate
^^^^^^^^^^^^^^^^^^

::

    GET   /api/v0/m/plates/{plate_id}/

**Response**

The response for a single Plate includes information on the WellSamples (fields) for
each Well such as the min/max WellSampleIndex for the Plate.

::

    {
      "data": {
        "@id": 5067,
        "Name": "Plate name",
        "Rows": 8,
        "Columns": 12,
        "RowNamingConvention": "letter",
        "ColumnNamingConvention": "number",
        "ExternalIdentifier": "003857",
        "url:plate": "https://server.openmicroscopy.org/api/v0/m/plates/5067/",
        "url:plateacquisitions": "https://server.openmicroscopy.org/api/v0/m/plates/5067/plateacquisitions/",
        "url:wells": "https://server.openmicroscopy.org/api/v0/m/plates/5067/wells/",
        "url:wellsampleindex_wells": [
          "https://server.openmicroscopy.org/api/v0/m/plates/5068/wellsampleindex/0/wells/",
          "https://server.openmicroscopy.org/api/v0/m/plates/5068/wellsampleindex/1/wells/",
          "https://server.openmicroscopy.org/api/v0/m/plates/5068/wellsampleindex/2/wells/",
          "https://server.openmicroscopy.org/api/v0/m/plates/5068/wellsampleindex/3/wells/"
        ],
        "omero:wellsampleIndex": [
          0,
          3
        ],
        "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Plate",
        "omero:details": {
          # omitted for brevity
        }
      }
    }


List Plate Acquisitions
^^^^^^^^^^^^^^^^^^^^^^^

A Plate Acquisition (run) is a collection of WellSamples, grouped by an acquisition time.
A Plate may contain zero, one or more Plate Acquisitions.

::

    GET   /api/v0/m/plates/{plate_id}/plateacquisitions/


**Response**

::

    {
      "data": [
        {
          "@id": 4217,
          "url:wellsampleindex_wells": [
            "https://server.openmicroscopy.org/api/v0/m/plateacquisitions/4217/wellsampleindex/0/wells/"
            "https://server.openmicroscopy.org/api/v0/m/plateacquisitions/4217/wellsampleindex/1/wells/"
            "https://server.openmicroscopy.org/api/v0/m/plateacquisitions/4217/wellsampleindex/2/wells/"
          ],
          "omero:details": {
            # omitted for brevity
          },
          "MaximumFieldCount": 3,
          "url:plateacquisition": "https://server.openmicroscopy.org/api/v0/m/plateacquisitions/4217/",
          "omero:wellsampleIndex": [
            0,
            2
          ],
          "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#PlateAcquisition"
        }
      ]
    }


List Wells in a Plate
^^^^^^^^^^^^^^^^^^^^^

Each Well in a Plate may contain zero, one or many WellSamples (fields).
By default, when listing Wells in a Plate, *all* of the WellSamples and Images
will be loaded for each Well. Wells are ordered by Column and Row.


**Parameters**

The following query parameters can be used (as described above)
::

    offset, limit, owner, normalize

::

    GET   /api/v0/m/plates/{plate_id}/wells/


.. note::

    If there are a large number of WellSamples per Well, this has the
    potential to load a large amount of data. This can be reduced by using
    a smaller ``limit`` on the number of Wells loaded or only loading a single
    WellSample per Well, as described below.


**Response**

::

    {
      "data": [
        {
          "@id": 139,
          "Column": 0,
          "Row": 0,
          "omero:details": {
            # omitted for brevity
          },
          "url:well": "https://server.openmicroscopy.org/api/v0/m/wells/139/",
          "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Well",
          "WellSamples": [
            {
              "PositionX": {
                "Symbol": "reference frame",
                "Value": 21864.47,
                "@type": "TBD#LengthI",
                "Unit": "REFERENCEFRAME"
              },
              "PositionY": {
                "Symbol": "reference frame",
                "Value": 36711.98,
                "@type": "TBD#LengthI",
                "Unit": "REFERENCEFRAME"
              },
              "omero:details": {
                # omitted for brevity
              },
              "Image": {
                "Name": "plate1.HTD [Well E02 Field #1]",
                "AcquisitionDate": 1252939626000,
                "omero:details": {
                  # omitted for brevity
                },
                "url:image": "https://server.openmicroscopy.org/api/v0/m/images/2942/",
                "omero:series": 120,
                "@id": 2942,
                "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Image",
                "Description": "Scan Time: Mon Sep 14 11:36:58 2009"
              },
              "PlateAcquisition": {
                "omero:details": {
                  # omitted for brevity
                },
                "MaximumFieldCount": 4,
                "StartTime": 1252938959000,
                "EndTime": 1252939813000,
                "@id": 102,
                "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#PlateAcquisition"
              },
              "@id": 203,
              "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#WellSample"
            }
          ]
        }
      ]
    }

It is also possible to list all Wells without filtering by Plate, using the top-level
URL ``/api/v0/m/wells/`` optionally filtering by the ``plate`` query parameter.


List Wells by WellSample Index
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

To list Wells in a Plate, loading only a *single* WellSample and Image per Well,
you can filter by WellSample Index. This list of Wells will not include empty
Wells (Wells that have no WellSamples and Images).

::

    GET   /api/v0/m/plates/{plate_id}/wellsampleindex/{index}/wells/


It is also possible to use the Plate Acquisition ID instead of
Plate ID, when the WellSample (field) at the specified index was acquired
as part of that Plate Acquisition:

::

    GET   /api/v0/m/plateacquisitions/{plateacquisition_id}/wellsampleindex/{index}/wells/


Get a single Well
^^^^^^^^^^^^^^^^^

When a single Well is loaded, this will include all the WellSamples and Images
with Pixels loaded.

::

    GET   /api/v0/m/wells/{well_id}/


ROIs and Shapes
---------------

Support for listing ROIs was added in API version 0.1.
ROIs are linked to Images and contain one or more Shapes. Types of
shape are Ellipse, Label, Line, Mask, Point, Polygon, Polyline
and Rectangle.

List ROIs
^^^^^^^^^

When ROIs are listed, their child Shapes will also be loaded.


**Parameters**

::

    Name        Type        Description
    ------------------------------------------------------------------
    image       Number      Filter ROIs by Image ID


These query parameters are also supported (see above):

::

    offset, limit, owner, group, normalize

::

    GET     /api/v0/m/rois/

**Response**

::

    {
      "data": [
        {
          "@id": 454,
          "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#ROI",
          "shapes": [
            {
              "FontStyle": "Normal",
              "Locked": false,
              "Width": 98,
              "omero:details": {
                # omitted for brevity
              },
              "Height": 135,
              "FontFamily": "sans-serif",
              "StrokeWidth": {},
              "FontSize": {
                "Symbol": "pt",
                "Value": 12,
                "@type": "TBD#LengthI",
                "Unit": "POINT"
              },
              "FillColor": 1073741824,
              "Y": 192,
              "X": 189,
              "StrokeColor": -993737532,
              "TheT": 23,
              "@id": 713,
              "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Rectangle",
              "TheZ": 1
            }
          ],
          "omero:details": {
            # omitted for brevity
          },
        },
      ]
    }

**ROIs on an Image**

ROIs can be filtered by Image using the ``?image=id`` query string but
you can also show ROIs on an Image using this URL:

::

    GET     /api/v0/m/images/{image_id}/rois/


Experimenters and Groups
------------------------

Support for listing Experimenters and Groups was added in API version 0.2.
Experimenters are users of OMERO and can belong to one or more Groups.
Groups are defined as ExperimenterGroups in the OME model.

Listing Experimenters
^^^^^^^^^^^^^^^^^^^^^

OMERO will only allow you to access details of Experimenters who are members of
a **non-private** group that you are also a member of.

**Parameters**

::

    Name                  Type        Description
    ------------------------------------------------------------------
    experimentergroup     Number      Filter Experimenters by Group


These query parameters are also supported (see above):

::

    offset, limit

::

    GET     /api/v0/m/experimenters/

**Response**

::

    {
      "data": [
        {
          "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Experimenter",
          "@id": 10,
          "omero:details": {
            "@type": "TBD#Details",
            "permissions": {
              "@type": "TBD#Permissions",
              "perm": "------",
              "canAnnotate": true,
              "canDelete": false,
              "canEdit": false,
              "canLink": true,
              "isWorldWrite": false,
              "isWorldRead": false,
              "isGroupWrite": false,
              "isGroupRead": false,
              "isGroupAnnotate": false,
              "isUserWrite": false,
              "isUserRead": false
            }
          },
          "FirstName": "Ben",
          "LastName": "Nevis",
          "UserName": "ben",
          "url:experimenter": "https://server.openmicroscopy.org/web/api/v0/m/experimenters/10/",
          "url:experimentergroups": "https://server.openmicroscopy.org/web/api/v0/m/experimenters/10/experimentergroups/"
        },
      ]
    }

Get a single Experimenter
^^^^^^^^^^^^^^^^^^^^^^^^^

Load an Experimenter with:

::

    GET   /api/v0/m/experimenters/{experimenter_id}/

Experimenters in a Group
^^^^^^^^^^^^^^^^^^^^^^^^

Experimenters can be filtered by Group using the ``?experimentergroup=id`` query string but
you can also show Members of a Group using this URL:

::

    GET     /api/v0/m/experimentergroups/{group_id}/experimenters/


Listing Groups
^^^^^^^^^^^^^^

**Parameters**

::

    Name             Type        Description
    ------------------------------------------------------------------
    experimenter     Number      Filter Groups by Experimenter


These query parameters are also supported (see above):

::

    offset, limit

::

    GET     /api/v0/m/experimentergroups/

**Response**

::

    {
      "data": [
        {
          "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#ExperimenterGroup",
          "@id": 10,
          "omero:details": {
            "@type": "TBD#Details",
            "permissions": {
              "@type": "TBD#Permissions",
              "perm": "------",
              "canAnnotate": true,
              "canDelete": false,
              "canEdit": false,
              "canLink": true,
              "isWorldWrite": false,
              "isWorldRead": false,
              "isGroupWrite": false,
              "isGroupRead": false,
              "isGroupAnnotate": false,
              "isUserWrite": false,
              "isUserRead": false
            }
          },
          "Name": "Swedlow Lab",
          "url:experimentergroup": "https://server.openmicroscopy.org/web/api/v0/m/experimentergroups/10/",
          "url:experimenters": "https://server.openmicroscopy.org/web/api/v0/m/experimentergroups/10/experimenters/"
        },
      ]
    }

Get a single Group
^^^^^^^^^^^^^^^^^^

Load a Group with:

::

    GET   /api/v0/m/experimentergroups/{group_id}/

Groups for an Experimenter
^^^^^^^^^^^^^^^^^^^^^^^^^^

Groups can be filtered by Experimenter using the ``?experimenter=id`` query string but
you can also show ExperimenterGroups that an Experimenter belongs to using this URL:

::

    GET     /api/v0/m/experimenters/{experimenter_id}/experimentergroups


Creating and saving objects
---------------------------

The JSON API currently supports creating and saving of a limited number of
object types, namely Projects, Datasets and Screens.
It is not yet possible to save objects with unloaded objects, such as an Image
without Pixels or Channels loaded. We will be working to resolve these issues
in future releases.

Creating and saving of JSON objects are handled by a single ``save`` URL
and objects are identified by their ``@type`` and ``@id`` attributes.


Object types
^^^^^^^^^^^^

The object ``@type`` must be based on the currently supported Schema URL
which can be retrieved with:

::

    GET     /api/v0/


**Response**

::

    {
      "url:schema": "http://www.openmicroscopy.org/Schemas/OME/2016-06",
      # other urls not shown
    }


This can then be used to create a ``@type`` by appending ``#`` and the
object name, such as:

::

    http://www.openmicroscopy.org/Schemas/OME/2016-06#Project


Creating objects
^^^^^^^^^^^^^^^^

To create an object, POST the JSON for that object, including the ID of the
OMERO group that the object should be saved in.
Currently only creation of Projects, Datasets and Screens is supported.

::

    POST  /api/v0/m/save/?group={group_id}


**Content**

::

    {
      "Name": "My new Project",
      "Description": "Created via the JSON API",
      "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Project"
    }


**Response**

::

    {
      "data": {
        "@id": 567,
        "Name": "My new Project",
        "Description": "Created via the JSON API",
        "url:datasets": "https://server.openmicroscopy.org/api/v0/m/projects/3872/datasets/",
        "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Project",
        "omero:details": {
          # omitted for brevity
        }
      }
    }


Updating objects
^^^^^^^^^^^^^^^^

The API supports PUT to replace existing objects with the submitted data.
As mentioned above, the only objects that you can currently update are
Projects, Datasets and Screens.
The submitted JSON data can be constructed from scratch, but it will generally
be more convenient and safer to GET the object, update it and save
the edited JSON.

For example, to edit the Name of the Project in the previous example:

::

    PUT   /api/v0/m/save/


**Content**

::

    {
      "@id": 567,
      "Name": "Edited Project Name",
      "Description": "Created via the JSON API",
      "url:datasets": "https://server.openmicroscopy.org/api/v0/m/projects/3872/datasets/",
      "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Project",
      "omero:details": {
        # omitted for brevity
      }
    }


**Response**

::

    {
      "data": {
        "@id": 567,
        "Name": "Edited Project Name",
        "Description": "Created via the JSON API",
        "url:datasets": "https://server.openmicroscopy.org/api/v0/m/projects/3872/datasets/",
        "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Project",
        "omero:details": {
          # omitted for brevity
        }
      }
    }


Deleting objects
^^^^^^^^^^^^^^^^

To delete a Project, Dataset or Screen, simply DELETE using the URL to that
object. The deleted object will be returned. For example, to delete a Project:

::

    DELETE  /api/v0/m/projects/{project_id}/


**Response**

::

    {
      "data": {
        "@id": 567,
        "Name": "Edited Project Name",
        "Description": "Created via the JSON API",
        "url:datasets": "https://server.openmicroscopy.org/api/v0/m/projects/3872/datasets/",
        "@type": "http://www.openmicroscopy.org/Schemas/OME/2016-06#Project",
        "omero:details": {
          # omitted for brevity
        }
      }
    }
