DICOM Router - API Reference

API Reference

Overview

The DICOM Proxy provides comprehensive REST APIs that follow DICOMweb standards along with proprietary proxy APIs for advanced functionality. All APIs support JSON responses and standard HTTP status codes.

Base URL: http://localhost:8080 (or configured HTTP port) Base URL (SSL): https://localhost:8443 (or configured HTTPS port)

OpenAPI Documentation

Interactive API documentation is available at:

  • OpenAPI Spec: GET /openapi.json
  • Swagger UI: Available through third-party tools using the OpenAPI spec

Authentication

Basic Authentication (Optional)

When authentication is enabled, include credentials in the Authorization header:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

API Keys (Optional)

For programmatic access, use API key in header:

X-API-Key: your-api-key-here

DICOMweb APIs

QIDO-RS (Query based on ID for DICOM Objects)

Query for DICOM objects using standard QIDO-RS endpoints.

Search for Studies

GET /wado/studies

Query Parameters:

  • StudyDate - Study date range (format: YYYYMMDD or YYYYMMDD-YYYYMMDD)
  • StudyTime - Study time range (format: HHMMSS or HHMMSS-HHMMSS)
  • AccessionNumber - Accession number
  • PatientID - Patient identifier
  • PatientName - Patient name (supports wildcards)
  • StudyInstanceUID - Study instance UID
  • StudyID - Study ID
  • ModalitiesInStudy - Modalities (comma-separated)
  • InstitutionName - Institution name
  • ReferringPhysicianName - Referring physician
  • limit - Maximum number of results (default: 100)
  • offset - Result offset for pagination

Example Request:

curl "http://localhost:8080/wado/studies?PatientName=DOE*&StudyDate=20240101-20241231&limit=50"

Example Response:

[
  {
    "00080020": {"Value": ["20240315"], "vr": "DA"},
    "00080030": {"Value": ["143000.000"], "vr": "TM"},
    "00080050": {"Value": ["ACC001"], "vr": "SH"},
    "00080061": {"Value": ["CT"], "vr": "CS"},
    "00080090": {"Value": ["Dr. Smith"], "vr": "PN"},
    "0020000D": {"Value": ["1.2.3.4.5.6.7.8.9"], "vr": "UI"},
    "00100010": {"Value": [{"Alphabetic": "Doe^John"}], "vr": "PN"},
    "00100020": {"Value": ["123456"], "vr": "LO"},
    "00200010": {"Value": ["ST001"], "vr": "SH"}
  }
]

Search for Series

GET /wado/studies/{studyInstanceUID}/series

Path Parameters:

  • studyInstanceUID - Study instance UID

Query Parameters:

  • Modality - Series modality
  • SeriesNumber - Series number
  • SeriesInstanceUID - Series instance UID
  • BodyPartExamined - Body part examined
  • SeriesDescription - Series description
  • limit - Maximum number of results
  • offset - Result offset

Example Request:

curl "http://localhost:8080/wado/studies/1.2.3.4.5.6.7.8.9/series?Modality=CT"

Search for Instances

GET /wado/studies/{studyInstanceUID}/series/{seriesInstanceUID}/instances

Path Parameters:

  • studyInstanceUID - Study instance UID
  • seriesInstanceUID - Series instance UID

Query Parameters:

  • SOPInstanceUID - SOP instance UID
  • InstanceNumber - Instance number
  • limit - Maximum number of results
  • offset - Result offset

WADO-RS (Web Access to DICOM Objects)

Retrieve DICOM objects and metadata.

Retrieve Study

GET /wado/studies/{studyInstanceUID}

Accept Headers:

  • application/dicom - DICOM Part 10 format
  • multipart/related; type="application/dicom" - Multipart DICOM
  • application/json - JSON metadata

Retrieve Series

GET /wado/studies/{studyInstanceUID}/series/{seriesInstanceUID}

Retrieve Instance

GET /wado/studies/{studyInstanceUID}/series/{seriesInstanceUID}/instances/{sopInstanceUID}

Retrieve Metadata

GET /wado/studies/{studyInstanceUID}/metadata
GET /wado/studies/{studyInstanceUID}/series/{seriesInstanceUID}/metadata
GET /wado/studies/{studyInstanceUID}/series/{seriesInstanceUID}/instances/{sopInstanceUID}/metadata

