view Sphinx/source/users/rest.rst @ 1032:6814e5adb789

end of dual licensing and cla
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 02 Feb 2024 16:37:39 +0100
parents a3436ae3709c
children d2be251975d1
line wrap: on
line source

.. _rest:

REST API of Orthanc
===================

.. contents::
   :depth: 3

One of the major strengths of Orthanc lies in its built-in `RESTful
API
<https://en.wikipedia.org/wiki/Representational_state_transfer>`__,
that can be used to drive Orthanc from external applications,
independently of the programming language that is used to develop
these applications. The REST API of Orthanc gives a full programmatic
access to all the core features of Orthanc.

Importantly, Orthanc Explorer (the embedded administrative interface
of Orthanc) entirely resorts to this REST API for all its features.
This implies that anything that can be done through Orthanc Explorer,
can also be done through REST queries.

*Note:* All the examples are illustrated with the `cURL command-line
tool <https://curl.haxx.se/>`__, but equivalent calls can be readily
transposed to any programming language that supports both HTTP and
JSON.


.. _curl-windows:

Warning about using cURL from the Windows prompt
------------------------------------------------

The examples on this page assume that the user is running a bash shell
on some GNU/Linux distribution. Such a shell has the major advantage
of having the possibility to use either single-quote or double-quotes
characters in order to group a set of characters (including spaces) as
a whole string.

.. highlight:: bash

Unfortunately, the default command-line prompt of Microsoft Windows
**doesn't support single-quote characters**. If you copy/paste a cURL
command-line from this page that mixes single-quote and double-quotes,
it won't work as such, and you'll have to replace single-quotes by
double-quotes, and prefix the double-quotes by a backslash
character. For instance, consider the following command line that
works fine on GNU/Linux::

  $ curl -v -X PUT http://localhost:8042/modalities/sample \
         -d '{"AET" : "ORTHANCC", "Host": "127.0.0.1", "Port": 2002}'

This call will **not** work on the Microsoft Windows prompt as it
contains single-quotes. You should adapt this command line as follows
to run it on Windows::

  $ curl -v -X PUT http://localhost:8042/modalities/sample \
         -d "{\"AET\" : \"ORTHANCC\", \"Host\": \"127.0.0.1\", \"Port\": 2002}"

As an alternative, consider using a different Windows shell, for
instance `Windows PowerShell
<https://fr.wikipedia.org/wiki/Windows_PowerShell>`__ (some examples
of PowerShell can be found below on this page).


.. _sending-dicom-images:

Sending DICOM images
--------------------

.. highlight:: bash

The upload of DICOM files is possible by querying the REST API using
the following syntax::

    $ curl -X POST http://localhost:8042/instances --data-binary @CT.X.1.2.276.0.7230010.dcm
    $ curl -X POST http://localhost:8042/instances --data-binary @multiple-files.zip

.. highlight:: json

Orthanc will respond with a JSON file that contain information about
the location of the stored instance, such as::

    {
      "ID" : "5d4a3991-8a265cb2-da669bea-d8c761af-4a77113a",
      "ParentPatient" : "69a957ab-57545037-ce9a492a-d0bd89c1-d7e2220d",
      "ParentSeries" : "87c81b2c-e9f92adf-2dc11d37-399b5214-37275cdb",
      "ParentStudy" : "1b1cc0c9-c0377071-78e8cd3a-2e382948-a243db42",
      "Path" : "/instances/5d4a3991-8a265cb2-da669bea-d8c761af-4a77113a",
      "Status" : "Success"
    }

.. highlight:: bash

Note that in the case of curl, setting the ``Expect`` HTTP Header will
significantly `reduce the execution time of POST requests
<https://stackoverflow.com/questions/463144/php-http-post-fails-when-curl-data-1024/463277#463277>`__::

    $ curl -X POST -H "Expect:" http://localhost:8042/instances --data-binary @CT.X.1.2.276.0.7230010.dcm

The code distribution of Orthanc contains a `sample Python script
<https://orthanc.uclouvain.be/hg/orthanc/file/Orthanc-1.12.3/OrthancServer/Resources/Samples/ImportDicomFiles/ImportDicomFiles.py>`__
that recursively upload the content of some folder into Orthanc using
the REST API::

    $ python ImportDicomFiles.py localhost 8042 ~/DICOM/

Starting with Orthanc 1.8.1, the source distribution of Orthanc
includes another Python script named ``OrthancImport.py`` that
provides more features than ``ImportDicomFiles.py``. It can notably
import the content of ``.zip``, ``.tar.gz`` or ``.tar.bz2`` archives
without having to uncompress them first. It also provides more
comprehensive command-line options. `Check this script out
<https://orthanc.uclouvain.be/hg/orthanc/file/Orthanc-1.12.3/OrthancServer/Resources/Samples/ImportDicomFiles/OrthancImport.py>`__.
    

.. highlight:: perl

If you are using Powershell (>= 3.0), you can use the following to send a single
Dicom instance to Orthanc::

    # disabling the progress bar makes the Invoke-RestMethod call MUCH faster
    $ProgressPreference = 'SilentlyContinue'

    # upload it to Orthanc
    $reply = Invoke-RestMethod http://localhost:8042/instances -Method POST -InFile CT.X.1.2.276.0.7230010.dcm

    # display the result
    Write-Host "The instance can be retrieved at http://localhost:8042$($reply.Path)"

.. _rest-access:

Accessing the content of Orthanc
--------------------------------

Orthanc structures the stored DICOM resources using the "Patient,
Study, Series, Instance" model of the DICOM standard. Each DICOM
resource is associated with an :ref:`unique identifier <orthanc-ids>`.

List all the DICOM resources
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Here is how you would list all the DICOM resources that are stored in
your local Orthanc instance::

    $ curl http://localhost:8042/patients
    $ curl http://localhost:8042/studies
    $ curl http://localhost:8042/series
    $ curl http://localhost:8042/instances

Note that the result of this command is a `JSON file
<https://en.wikipedia.org/wiki/Json>`__ that contains an array of
resource identifiers. The JSON file format is lightweight and can be
parsed from almost any computer language.

Accessing a patient
^^^^^^^^^^^^^^^^^^^

.. highlight:: bash

To access a single resource, add its identifier to the `URI
<https://en.wikipedia.org/wiki/Uniform_resource_identifier>`__. You
would for instance retrieve the main information about one patient as
follows::

    $ curl http://localhost:8042/patients/dc65762c-f476e8b9-898834f4-2f8a5014-2599bc94

.. highlight:: json

Here is a possible answer from Orthanc::

 {
   "ID" : "07a6ec1c-1be5920b-18ef5358-d24441f3-10e926ea",
   "MainDicomTags" : {
      "OtherPatientIDs" : "(null)",
      "PatientBirthDate" : "0",
      "PatientID" : "000000185",
      "PatientName" : "Anonymous^Unknown",
      "PatientSex" : "O"
   },
   "Studies" : [ "9ad2b0da-a406c43c-6e0df76d-1204b86f-78d12c15" ],
   "Type" : "Patient"
 }

This is once again a JSON file. Note how Orthanc gives you a summary
of the main DICOM tags that correspond to the patient level.


.. _browsing-hierarchy:

Browsing from the patient down to the instance
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. highlight:: bash

The field ``Studies`` list all the DICOM studies that are associated
with the patient. So, considering the patient above, we would go down
in her DICOM hierarchy as follows::

    $ curl http://localhost:8042/studies/9ad2b0da-a406c43c-6e0df76d-1204b86f-78d12c15

.. highlight:: json

And Orthanc could answer::

 {
   "ID" : "9ad2b0da-a406c43c-6e0df76d-1204b86f-78d12c15",
   "MainDicomTags" : {
      "AccessionNumber" : "(null)",
      "StudyDate" : "20120716",
      "StudyDescription" : "TestSUVce-TF",
      "StudyID" : "23848",
      "StudyInstanceUID" : "1.2.840.113704.1.111.7016.1342451220.40",
      "StudyTime" : "170728"
   },
   "ParentPatient" : "07a6ec1c-1be5920b-18ef5358-d24441f3-10e926ea",
   "Series" : [
      "6821d761-31fb55a9-031ebecb-ba7f9aae-ffe4ddc0",
      "2cc6336f-2d4ae733-537b3ca3-e98184b1-ba494b35",
      "7384c47e-6398f2a8-901846ef-da1e2e0b-6c50d598"
   ],
   "Type" : "Study"
 }

.. highlight:: bash

The main DICOM tags are now those that are related to the study
level. It is possible to retrieve the identifier of the patient in the
``ParentPatient`` field, which can be used to go upward the DICOM
hierarchy. But let us rather go down to the series level by using the
``Series`` array. The next command would return information about one
of the three series that have just been reported::

    $ curl http://localhost:8042/series/2cc6336f-2d4ae733-537b3ca3-e98184b1-ba494b35

.. highlight:: json

Here is a possible answer::

 {
   "ExpectedNumberOfInstances" : 45,
   "ID" : "2cc6336f-2d4ae733-537b3ca3-e98184b1-ba494b35",
   "Instances" : [
      "41bc3f74-360f9d10-6ae9ffa4-01ea2045-cbd457dd",
      "1d3de868-6c4f0494-709fd140-7ccc4c94-a6daa3a8",
      <...>
      "1010f80b-161b71c0-897ec01b-c85cd206-e669a3ea",
      "e668dcbf-8829a100-c0bd203b-41e404d9-c533f3d4"
   ],
   "MainDicomTags" : {
      "Manufacturer" : "Philips Medical Systems",
      "Modality" : "PT",
      "NumberOfSlices" : "45",
      "ProtocolName" : "CHU/Body_PET/CT___50",
      "SeriesDate" : "20120716",
      "SeriesDescription" : "[WB_CTAC] Body",
      "SeriesInstanceUID" : "1.3.46.670589.28.2.12.30.26407.37145.2.2516.0.1342458737",
      "SeriesNumber" : "587370",
      "SeriesTime" : "171121",
      "StationName" : "r054-svr"
   },
   "ParentStudy" : "9ad2b0da-a406c43c-6e0df76d-1204b86f-78d12c15",
   "Status" : "Complete",
   "Type" : "Series"
 }

It can be seen that this series comes from a PET modality. Orthanc has
computed that this series should contain 45 instances.

.. highlight:: bash

So far, we have navigated from the patient level, to the study level,
and finally to the series level. There only remains the instance
level. Let us dump the content of one of the instances::

    $ curl http://localhost:8042/instances/e668dcbf-8829a100-c0bd203b-41e404d9-c533f3d4

.. highlight:: json

The instance contains the following information::

 {
   "FileSize" : 70356,
   "FileUuid" : "3fd265f0-c2b6-41a2-ace8-ae332db63e06",
   "ID" : "e668dcbf-8829a100-c0bd203b-41e404d9-c533f3d4",
   "IndexInSeries" : 6,
   "MainDicomTags" : {
      "ImageIndex" : "6",
      "InstanceCreationDate" : "20120716",
      "InstanceCreationTime" : "171344",
      "InstanceNumber" : "6",
      "SOPInstanceUID" : "1.3.46.670589.28.2.15.30.26407.37145.3.2116.39.1342458737"
   },
   "ParentSeries" : "2cc6336f-2d4ae733-537b3ca3-e98184b1-ba494b35",
   "Type" : "Instance"
 }

.. highlight:: bash

The instance has the index 6 in the parent series. The instance is
stored as a raw DICOM file of 70356 bytes. You would download this
DICOM file using the following command::

    $ curl http://localhost:8042/instances/e668dcbf-8829a100-c0bd203b-41e404d9-c533f3d4/file > Instance.dcm


Accessing the DICOM fields of an instance as a JSON file
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. highlight:: bash

When one gets to the instance level, you can retrieve the hierarchy of
all the DICOM tags of this instance as a JSON file::

    $ curl http://localhost:8042/instances/e668dcbf-8829a100-c0bd203b-41e404d9-c533f3d4/simplified-tags

.. highlight:: json