Example Response:

[
  {
    "00080018": {"Value": ["1.2.3.4.5.6.7.8.9.10"], "vr": "UI"},
    "00080016": {"Value": ["1.2.840.10008.5.1.4.1.1.2"], "vr": "UI"},
    "00200013": {"Value": ["1"], "vr": "IS"},
    "00280010": {"Value": [512], "vr": "US"},
    "00280011": {"Value": [512], "vr": "US"},
    "00280030": {"Value": [0.5, 0.5], "vr": "DS"}
  }
]

Retrieve Rendered Images

GET /wado/studies/{studyInstanceUID}/series/{seriesInstanceUID}/instances/{sopInstanceUID}/rendered

Query Parameters:

  • viewport - Image dimensions (format: width,height)
  • window - Window center and width (format: center,width)
  • quality - JPEG quality (1-100)

Accept Headers:

  • image/jpeg - JPEG format
  • image/png - PNG format
  • image/gif - GIF format

STOW-RS (Store Over the Web)

Store DICOM objects via HTTP.

Store Study

POST /wado/studies
Content-Type: multipart/related; type="application/dicom"

Store to Specific Study

POST /wado/studies/{studyInstanceUID}
Content-Type: multipart/related; type="application/dicom"

Example Request:

curl -X POST \
  -H "Content-Type: multipart/related; type=\"application/dicom\"" \
  --data-binary @study.dcm \
  http://localhost:8080/wado/studies

Proxy APIs

Proxy DICOM Operations

Proxy C-ECHO

Test connectivity to a configured PACS server.

POST /proxy/echo/{serverid}

Path Parameters:

  • serverid - Server ID from configuration

Example Request:

curl -X POST http://localhost:8080/proxy/echo/pacs1

Example Response:

{
  "success": true,
  "server_id": "pacs1",
  "response_time_ms": 45,
  "status": "Success"
}

Proxy C-STORE

Store DICOM objects to a specific PACS server.

POST /proxy/cstore/{serverid}
Content-Type: application/dicom

Path Parameters:

  • serverid - Server ID from configuration

Example Request:

curl -X POST \
  -H "Content-Type: application/dicom" \
  --data-binary @image.dcm \
  http://localhost:8080/proxy/cstore/pacs1

Proxy QIDO-RS

Query a specific PACS server using QIDO-RS format.

GET /proxy/wado/{serverid}/rs/studies
GET /proxy/wado/{serverid}/rs/studies/{studyInstanceUID}/series
GET /proxy/wado/{serverid}/rs/studies/{studyInstanceUID}/series/{seriesInstanceUID}/instances

Path Parameters:

  • serverid - Server ID from configuration

Query Parameters: Same as standard QIDO-RS parameters

Proxy WADO-RS

Retrieve objects from a specific PACS server.

GET /proxy/wado/{serverid}/rs/studies/{studyInstanceUID}
GET /proxy/wado/{serverid}/rs/studies/{studyInstanceUID}/series/{seriesInstanceUID}
GET /proxy/wado/{serverid}/rs/studies/{studyInstanceUID}/series/{seriesInstanceUID}/instances/{sopInstanceUID}

Administrative APIs

System Status

GET /api/status

Example Response:

{
  "service_name": "DICOM Proxy",
  "version": "1.09.1",
  "uptime_seconds": 3600,
  "dicom_port": 11112,
  "http_port": 8080,
  "https_enabled": false,
  "storage_path": "C:\\DicomStorage",
  "studies_count": 1542,
  "series_count": 8967,
  "instances_count": 234567,
  "storage_used_gb": 156.7,
  "storage_available_gb": 843.3,
  "license_status": "Valid",
  "license_expires": "2025-12-31"
}

Connection Status

GET /api/connections

Example Response:

{
  "active_dicom_connections": 5,
  "total_dicom_connections": 1234,
  "active_http_connections": 12,
  "configured_servers": [
    {
      "id": "pacs1",
      "name": "Main PACS Server",
      "status": "Connected",
      "last_echo": "2024-03-15T14:30:00Z",
      "response_time_ms": 23
    }
  ]
}

Configuration

GET /api/config
PUT /api/config

Example Response (GET):

{
  "dicom_port": 11112,
  "http_port": 8080,
  "https_port": 8443,
  "max_connections": 50,
  "storage_quota_gb": 1000,
  "cleanup_enabled": true,
  "this_modality": {
    "ae_title": "DICOMPROXY",
    "port": 11112,
    "ip_address": "0.0.0.0"
  }
}

Server Management

GET /api/servers
POST /api/servers
PUT /api/servers/{serverid}
DELETE /api/servers/{serverid}

Example Server Object:

{
  "id": "pacs1",
  "name": "Main PACS Server",
  "ae_title": "MAINPACS",
  "hostname": "192.168.1.100",
  "port": 11112,
  "enabled": true,
  "max_connections": 10,
  "timeout_seconds": 30,
  "priority": 1,
  "supported_services": ["C-STORE", "C-FIND", "C-GET", "C-MOVE", "C-ECHO"]
}

Database Operations

GET /api/database/studies
GET /api/database/series/{studyInstanceUID}
GET /api/database/instances/{studyInstanceUID}/{seriesInstanceUID}
DELETE /api/database/studies/{studyInstanceUID}
POST /api/database/cleanup
POST /api/database/reindex

Monitoring & Metrics

GET /api/metrics

Example Response:

{
  "timestamp": "2024-03-15T14:30:00Z",
  "performance": {
    "cpu_usage_percent": 12.5,
    "memory_usage_mb": 512,
    "disk_io_read_mbps": 45.2,
    "disk_io_write_mbps": 23.1,
    "network_in_mbps": 15.7,
    "network_out_mbps": 22.3
  },
  "dicom_stats": {
    "c_store_requests_per_minute": 45,
    "c_find_requests_per_minute": 12,
    "c_get_requests_per_minute": 8,
    "c_move_requests_per_minute": 3,
    "c_echo_requests_per_minute": 20,
    "average_response_time_ms": 150
  },
  "http_stats": {
    "requests_per_minute": 67,
    "average_response_time_ms": 89,
    "error_rate_percent": 0.5
  }
}

Upload APIs

TUS Resumable Upload

Support for TUS protocol for large file uploads.

POST /files/
PATCH /files/{upload-id}
HEAD /files/{upload-id}

Headers:

  • Tus-Resumable: 1.0.0
  • Upload-Length: <file-size>
  • Upload-Metadata: filename <base64-encoded-filename>

Error Handling

HTTP Status Codes

Code Description Usage
200 OK Successful request
201 Created Resource created successfully
204 No Content Successful request with no content
400 Bad Request Invalid request parameters
401 Unauthorized Authentication required
403 Forbidden Insufficient permissions
404 Not Found Resource not found
409 Conflict Resource conflict (duplicate)
422 Unprocessable Entity Invalid DICOM data
500 Internal Server Error Server error
503 Service Unavailable Service temporarily unavailable

Error Response Format

{
  "error": {
    "code": "INVALID_DICOM_DATA",
    "message": "The DICOM file contains invalid data",
    "details": "Missing required tag: PatientID (0010,0020)",
    "timestamp": "2024-03-15T14:30:00Z",
    "request_id": "req-123456"
  }
}

Common Error Codes

Code Description
INVALID_PARAMETERS Request parameters are invalid
INVALID_DICOM_DATA DICOM data is invalid or corrupted
STORAGE_FULL Storage quota exceeded
SERVER_UNREACHABLE Configured PACS server unreachable
LICENSE_EXPIRED Software license has expired
AUTHENTICATION_FAILED Authentication credentials invalid
RATE_LIMIT_EXCEEDED Too many requests

Rate Limiting

The API implements rate limiting to prevent abuse:

  • Default Limit: 1000 requests per hour per IP
  • Authenticated Users: 5000 requests per hour
  • Headers:
    • X-RateLimit-Limit: Request limit
    • X-RateLimit-Remaining: Remaining requests
    • X-RateLimit-Reset: Reset time (Unix timestamp)

Pagination

For endpoints that return multiple results, pagination is supported:

Request Parameters:

  • limit - Number of results per page (default: 100, max: 1000)
  • offset - Starting position (default: 0)