Here is a excerpt of the Orthanc answer::

 {
   "ACR_NEMA_2C_VariablePixelDataGroupLength" : "57130",
   "AccessionNumber" : null,
   "AcquisitionDate" : "20120716",
   "AcquisitionDateTime" : "20120716171219",
   "AcquisitionTime" : "171219",
   "ActualFrameDuration" : "3597793",
   "AttenuationCorrectionMethod" : "CTAC-SG",
   <...>
   "PatientID" : "000000185",
   "PatientName" : "Anonymous^Unknown",
   "PatientOrientationCodeSequence" : [
      {
         "CodeMeaning" : "recumbent",
         "CodeValue" : "F-10450",
         "CodingSchemeDesignator" : "99SDM",
         "PatientOrientationModifierCodeSequence" : [
            {
               "CodeMeaning" : "supine",
               "CodeValue" : "F-10340",
               "CodingSchemeDesignator" : "99SDM"
            }
         ]
      }
   ],
   <...>
   "StudyDescription" : "TestSUVce-TF",
   "StudyID" : "23848",
   "StudyInstanceUID" : "1.2.840.113704.1.111.7016.1342451220.40",
   "StudyTime" : "171117",
   "TypeOfDetectorMotion" : "NONE",
   "Units" : "BQML",
   "Unknown" : null,
   "WindowCenter" : "1.496995e+04",
   "WindowWidth" : "2.993990e+04"
 }

.. highlight:: bash

If you need more detailed information about the type of the variables
or if you wish to use the hexadecimal indexes of DICOM tags, you are
free to use the following URL::

    $ curl http://localhost:8042/instances/e668dcbf-8829a100-c0bd203b-41e404d9-c533f3d4/tags

Accessing the raw DICOM fields of an instance
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. highlight:: bash

You also have the opportunity to access the raw value of the DICOM
tags of an instance, without going through a JSON file. Here is how
you would find the Patient Name of the instance::

    $ curl http://localhost:8042/instances/e668dcbf-8829a100-c0bd203b-41e404d9-c533f3d4/content/0010-0010
    Anonymous^Unknown

The list of all the available tags for this instance can also be retrieved easily::

    $ curl http://localhost:8042/instances/e668dcbf-8829a100-c0bd203b-41e404d9-c533f3d4/content

It is also possible to recursively explore the sequences of tags::

    $ curl http://localhost:8042/instances/e668dcbf-8829a100-c0bd203b-41e404d9-c533f3d4/content/0008-1250/0/0040-a170/0/0008-0104
    For Attenuation Correction

The command above has opened the "0008-1250" tag that is a DICOM
sequence, taken its first child, opened its "0040-a170" tag that is
also a sequence, taken the first child of this child, and returned the
"0008-0104" DICOM tag.

Downloading images
^^^^^^^^^^^^^^^^^^

.. highlight:: bash

As :ref:`explained above <browsing-hierarchy>`, the raw DICOM file
corresponding to a single instance can be retrieved as follows::

  $ curl http://localhost:8042/instances/609665c0-c5198aa2-8632476b-a00e0de0-e9075d94/file > Instance.dcm

It is also possible to download a preview PNG image that corresponds
to some DICOM instance::

  $ curl http://localhost:8042/instances/609665c0-c5198aa2-8632476b-a00e0de0-e9075d94/preview > Preview.png

The resulting image will be a standard graylevel PNG image (with 8
bits per pixel) that can be opened by any painting software. The
dynamic range of the pixel data is stretched to the [0..255] range.
An equivalent JPEG image can be downloaded by setting the `HTTP header
<https://en.wikipedia.org/wiki/List_of_HTTP_header_fields>`__
``Accept`` to ``image/jpeg``.  By default, the jpeg quality is set to 
90% but this can be specified in the url::

  $ curl -H 'Accept: image/jpeg' http://localhost:8042/instances/609665c0-c5198aa2-8632476b-a00e0de0-e9075d94/preview > Preview.jpg
  $ curl -H 'Accept: image/jpeg' http://localhost:8042/instances/609665c0-c5198aa2-8632476b-a00e0de0-e9075d94/preview?quality=80 > Preview80.jpg

If you don't want to stretch the dynamic range, and create a 8bpp or
16bpp PNG image, you can use the following URIs::

  $ curl http://localhost:8042/instances/609665c0-c5198aa2-8632476b-a00e0de0-e9075d94/image-uint8 > full-8.png
  $ curl http://localhost:8042/instances/609665c0-c5198aa2-8632476b-a00e0de0-e9075d94/image-uint16 > full-16.png

In these images, the values are cropped to the maximal value that can
be encoded by the target image format. The
``/instances/{...}/image-int16`` is available as well to download
signed DICOM pixel data.

Since Orthanc 1.4.2, it is also possible to download such images in
the generic `PAM format
<https://en.wikipedia.org/wiki/Netpbm#PAM_graphics_format>`__::

  $ curl -H 'Accept: image/x-portable-arbitrarymap' http://localhost:8042/instances/609665c0-c5198aa2-8632476b-a00e0de0-e9075d94/image-uint16 > full-16.pam

Users of Matlab or Octave can find related information :ref:`in the
dedicated section <matlab>`.


.. _download_numpy:

Downloading decoded images from Python
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. highlight:: python

Starting with Orthanc 1.11.0, it is possible to immediately download
DICOM instances and DICOM series as numpy arrays (even if they use a
compressed transfer syntax). This is especially useful for the
integration within AI (artificial intelligence) pipelines. Here is a
sample call::

  import io
  import numpy
  import requests
  
  r = requests.get('https://orthanc.uclouvain.be/demo/instances/6582b1c0-292ad5ab-ba0f088f-f7a1766f-9a29a54f/numpy')
  r.raise_for_status()
  
  image = numpy.load(io.BytesIO(r.content))
  print(image.shape)  # (1, 358, 512, 1)

The downloaded numpy array for one single DICOM instance contains
floating-point values, and has a shape of ``(1, height, width, 1)`` if
the corresponding instance is grayscale, or ``(1, height, width, 3)``
if the instance has colors (e.g. in ultrasound images). If applicable,
the ``Rescale Slope (0028,1053)`` and ``Rescale Intercept
(0028,1052)`` DICOM tags are applied to the floating-point values.

Similarly, this feature is available at the series level::

  import io
  import numpy
  import requests
  
  r = requests.get('https://orthanc.uclouvain.be/demo/series/dc0216d2-a406a5ad-31ef7a78-113ae9d9-29939f9e/numpy')
  r.raise_for_status()
  
  image = numpy.load(io.BytesIO(r.content))
  print(image.shape)  # (100, 256, 256, 1)

As can be seen, in the case of a DICOM series, the first dimension of
the resulting numpy array corresponds to the depth of the series
(i.e. to its number of 2D slices).

Some options are available for these ``/instances/.../numpy`` and
``/series/.../numpy`` routes:

* ``?compress=1`` will return a ``.npz`` compressed numpy archive
  instead of a plain ``.npy`` numpy array. This can be used to reduce
  the network bandwidth. In such a case, the array of interest is
  named ``arr_0`` in the ``.npz`` archive, e.g.::

    print(image['arr_0'].shape)

* ``?rescale=0`` will skip the conversion to floating-point values,
  and will not apply the rescale slope/intercept. This can be useful
  to reduce the network bandwidth or to receive the original integer
  values of the voxels.


Downloading studies
^^^^^^^^^^^^^^^^^^^

.. highlight:: bash

All instances of a study can be retrieved as a zip file as follows::

  $ curl http://localhost:8042/studies/6b9e19d9-62094390-5f9ddb01-4a191ae7-9766b715/archive > Study.zip

It is also possible to download a zipped DICOMDIR through::

  $ curl http://localhost:8042/studies/6b9e19d9-62094390-5f9ddb01-4a191ae7-9766b715/media > Study.zip


.. _download-pdf-videos:

Downloading PDF or videos
^^^^^^^^^^^^^^^^^^^^^^^^^

.. highlight:: bash

Given a DICOM instance that embeds a PDF file (typically, one instance
whose SOP Class UID is ``1.2.840.10008.5.1.4.1.1.104.1`` -
Encapsulated PDF Storage), the PDF content can be downloaded as
follows::

  $ curl http://localhost:8042/instances/1915e0cc-c2c1a0fc-12cdd7f5-3ba32114-a97c2c9b/content/0042,0011 > sample.pdf

This corresponds to downloading the raw DICOM tag "Encapsulated
Document" (0042,0011). Beware that the last byte of the downloaded
file might correspond to one padding byte, if the source PDF had an
odd number of bytes.

Similarly, if you know that a DICOM instance :ref:`embeds a video
<videos>` (which can be tested by checking the :ref:`value of the
metadata <metadata-core>` corresponding to its transfer syntax UID),
the raw video can be downloaded as follows::

  $ curl http://localhost:8042/instances/e465dd27-83c96343-96848735-7035a133-1facf1a0/frames/0/raw > sample.mp4


.. _peering:

Sending resources to remote Orthanc over HTTP/HTTPS (through Orthanc peering)
-----------------------------------------------------------------------------

Orthanc can send its DICOM instances to remote Orthanc servers over
HTTP/HTTPS. Such servers are referred to as :ref:`Orthanc peers
<peers>`. This process can be triggered by the REST API, which is
described in this section.

Configuration
^^^^^^^^^^^^^

.. highlight:: json