Response Headers:

  • X-Total-Count: Total number of results
  • Link: Pagination links (next, prev, first, last)

Example Link Header:

Link: </wado/studies?limit=100&offset=0>; rel="first",
      </wado/studies?limit=100&offset=100>; rel="next",
      </wado/studies?limit=100&offset=900>; rel="last"

Content Types

Supported Content Types

Request Content Types:

  • application/dicom - DICOM Part 10 files
  • multipart/related; type="application/dicom" - Multipart DICOM
  • application/json - JSON data
  • application/x-www-form-urlencoded - Form data

Response Content Types:

  • application/json - JSON responses
  • application/dicom - DICOM files
  • multipart/related; type="application/dicom" - Multipart DICOM
  • image/jpeg - JPEG images
  • image/png - PNG images
  • text/plain - Plain text responses

Transfer Syntaxes

Supported DICOM transfer syntaxes:

  • Implicit VR Little Endian
  • Explicit VR Little Endian
  • Explicit VR Big Endian
  • JPEG Baseline (Process 1)
  • JPEG Extended (Processes 2 & 4)
  • JPEG Lossless, Nonhierarchical (Processes 14)
  • JPEG Lossless, Nonhierarchical, First-Order Prediction
  • JPEG-LS Lossless Image Compression
  • JPEG-LS Lossy (Near-lossless) Image Compression
  • JPEG 2000 Image Compression (Lossless Only)
  • JPEG 2000 Image Compression
  • RLE Lossless

SDK Integration Examples

JavaScript/Node.js

const axios = require('axios');

class DicomProxyClient {
  constructor(baseUrl = 'http://localhost:8080') {
    this.baseUrl = baseUrl;
  }

  async searchStudies(params = {}) {
    const response = await axios.get(`${this.baseUrl}/wado/studies`, { params });
    return response.data;
  }

  async getStudy(studyInstanceUID) {
    const response = await axios.get(
      `${this.baseUrl}/wado/studies/${studyInstanceUID}`,
      { headers: { 'Accept': 'application/json' } }
    );
    return response.data;
  }

  async storeStudy(dicomBuffer) {
    const response = await axios.post(
      `${this.baseUrl}/wado/studies`,
      dicomBuffer,
      { headers: { 'Content-Type': 'application/dicom' } }
    );
    return response.data;
  }
}

Python

import requests
import json

class DicomProxyClient:
    def __init__(self, base_url='http://localhost:8080'):
        self.base_url = base_url
        
    def search_studies(self, **params):
        response = requests.get(f'{self.base_url}/wado/studies', params=params)
        return response.json()
        
    def get_study(self, study_instance_uid):
        headers = {'Accept': 'application/json'}
        response = requests.get(
            f'{self.base_url}/wado/studies/{study_instance_uid}',
            headers=headers
        )
        return response.json()
        
    def store_study(self, dicom_bytes):
        headers = {'Content-Type': 'application/dicom'}
        response = requests.post(
            f'{self.base_url}/wado/studies',
            data=dicom_bytes,
            headers=headers
        )
        return response.json()

C#

using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Text.Json;

public class DicomProxyClient
{
    private readonly HttpClient _httpClient;
    private readonly string _baseUrl;

    public DicomProxyClient(string baseUrl = "http://localhost:8080")
    {
        _baseUrl = baseUrl;
        _httpClient = new HttpClient();
    }

    public async Task<JsonDocument> SearchStudiesAsync(Dictionary<string, string> parameters = null)
    {
        var queryString = parameters != null 
            ? string.Join("&", parameters.Select(p => $"{p.Key}={p.Value}"))
            : "";
        
        var url = $"{_baseUrl}/wado/studies?{queryString}";
        var response = await _httpClient.GetStringAsync(url);
        return JsonDocument.Parse(response);
    }

    public async Task<JsonDocument> GetStudyAsync(string studyInstanceUID)
    {
        _httpClient.DefaultRequestHeaders.Accept.Clear();
        _httpClient.DefaultRequestHeaders.Accept.Add(
            new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")
        );
        
        var response = await _httpClient.GetStringAsync($"{_baseUrl}/wado/studies/{studyInstanceUID}");
        return JsonDocument.Parse(response);
    }
}

For more examples and tutorials, see the Examples & Tutorials documentation.