You first have to declare the Url of the remote orthanc inside the
:ref:`configuration file <configuration>`. For instance, here is how
to declare a remote orthanc peer::

    ...
    "OrthancPeers" : {
      "sample" : [ "http://localhost:8043" ], // short version
      "sample2" : {                           // long version
        "Url" : "http://localhost:8044",
        "Username" : "alice",                          // optional
        "Password" : "alicePassword",                  // optional
        "HttpHeaders" : { "Token" : "Hello world" },   // optional
        "CertificateFile" : "client.crt",              // optional (only if using client certificate authentication)
        "CertificateKeyFile" : "client.key",           // optional (only if using client certificate authentication)
        "CertificateKeyPassword" : "certpass"          // optional (only if using client certificate authentication)
    },
    ...

.. highlight:: bash

Such a configuration would enable Orthanc to connect to two other
Orthanc instances that listens on the localhost on the ports 8043
and 8044. The peers that are known to Orthanc can be queried::

    $ curl http://localhost:8042/peers?expand

Instead of using the configuration file, peers can be created or
updated through the REST API using the ``PUT`` method of HTTP::

    $ curl -v -X PUT http://localhost:8042/peers/sample -d '{"Url" : "http://127.0.0.1:8043"}'

One peer can also be removed using the ``DELETE`` method as follows::
    
    $ curl -v -X DELETE http://localhost:8042/peers/sample

Note that, by default, peers are read from the Orthanc configuration
files and are updated in Orthanc memory only. If you want your
modifications to be persistent, you should configure Orthanc to store
its peers in the database.  This is done through this configuration::

    ...
    "OrthancPeersInDatabase" : true,
    ...

Sending One Resource
^^^^^^^^^^^^^^^^^^^^

.. highlight:: bash

Once you have identified the Orthanc identifier of the DICOM resource
that would like to send :ref:`as explained above <rest-access>`, you
would use the following command to send it::

    $ curl -X POST http://localhost:8042/peers/sample/store -d c4ec7f68-9b162055-2c8c5888-5bf5752f-155ab19f

The ``/sample/`` component of the URI corresponds to the identifier of
the remote modality, as specified above in the configuration file.

Note that you can send isolated DICOM instances with this command, but
also entire patients, studies or series. It is possible to send multiple instances with a single POST
request::

    $ curl -X POST http://localhost:8042/peers/sample/store -d '["d4b46c8e-74b16992-b0f5ca11-f04a60fa-8eb13a88","d5604121-7d613ce6-c315a5-a77b3cf3-9c253b23","cb855110-5f4da420-ec9dc9cb-2af6a9bb-dcbd180e"]'
     
Note that the list of resources to be sent can include the
:ref:`Orthanc identifiers <orthanc-ids>` of entire patients,
studies or series as well.

**Important remark:** Neither the :ref:`metadata <metadata>`, nor the
:ref:`attachments <attachments>` are transferred between the Orthanc
peers. This is because metadata and attachments are considered as
local to one Orthanc server.


Testing connectivity with a remote peer
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. highlight:: bash

In version 1.5.9+, we have introduced a route to retrieve the ``/system`` info from
a remote peer.  This route can also be used to test the connectivity with that peer
without actually sending a DICOM resource.::

    $ curl http://localhost:8042/peers/sample/system


Using HTTPS
^^^^^^^^^^^

If you're transfering medical data over internet, it is mandatory to
use HTTPS.

On the server side, we recommend to put Orthanc behind an :ref:`HTTPS
server that will take care of the TLS <https>`.

On the client side, in order for the client Orthanc to recognize the
server certificate, you'll have to provide a path to the CA
(certification authority) certificates.  This is done in the
configuration file through this configurationg::

    ...
    "HttpsCACertificates" : "/etc/ssl/certs/ca-certificates.crt,
    ...

If you want your server to accept incoming connections for known hosts only, you can either:

- configure a firewall to accept incoming connections from known IP addresses 
- configure your client Orthanc to use a client certificate to authenticate at the Server.  This is done through the ``CertificateFile``, ``CertificateKeyFile`` and ``CertificateKeyPassword`` entries in the configuration file.




Sending resources to remote modalities (through DICOM C-Store)
--------------------------------------------------------------

Orthanc can send its DICOM instances to remote DICOM modalities (C-Store SCU). This process
can be triggered by the REST API.

Configuration
^^^^^^^^^^^^^

.. highlight:: json

You first have to declare the AET, the IP address and the port number
of the remote modality inside the :ref:`configuration file
<configuration>`. For instance, here is how to declare a remote
modality::

    ...
    "DicomModalities" : {
      "sample" : [ "ORTHANCA", "127.0.0.1", 2000 ], // short version
      "sample2" : {                                 // long version
        "AET" : "ORTHANCB",
        "Port" : 2001,
        "Host" : "127.0.0.1",
        "Manufacturer" : "Generic",
        "AllowEcho" : true,
        "AllowFind" : true,
        "AllowMove" : true,
        "AllowStore" : true
      }
    },
    ...

.. highlight:: bash

Such a configuration would enable Orthanc to connect to two DICOM
stores (for instance, other Orthanc instances) that listens on the
localhost on the port 2000 & 2001. The modalities that are known to Orthanc
can be queried::

    $ curl http://localhost:8042/modalities?expand

Instead of using the configuration file, modalities can be created or
updated through the REST API using the ``PUT`` method of HTTP::

    $ curl -v -X PUT http://localhost:8042/modalities/sample -d '{"AET" : "ORTHANCC", "Host": "127.0.0.1", "Port": 2002}'

One modality can also be removed using the ``DELETE`` method as follows::
    
    $ curl -v -X DELETE http://localhost:8042/modalities/sample

Note that, by default, modalities are read from the Orthanc
configuration files and are updated in Orthanc memory only. If you
want your modifications to be persistent, you should configure Orthanc
to store the modalities in the database.  This is done through this
configuration::

    ...
    "DicomModalitiesInDatabase" : true,
    ...


.. _rest-store-scu:
    
Sending One Resource
^^^^^^^^^^^^^^^^^^^^

.. highlight:: bash

Once you have identified the Orthanc identifier of the DICOM resource
that would like to send :ref:`as explained above <rest-access>`, you
would use the following command to send it::

    $ curl -X POST http://localhost:8042/modalities/sample/store -d c4ec7f68-9b162055-2c8c5888-5bf5752f-155ab19f

The ``/sample/`` component of the URI corresponds to the identifier of
the remote modality, as specified above in the configuration file.

Note that you can send isolated DICOM instances with this command, but
also entire patients, studies or series.

Various optional fields are also available.  i.e, if you need to 
monitor the state of a transfer, you can start the transfer in :ref:`asynchronous mode
<jobs>`, which will provide you with the identifier of the Orthanc job::

    $ curl -X POST http://localhost:8042/modalities/sample/store \
      --data '{
                "Resources" : ["d4b46c8e-74b16992-b0f5ca11-f04a60fa-8eb13a88"],
                "Synchronous" : false,
                "LocalAet" : "ORTHANC",
                "MoveOriginatorAet": "ORTHANC",
                "MoveOriginatorID": 1234,
                "Timeout": 10,
                "StorageCommitment": false
              }'


Bulk Store SCU
^^^^^^^^^^^^^^

.. highlight:: bash

Each time a POST request is made to ``/modalities/.../store``, a new
DICOM association is possibly established. This may lead to a large
communication overhead if sending multiple isolated instances by
making one REST call for each of these instances.

To circumvent this problem, you have 2 possibilities:

1. Set the ``DicomAssociationCloseDelay`` option in the
   :ref:`configuration file <configuration>` to a non-zero value. This
   will keep the DICOM connection open for a certain amount of time,
   waiting for new instances to be routed. This is useful if 
   autorouting images :ref:`using Lua <lua-auto-routing>`.

2. It is possible to send multiple instances with a single POST
   request (so-called "Bulk Store SCU", available from Orthanc
   0.5.2)::

    $ curl -X POST http://localhost:8042/modalities/sample/store -d '["d4b46c8e-74b16992-b0f5ca11-f04a60fa-8eb13a88","d5604121-7d613ce6-c315a5-a77b3cf3-9c253b23","cb855110-5f4da420-ec9dc9cb-2af6a9bb-dcbd180e"]'

   The list of the resources to be sent are given as a JSON array. In
   this case, a single DICOM connection is used. `Sample code is
   available
   <https://orthanc.uclouvain.be/hg/orthanc/file/default/OrthancServer/Resources/Samples/Python/HighPerformanceAutoRouting.py>`__.

   Note that the list of resources to be sent can include the
   :ref:`Orthanc identifiers <orthanc-ids>` of entire patients,
   studies or series as well.


Performing C-Echo
-----------------

To validate the DICOM connectivity between Orthanc and a remote modality,
you can perform a C-ECHO::

    $ curl -X POST http://localhost:8042/modalities/sample/echo -d '{}'

From Orthanc 1.7.0, you can include an extra ``Timeout`` field::

    $ curl -X POST http://localhost:8042/modalities/sample/echo -d '{ "Timeout": 10 }'

If no ``Timeout`` parameter is specified, the value of the ``DicomScuTimeout``
configuration is used as a default.  If ``Timeout`` is set to zero, this means 
no timeout.

NB: A body containing a valid JSON object is needed by
``/modalities/{id}/echo`` since Orthanc 1.7.0.


Performing C-Move
-----------------

.. highlight:: bash

You can perform a DICOM C-Move to move a specific study from one modality 
to another (including Orthanc itself if you don't specify the ``TargetAet`` 
field).  

I.e. to move a study whose you know the ``StudyInstanceUID`` from
the modality ``sample`` to another Orthanc whose AET is ``ORTHANCB``::

  $ curl --request POST --url http://localhost:8042/modalities/samples/move \
    --data '{ 
              "Level" : "Study", 
              "Resources" : [ 
                { 
                  "StudyInstanceUID": "1.2.840.113543.6.6.4.7.64067529866380271256212683512383713111129" 
                } 
              ], 
              "TargetAet": "ORTHANCB",
              "Timeout": 60 
            }'


Performing Query/Retrieve (C-Find) and Find with REST
-----------------------------------------------------

*Section contributed by Bryan Dearlove*

Orthanc can be used to perform queries on the local Orthanc instance,
or on remote modalities through the REST API.

To perform a query of a remote modality you must define the modality
within the :ref:`configuration file <configuration>` (See
Configuration section under Sending resources to remote modalities).

.. _rest-find-scu:

Performing Queries on Modalities
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. highlight:: bash

To initiate a query you perform a POST command against the Modality
with the identifiers you are looking for. The the example below we are
performing a study level query against the modality sample for any
study descriptions with the word chest within it. This search is case
insensitive unless configured otherwise within the Orthanc
configuration file::

     $ curl --request POST \
       --url http://localhost:8042/modalities/sample/query \
       --data '{
                 "Level" : "Study",
                 "Query" : {
                   "PatientID" : "",
                   "StudyDescription" : "*Chest*",
                   "PatientName" : ""
                 }
               }'

You might be interested in including the ``Normalize`` option to bypass
the normalization of the outgoing C-FIND queries. For instance, for
the ``InstitutionName`` to be included at the ``Study`` level, one would
run::

  $ curl -v http://localhost:8042/modalities/sample/query -X POST -d \
    '{"Level":"Study","Query":{"InstitutionName":"a"},"Normalize":false}'

.. highlight:: json

You will receive back an ID which can be used to retrieve more
information with GET commands or C-Move requests with a POST Command::

     {
     	"ID": "5af318ac-78fb-47ff-b0b0-0df18b0588e0",
     	"Path": "/queries/5af318ac-78fb-47ff-b0b0-0df18b0588e0"
     }


Additional Options
^^^^^^^^^^^^^^^^^^

.. highlight:: json

You can use patient identifiers by including the ``*`` within your
search. For example if you were searching for a name beginning with
``Jones`` you can do::

  "PatientName":"Jones*"

If you wanted to search for a name with the words ``Jo`` anywhere
within it you can do::

  "PatientName":"*Jo*"

To perform date searches you can specify within StudyDate a starting
date and/or a before date. For example ``"StudyDate":"20180323-"``
would search for all study dates after the specified date to
now. Doing ``"StudyDate":"20180323-20180325"`` would search for all
study dates between the specified date.


Reviewing Level
^^^^^^^^^^^^^^^

.. highlight:: bash

::

   $ curl --request GET --url http://localhost:8042/queries/5af318ac-78fb-47ff-b0b0-0df18b0588e0/level

Will retrieve the level with which the query was performed, Study,
Series or Instance.


Reviewing Modality
^^^^^^^^^^^^^^^^^^

.. highlight:: bash

::

   $ curl --request GET --url http://localhost:8042/queries/5af318ac-78fb-47ff-b0b0-0df18b0588e0/modality

Will provide the modality name which the original query was performed against.


Reviewing Query
^^^^^^^^^^^^^^^

.. highlight:: bash

To retrieve information on what identifiers the query was originally
performed using you can use the query filter::

  $ curl --request GET --url http://localhost:8042/queries/5af318ac-78fb-47ff-b0b0-0df18b0588e0/query


Reviewing Query Answers
^^^^^^^^^^^^^^^^^^^^^^^

.. highlight:: bash

You are able to individually review each answer returned by performing
a GET with the answers parameter::

  $ curl --request GET --url http://localhost:8042/queries/5af318ac-78fb-47ff-b0b0-0df18b0588e0/answers

You will get a JSON back with numbered identifiers for each answer you
received back. For example because we performed a Study level query we
received back 5 studies answers back. We are able to query each answer
for content details::

  $ curl --request GET --url http://localhost:8042/queries/5af318ac-78fb-47ff-b0b0-0df18b0588e0/answers/0/content

If there are content items missing, you may add them by adding that
identifier to the original query. For example if we wanted Modalities
listed in this JSON answer in the initial query we would add to the
POST body: ``"ModalitiesInStudy":""``


Performing Retrieve (C-Move)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. highlight:: bash

You can perform a C-Move to retrieve all studies within the original
query using a post command and identifying the Modality (named in this 
example ``Orthanc``), to be one to in the POST contents::

  $ curl --request POST --url http://localhost:8042/queries/5af318ac-78fb-47ff-b0b0-0df18b0588e0/retrieve --data Orthanc

You are also able to perform individual C-Moves for a content item by
specifying that individual content item::

  $ curl --request POST --url http://localhost:8042/queries/5af318ac-78fb-47ff-b0b0-0df18b0588e0/answers/0/retrieve --data Orthanc

If C-Moves take too long (for example, performing a C-Move of a big
study), you may run the request in :ref:`asynchronous mode <jobs>`,
which will create a job in Orthanc::

  $ curl --request POST --url http://localhost:8042/queries/5af318ac-78fb-47ff-b0b0-0df18b0588e0/retrieve \
    --data '{"TargetAet":"Orthanc","Synchronous":false}'


.. highlight:: bash

The answer of this POST request is the job ID taking care of the
C-Move command, :ref:`whose status can be monitored <jobs-monitoring>`
in order to detect failure or completion::

  {
      "ID" : "11541b16-e368-41cf-a8e9-3acf4061d238",
      "Path" : "/jobs/11541b16-e368-41cf-a8e9-3acf4061d238"
  }



.. _rest-find:

Performing Finds within Orthanc
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. highlight:: bash

Performing a find within the local database of Orthanc is very similar
to using Queries against DICOM modalities and the additional options
listed above work with find also.  When performing a find, you will
receive the Orthanc ID's of all the matched items within your
find. For example if you perform a study level find and 5 Studies
match you will receive 5 study level Orthanc ID's in JSON format as a
response::

  $ curl --request POST --url http://localhost:8042/tools/find \
    --data '{
              "Level" : "Instance",
              "Query" : {
                "Modality" : "CR",
                "StudyDate" : "20180323-",
                "PatientID" : "*"
              }
            }'

Setting the ``Expand`` field to ``true`` in the POST body of the
query will automatically report details about each study::

  $ curl https://orthanc.uclouvain.be/demo/tools/find -d '{"Level":"Study","Query":{"PatientName":"KNIX"}}'
  [
    "b9c08539-26f93bde-c81ab0d7-bffaf2cb-a4d0bdd0"
  ]
  $ curl https://orthanc.uclouvain.be/demo/tools/find -d '{"Level":"Study","Query":{"PatientName":"KNIX"},"Expand":true}'
  [
    {
      "ID" : "b9c08539-26f93bde-c81ab0d7-bffaf2cb-a4d0bdd0",
      "IsStable" : true,
      "LastUpdate" : "20180414T091528",
      "MainDicomTags" : {
         "InstitutionName" : "0ECJ52puWpVIjTuhnBA0um",
         "ReferringPhysicianName" : "1",
         "StudyDate" : "20070101",
         "StudyDescription" : "Knee (R)",
         "StudyID" : "1",
         "StudyInstanceUID" : "1.2.840.113619.2.176.2025.1499492.7391.1171285944.390",
         "StudyTime" : "120000.000000"
      },
      "ParentPatient" : "6816cb19-844d5aee-85245eba-28e841e6-2414fae2",
      "PatientMainDicomTags" : {
         "PatientID" : "ozp00SjY2xG",
         "PatientName" : "KNIX"
      },
      "Series" : [
         "20b9d0c2-97d85e07-f4dbf4d2-f09e7e6a-0c19062e",
         "edbfa0a9-fa2641d7-29514b1c-45881d0b-46c374bd",
         "f2635388-f01d497a-15f7c06b-ad7dba06-c4c599fe",
         "4d04593b-953ced51-87e93f11-ae4cf03c-25defdcd",
         "5e343c3e-3633c396-03aefde8-ba0e08c7-9c8208d3",
         "8ea120d7-5057d919-837dfbcc-ccd04e0f-7f3a94aa"
      ],
      "Type" : "Study"
    }
  ]

Here is a sample REST API call to find the Orthanc identifiers of all
the DICOM series generated by an imaging modality whose "Device Serial
Number (0018,1000)" DICOM tag is equal to "123"::

  $ curl -X POST http://localhost:8042/tools/find -d '{"Level":"Series","Query":{"DeviceSerialNumber":"123"},"Expand":true}'

If you are interested by a **list of several items** (in this case, in
a list of serial numbers), just separate them with backslashes as
would do with DICOM C-FIND::

  $ curl -X POST http://localhost:8042/tools/find -d '{"Level":"Series","Query":{"DeviceSerialNumber":"123\\abc"},"Expand":true}'

 
Additional Options
^^^^^^^^^^^^^^^^^^
.. highlight:: json

You also have the ability to limit the responses by specifying a limit within the body of the POST message. For example::

  "Limit":4

.. highlight:: bash

Since Orthanc 1.11.0, you may also request a specific list of tags in the response (like in a C-FIND) even if these
tags are not stored in the MainDicomTags or if the tags needs to be computed (like ``ModalitiesInStudy``).  This ``RequestedTags`` option is
available only if you specify ``"Expand": true``::

  $ curl -X POST http://localhost:8042/tools/find -d '
    {
      "Level": "Studies",
      "Expand": true,
      "Query": {
        "StudyDate": "20220502"
      },
      "RequestedTags": ["PatientName", "PatientID", "StudyDescription", "StudyDate", "StudyInstanceUID", "ModalitiesInStudy", "NumberOfStudyRelatedSeries"]
    }'

.. highlight:: json

This query will return a response like this one::

  [
    {
      "ID" : "8a8cf898-ca27c490-d0c7058c-929d0581-2bbf104d",
      "IsStable" : true,
      "LastUpdate" : "20220428T074549",
      "MainDicomTags" : {
        "...":"..."
      },
      "..." : "...",
      "RequestedTags" : {
         "PatientName" : "Patient",
         "PatientID" : "1",
         "StudyDescription" : "Description",
         "StudyDate" : "20220502",
         "StudyInstanceUID" : "1.2.3",
         "ModalitiesInStudy" : "CT\\SEG\\SR",
         "NumberOfStudyRelatedSeries" : "3"
      },
      "Series" : [ "93034833-163e42c3-bc9a428b-194620cf-2c5799e5" ],
      "Type" : "Study"
   }
  ]


**Important:** Starting with Orthanc 1.12.0, this route in the REST
API also provide the ``Labels`` and ``LabelsConstraint`` options to
bring support for :ref:`labels <labels>`.


.. _changes:

Tracking changes
----------------

.. highlight:: bash

Whenever Orthanc receives a new DICOM instance, this event is recorded
in the so-called "Changes Log". This enables remote scripts to react
to the arrival of new DICOM resources. A typical application is
**auto-routing**, where an external script waits for a new DICOM
instance to arrive into Orthanc, then forward this instance to another
modality.

The Changes Log can be accessed by the following command::

    $ curl http://localhost:8042/changes

.. highlight:: json

Here is a typical output::

 {
   "Changes" : [
      {
         "ChangeType" : "NewInstance",
         "Date" : "20130507T143902",
         "ID" : "8e289db9-0e1437e1-3ecf395f-d8aae463-f4bb49fe",
         "Path" : "/instances/8e289db9-0e1437e1-3ecf395f-d8aae463-f4bb49fe",
         "ResourceType" : "Instance",
         "Seq" : 921
      },
      {
         "ChangeType" : "NewSeries",
         "Date" : "20130507T143902",
         "ID" : "cceb768f-e0f8df71-511b0277-07e55743-9ef8890d",
         "Path" : "/series/cceb768f-e0f8df71-511b0277-07e55743-9ef8890d",
         "ResourceType" : "Series",
         "Seq" : 922
      },
      {
         "ChangeType" : "NewStudy",
         "Date" : "20130507T143902",
         "ID" : "c4ec7f68-9b162055-2c8c5888-5bf5752f-155ab19f",
         "Path" : "/studies/c4ec7f68-9b162055-2c8c5888-5bf5752f-155ab19f",
         "ResourceType" : "Study",
         "Seq" : 923
      },
      {
         "ChangeType" : "NewPatient",
         "Date" : "20130507T143902",
         "ID" : "dc65762c-f476e8b9-898834f4-2f8a5014-2599bc94",
         "Path" : "/patients/dc65762c-f476e8b9-898834f4-2f8a5014-2599bc94",
         "ResourceType" : "Patient",
         "Seq" : 924
      }
   ],
   "Done" : true,
   "Last" : 924
 }

This output corresponds to the receiving of one single DICOM instance
by Orthanc. It records that a new instance, a new series, a new study
and a new patient has been created inside Orthanc. Note that each
changes is labeled by a ``ChangeType``, a ``Date`` (in the `ISO format
<https://en.wikipedia.org/wiki/ISO_8601>`__), the location of the
resource inside Orthanc, and a sequence number (``Seq``).

Note that this call is non-blocking. It is up to the calling program
to wait for the occurrence of a new event (by implementing a polling
loop).

.. highlight:: bash

This call only returns a fixed number of events, that can be changed
by using the ``limit`` option::

    $ curl http://localhost:8042/changes?limit=100

The flag ``Last`` records the sequence number of the lastly returned
event. The flag ``Done`` is set to ``true`` if no further event has
occurred after this lastly returned event. If ``Done`` is set to
``false``, further events are available and can be retrieved. This is
done by setting the ``since`` option that specifies from which
sequence number the changes must be returned::

    $ curl 'http://localhost:8042/changes?limit=100&since=922'

A `sample code in the source distribution
<https://orthanc.uclouvain.be/hg/orthanc/file/default/OrthancServer/Resources/Samples/Python/ChangesLoop.py>`__
shows how to use this Changes API to implement a polling loop.


Deleting resources from Orthanc
-------------------------------

.. highlight:: bash

Deleting patients, studies, series or instances
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Deleting DICOM resources (i.e. patients, studies, series or instances)
from Orthanc is as simple as using a HTTP DELETE on the URI of this
resource.

Concretely, you would first explore the resources that are stored in
Orthanc :ref:`as explained above <rest-access>`::

    $ curl http://localhost:8042/patients
    $ curl http://localhost:8042/studies
    $ curl http://localhost:8042/series
    $ curl http://localhost:8042/instances

Secondly, once you have spotted the resources to be removed, you would
use the following command-line syntax to delete them::

    $ curl -X DELETE http://localhost:8042/patients/dc65762c-f476e8b9-898834f4-2f8a5014-2599bc94
    $ curl -X DELETE http://localhost:8042/studies/c4ec7f68-9b162055-2c8c5888-5bf5752f-155ab19f
    $ curl -X DELETE http://localhost:8042/series/cceb768f-e0f8df71-511b0277-07e55743-9ef8890d
    $ curl -X DELETE http://localhost:8042/instances/8e289db9-0e1437e1-3ecf395f-d8aae463-f4bb49fe


Starting with Orthanc 1.9.4, it is also possible to ``POST`` on the
new route ``/tools/bulk-delete`` to delete at once a set of multiple
DICOM resources that are not related (i.e. that don't share any parent
DICOM resource). A typical use case is to delete a list of DICOM
instances that don't belong to the same parent patient/study/series.
The list of the :ref:`Orthanc identifiers <orthanc-ids>` of the
resources to be deleted (that may indifferently correspond to
patients, studies, series or instances) must be provided in an
argument ``Resources`` in the body of the request. Here is a sample
call::

  $ curl http://localhost:8042/tools/bulk-delete -d '{"Resources":["b6da0b16-a25ae9e7-1a80fc33-20df01a9-a6f7a1b0","d6634d97-24379e4a-1e68d3af-e6d0451f-e7bcd3d1"]}'

    
Clearing log of changes
^^^^^^^^^^^^^^^^^^^^^^^

:ref:`As described above <changes>`, Orthanc keeps track of all the
changes that occur in the DICOM store. This so-called "Changes Log"
is accessible at the following URI::

    $ curl http://localhost:8042/changes

To clear the content of the Changes Log, simply DELETE this URI::

    $ curl -X DELETE http://localhost:8042/changes


Log of exported resources
^^^^^^^^^^^^^^^^^^^^^^^^^

For medical traceability, Orthanc can be configured to store a log of
all the resources that have been exported to remote modalities::

    $ curl http://localhost:8042/exports

In auto-routing scenarios, it is important to prevent this log to grow
indefinitely as incoming instances are routed. You can either disable
this logging by setting the option ``LogExportedResources`` to ``false``
in the :ref:`configuration file <configuration>`, or periodically
clear this log by DELETE-ing this URI::

    $ curl -X DELETE http://localhost:8042/exports

NB: Starting with Orthanc 1.4.0, the ``LogExportedResources`` is set
to ``false`` by default. If the logging is desired, set this option to
``true``.
    

Anonymization and modification
------------------------------

The process of anonymizing and modifying DICOM resources is
:ref:`documented in a separate page <anonymization>`.


Further reading
---------------

The examples above have shown you the basic principles for driving an
instance of Orthanc through its REST API. All the possibilities of the
API have not been described:

* Advanced features of the REST API can be found on :ref:`another page
  <rest-advanced>`.
* A :ref:`FAQ entry <rest-samples>` lists where you can find more
  advanced samples of the REST API of Orthanc.
* A :ref:`short reference of the REST API of Orthanc <cheatsheet>` is
  part of the Orthanc Book.
* The full documentation of the REST API in the OpenAPI/Swagger format
  is `available online <https://orthanc.uclouvain.be/api/>`__. This
  reference is automatically generated from the source code of
  Orthanc.