DICOM Conformance Statement for Kastoria Health DICOMweb Service
Introduction
This document describes the DICOM conformance statement for the Kastoria Health DICOMweb Service. A DICOM Conformance Statement is a technical document that describes how a device or software implements the DICOM standard.
The Kastoria Health DICOMweb Service supports a subset of the DICOMweb Standard for medical imaging data management. Support includes:
- Studies Service
- Store (STOW-RS)
- Retrieve (WADO-RS)
- Search (QIDO-RS)
The service exposes a REST API following the DICOMweb standard (DICOM PS3.18).
Service Base URL
The service base URL follows the pattern:
https://{host}/
A GET /health endpoint is provided for liveness checks, and GET / returns basic server
information.
Authorization
The Retrieve (WADO-RS) and Search (QIDO-RS) transactions support study-scoped access with viewer JSON Web Tokens (JWTs). Authorization is off by default and is enabled per deployment. When it is enabled:
- Every WADO-RS and QIDO-RS request must carry
Authorization: Bearer <jwt>. A missing, malformed, invalid or expired token is refused with401 (Unauthorized). - The token's
studyInstanceUIDsclaim is the authorization scope. A request whose path names a Study Instance UID outside that scope is refused with403 (Forbidden). - Study search (
GET /studies) returns only studies within the scope; a token whose scope is empty receives an empty result. - A scope containing
*grants every study.
Store (STOW-RS) requests are not subject to viewer-token authorization.
See JWT Authorization for the token format, claims and verification rules.
Studies Service
The Studies Service allows users to store, retrieve, and search for DICOM Studies, Series, and Instances.
Store (STOW-RS)
This transaction uses the POST method to store representations of studies, series, and instances contained in the request payload.
| Method | Path | Description |
|---|---|---|
| POST | /studies | Store instances |
| POST | /studies/{study} | Store instances for a specific study |
Parameter study corresponds to the DICOM attribute StudyInstanceUID. If specified, any instance
that doesn't belong to the provided study is reported as a failure with failure reason 272 (PS3.18
§6.6.1.2).
Responses are always returned as:
application/dicom+json
The following Content-Type headers are supported:
multipart/related; type="application/dicom"application/dicom
Ingest-Time Transcoding
Unlike a pass-through store, the service may transcode pixel data at ingest time according to rules
evaluated against the instance's metadata (modality, transfer syntax, frame parameters such as bits
allocated/stored, rows, columns, and photometric interpretation — see Transfer Syntax
Support). By default, instances of modalities CR, CT, DX, MG, and MR —
and losslessly-encoded NM, OT, PT, RF, SM, and US instances — are transcoded to High-Throughput JPEG
2000 with RPCL Options (Lossless Only, 1.2.840.10008.1.2.4.202). All other DICOM attributes are
stored as provided.
Two transfer syntaxes are normalized before any rule is evaluated: instances arriving as Deflated
Explicit VR Little Endian (1.2.840.10008.1.2.1.99) or Explicit VR Big Endian
(1.2.840.10008.1.2.2) are re-encoded losslessly to Explicit VR Little Endian, and it is that
re-encoding the service stores — these two syntaxes are never a stored syntax. All data element
values, including pixel data, are preserved, though the bytes are re-serialized as Explicit VR
Little Endian: a big-endian instance comes back with every multi-byte value in little-endian byte
order, and an out-of-order dataset comes back re-sorted into ascending tag order. The file meta
group is rewritten by the encoder and carries its implementation UID rather than the sender's. An
instance whose deflated stream does not decode is rejected like any other unparseable input.
Ingest-time transcoding can be disabled per request with the header:
| Header | Accepted Values | Description |
|---|---|---|
x-kastoria-disable-transcode |
true |
Store instances in their original transfer syntax without transcoding (Deflated and Big Endian inputs are still normalized to Explicit VR Little Endian) |
Store Required Attributes
Each DICOM file must be parseable as a DICOM Part 10 file, and the following DICOM elements are required to be present:
StudyInstanceUID(0020,000D)SeriesInstanceUID(0020,000E)SOPInstanceUID(0008,0018)TransferSyntaxUID(0002,0010)
Note:
SOPClassUID(0008,0016) is extracted on a best-effort basis; instances lacking it are still accepted- No UID format/length validation is performed beyond presence checks
- Files that fail parsing or are zero-length are reported in the
FailedSOPSequencewith failure reason272
Store Response Status Codes
| Code | Description |
|---|---|
200 (OK) |
All the SOP instances in the request were stored successfully |
202 (Accepted) |
Some instances were stored successfully, others failed. Details are in the response body |
400 (Bad Request) |
The provided Content-Type is neither multipart/related nor application/dicom |
409 (Conflict) |
None of the instances in the store transaction request were stored |
500 (Internal Server Error) |
The server encountered an unexpected error, including a multipart/related Content-Type that names no boundary |
Store Response Payload
The response payload populates a DICOM dataset with the following elements:
| Tag | Name | Description |
|---|---|---|
| (0008,1190) | RetrieveURL |
The Retrieve URL of the study if StudyInstanceUID was provided and at least one instance was successfully stored |
| (0008,1198) | FailedSOPSequence |
The sequence of instances that failed to store |
| (0008,1199) | ReferencedSOPSequence |
The sequence of stored instances |
Each dataset in the FailedSOPSequence has the following elements:
| Tag | Name | Description |
|---|---|---|
| (0008,1150) | ReferencedSOPClassUID |
The SOP class UID of the instance that failed to store |
| (0008,1155) | ReferencedSOPInstanceUID |
The SOP instance UID of the instance that failed to store |
| (0008,1197) | FailureReason |
The reason code why this instance failed to store |
Each dataset in the ReferencedSOPSequence has the following elements:
| Tag | Name | Description |
|---|---|---|
| (0008,1150) | ReferencedSOPClassUID |
The SOP class UID of the instance that was stored (omitted when unavailable) |
| (0008,1155) | ReferencedSOPInstanceUID |
The SOP instance UID of the instance that was stored |
| (0008,1190) | RetrieveURL |
The retrieve URL of this instance on the DICOM server |
Note on Retrieve URLs: For POST /studies (without a study UID), the top-level study
RetrieveURL is only included when all stored instances belong to a single study.
Retrieve URL tags are omitted entirely when the base URL cannot be determined. The
authoritative base URL for retrieval from the DICOMweb service is configured in the service
deployment. As a RetrieveURL is dereferenced by whoever receives it, it is never built from an
unverified request header. If the base URL is not configured for a deployment, store responses from
that service carry no (0008,1190) at either level. The store itself still succeeds and the response
is otherwise unchanged — the instances are stored and listed in the ReferencedSOPSequence, without
a URL to fetch them back by.
Store Failure Reason Codes
| Code | Description |
|---|---|
272 (0x0110) |
Processing failure — used for all store failures, including parse failures, zero-length parts, storage errors, and instances whose StudyInstanceUID does not match the study UID stated in the request path |
Retrieve (WADO-RS)
This transaction offers support for retrieving stored studies, series, instances, frames, metadata, rendered images, and thumbnails by reference.
| Method | Path | Description |
|---|---|---|
| GET | /studies/{study} | Retrieve all instances within a study |
| GET | /studies/{study}/metadata | Retrieve metadata for all instances within a study |
| GET | /studies/{study}/series/{series} | Retrieve all instances within a series |
| GET | /studies/{study}/series/{series}/metadata | Retrieve metadata for all instances within a series |
| GET | /studies/{study}/series/{series}/instances/{instance} | Retrieve a single instance |
| GET | /studies/{study}/series/{series}/instances/{instance}/metadata | Retrieve metadata for a single instance |
| GET | /studies/{study}/series/{series}/instances/{instance}/frames/{frames} | Retrieve one or many frames from a single instance (comma-separated frame numbers, 1-indexed) |
| GET | /studies/{study}/series/{series}/instances/{instance}/rendered | Retrieve an instance rendered into an image format (renders frame 0) |
| GET | /studies/{study}/series/{series}/instances/{instance}/frames/{frames}/rendered | Retrieve frame(s) rendered into an image format |
| GET | /studies/{study}/series/{series}/instances/{instance}/thumbnail | Retrieve a thumbnail of an instance (renders frame 0) |
| GET | /studies/{study}/series/{series}/instances/{instance}/frames/{frames}/thumbnail | Retrieve thumbnail(s) of frame(s) |
Retrieve Instances Within Study or Series
The following Accept headers are supported for retrieving instances:
multipart/related; type="application/dicom"application/dicomapplication/**/*(defaults tomultipart/related; type="application/dicom")
The transfer-syntax Accept-header parameter (PS3.18 §8.7.3.5.2) is supported. When a specific
transfer syntax is requested and differs from the stored one, each instance is transcoded on the fly
before being returned. transfer-syntax=* (or omitting the parameter) returns instances in their
stored transfer syntax (which may be the result of ingest-time transcoding — see
Store). Each part's Content-Type carries a transfer-syntax parameter
identifying the actual returned syntax (PS3.18 §8.7.9). An unsupported requested transfer syntax
results in 406 Not Acceptable.
Retrieve an Instance
The following Accept headers are supported for retrieving a specific instance:
multipart/related; type="application/dicom"application/dicomapplication/**/*(defaults tomultipart/related; type="application/dicom")
The transfer-syntax Accept-header parameter is supported as described above — the instance is
transcoded when the requested syntax differs from the stored one.
Retrieve Frames
The following Accept headers are supported for retrieving frames:
multipart/related- returnsmultipart/related; type="<frame media type>"with appropriate media type based on the instance's transfer syntaxapplication/octet-streamapplication/**/*
The frame media type is derived from the returned transfer syntax:
application/octet-stream- Uncompressedimage/dicom-rle- RLE Losslessimage/jpeg- JPEG Baseline or JPEG Losslessimage/jls- JPEG-LSimage/jp2- JPEG 2000image/jxl- JPEG XLimage/jphc- High-Throughput JPEG 2000
A single-part response carries the frame media type, not application/octet-stream. A request
for one frame under Accept: */* against a JPEG-encoded instance is answered Content-Type:
image/jpeg; only an instance in an uncompressed transfer syntax is answered
application/octet-stream. There is no single-part media type this service falls back to — the
bytes are the stored frame, and the header names what they actually are.
A request naming more than one frame is always answered as multipart/related, whatever the
Accept header allows, because separate frames need separate body parts (PS3.18 §10.4.3).
The Accept header is checked against every frame media type this service can produce, not
against the one this instance will produce. A request with Accept: application/octet-stream for
a JPEG-encoded frame is therefore answered 200 with Content-Type: image/jpeg rather than 406.
A client that can only decode one encoding should name the transfer syntax it wants with the
transfer-syntax Accept-header parameter, which does govern what comes back. That parameter is
read from a multipart/related, application/dicom, application/* or */* media range only —
carried on a concrete image media type such as image/jpeg, it is ignored.
The transfer-syntax Accept-header parameter is supported. When a specific transfer syntax is
requested and differs from the stored one, frames are transcoded on the fly and the frame media type
reflects the target syntax. transfer-syntax=* (or omitting the parameter) returns frames in their
stored format. An unsupported requested transfer syntax results in 406 Not Acceptable.
Retrieve Metadata (for Study, Series, or Instance)
The following Accept header is supported for retrieving metadata:
application/dicom+json, or a wildcard that covers it (application/*,*/*, or noAcceptheader at all)
Metadata is returned in DICOM JSON format as defined in PS3.18 Annex F.
Compression: Metadata responses are served gzip-compressed when the client sends
Accept-Encoding: gzip.
Note: Bulk pixel data (PixelData, 7FE0,0010) is never included in metadata responses; retrieve
it via the frames or instance endpoints.
Retrieve Rendered Image (for Instance or Frame)
The following Accept headers are supported for retrieving a rendered image:
image/pngimage/jpegimage/bmpimage/*(defaults to PNG)*/*(defaults to PNG)multipart/relatedorapplication/octet-stream(defaults to PNG) — accepted so a client that names only a container gets a rendered image rather than a406
The service renders the specified instance or frame(s) into the requested image format. For instance
endpoints, frame 0 is rendered. Multiple frames are returned as multipart/related with individual
image parts.
Supported Query Parameters:
| Parameter | Format | Description |
|---|---|---|
viewport |
vw,vh[,sx,sy,sw,sh] |
Scaling dimensions (vw, vh: required positive integers, with vw×vh at most 16,777,216). Optional crop, all four values or none: sx, sy non-negative integers, sw, sh positive integers; the source region is extracted before scaling |
window |
center,width,function |
Windowing parameters. center and width must be numbers; function must be linear or sigmoid |
quality |
1-100 |
JPEG quality (integer 1-100, applies only to JPEG output) |
Priority: Image formats are selected in priority order: PNG > JPEG > BMP
Retrieve Thumbnail (for Instance or Frame)
The following Accept headers are supported for retrieving a thumbnail:
image/jpeg(default per DICOM spec)image/pngimage/bmpimage/*(defaults to JPEG)*/*(defaults to JPEG)multipart/relatedorapplication/octet-stream(defaults to JPEG) — accepted so a client that names only a container gets a thumbnail rather than a406
The service generates a thumbnail of the specified instance or frame(s). For instance endpoints,
frame 0 is rendered. Multiple frames are returned as multipart/related with individual image
parts.
Supported Query Parameters:
| Parameter | Format | Description |
|---|---|---|
viewport |
vw,vh |
Thumbnail dimensions (width and height are required positive integers, with vw×vh at most 1,048,576). Defaults to 128,128 |
Priority: Image formats are selected in priority order: JPEG > PNG > BMP
Retrieve Response Status Codes
| Code | Description |
|---|---|
200 (OK) |
All requested data was retrieved successfully |
400 (Bad Request) |
Invalid query parameters (e.g., malformed viewport, window, or quality value, or a non-integer frame number), or a /rendered or /thumbnail request naming more frames than the service is configured to render at once |
401 (Unauthorized) |
Authorization is enabled and the request carries no valid bearer token; see Authorization |
403 (Forbidden) |
Authorization is enabled and the requested study is not in the token's scope; see Authorization |
404 (Not Found) |
The specified DICOM resource could not be found, or the instance does not contain pixel data for rendered/thumbnail requests |
406 (Not Acceptable) |
The specified Accept header is not supported, or a requested transfer-syntax cannot be transcoded to |
500 (Internal Server Error) |
The server encountered an unexpected error (if a mid-stream error occurs after headers are sent, the connection is torn down instead) |
Search (QIDO-RS)
Query based on ID for DICOM Objects (QIDO) enables searching for studies, series and instances by attributes.
| Method | Path | Description |
|---|---|---|
| GET | /studies | Search for studies |
| GET | /studies/{study}/series | Search for series in a study |
| GET | /studies/{study}/instances | Search for instances in a study |
| GET | /studies/{study}/series/{series}/instances | Search for instances in a series |
The following Accept header is supported for searching:
application/dicom+json, or a wildcard that covers it (application/*,*/*, or noAcceptheader at all)
Index Requirements
Search queries are served from search indexes that are maintained automatically by a background study-processing stage after instances are stored.
Important: Newly stored studies become searchable once this processing has completed. Queries against studies that have not yet been processed return an empty array.
Supported Search Parameters (Study-Level)
The following query parameters are supported for study-level searches:
| Parameter | Support | Description |
|---|---|---|
StudyInstanceUID |
Direct lookup | Unique study identifier |
PatientID |
Exact match, case-insensitive | Patient identifier |
StudyDate |
Single date or range | Study date in YYYYMMDD format. Supports single date (20240101) or range (20240101-20240131, 20240101-, -20240131) |
PatientName |
Leading components, case-insensitive | Patient's name in DICOM PN form. The value names leading components and each matches whole: DOE matches DOE^JOHN, DOE^JOHN matches DOE^JOHN^Q but not DOE^JOHNSON. Matched against the alphabetic component group |
StudyTime |
Single time or range | Study time in DICOM TM format, HH[MM[SS[.FFFFFF]]]. Supports single time (143000) or range (080000-170000, 080000-, -170000) |
AccessionNumber |
Exact match, case-insensitive | Accession number |
StudyDescription |
Exact match, case-insensitive | Study description |
ModalitiesInStudy |
List; matches any one modality, ignoring case | Modality (e.g. CT, MR). A list separated by \ or , is an IN clause — the study matches when any of its modalities equals any listed value |
limit |
Supported (default 100, maximum 1000) | Maximum number of matches returned in one response |
offset |
Supported (default 0, maximum 1000) | Number of matches skipped before the first returned one. A value above the maximum is rejected with 400, not capped |
Search Matching
The service supports the following matching types:
| Search Type | Supported Attributes | Example |
|---|---|---|
| Range Query | StudyDate, StudyTime |
StudyDate=20240101-20240131 - Inclusive range. Either bound may be omitted (e.g., StudyDate=20240101- or StudyDate=-20240131) |
| Exact Match | StudyInstanceUID, PatientID, AccessionNumber, StudyDescription, ModalitiesInStudy |
PatientID=PATIENT001 |
| Leading Components | PatientName |
PatientName=DOE matches DOE^JOHN — the value names leading PN components and each matches whole, so this is not an exact match on the full name |
Note:
- A zero-length value is universal matching (PS3.4 §C.2.2.2.1):
PatientName=places no constraint and every study matches. It is neither an error nor an ignored parameter, so it carries no Warning header field — a universal matcher selects everything by definition - Matching ignores case for every attribute except
StudyInstanceUID, which is a UID:aa-1234andAA-1234are one identifier, andchrisandCHRISare one person StudyTimevalues are compared by the instant they denote, so a query and a stored value written to different precision (090000and090000.000000) match- The upper bound of a
StudyTimerange runs to the end of the unit it names, matching the way aStudyDateupper bound runs to the end of its day.-235959includes a study acquired at235959.500, and-0900includes one at090030. An explicit fraction names an instant instead, so-090030.000ends exactly there - Each query parameter must be supplied at most once. A repeated parameter —
PatientID=A&PatientID=B— is rejected with400 Bad Requestnaming the parameter - A
StudyTimenaming the whole day —000000-235959,000000-,-235959, or a bare-— narrows nothing and is treated as absent rather than searched for
Attribute ID
Query parameter keys may be encoded as either of the following (per PS3.18 §8.3.4.1):
| Value | Example |
|---|---|
{group}{element} |
0020000D |
{dicomKeyword} |
StudyInstanceUID |
Response Pagination
Both search transactions implement response pagination per PS3.18 §8.3.4.4.
| Parameter | Default | Behavior |
|---|---|---|
offset |
0 | Number of matches skipped before the first returned match; an explicit value above 1000 is rejected with 400 |
limit |
100 | Maximum matches returned in one response; an explicit value above 1000 is capped |
maxResults (PS3.18 §8.3.4.4.1) is 1000 — the ceiling on an explicit limit, so no single
response returns more than 1000 matches. A request that supplies no limit receives 100.
When matches remain beyond those returned, the response carries a Warning header field:
Warning: 299 {service}: There are more additional results that can be requested
The header announces that a further page can be requested. It does not carry a count of the matches not returned.
Search Depth
A search that combines two or more matching attributes is limited in how far back it reaches, but only where it has to be. Naming anything selective — a patient identifier, an accession number — settles the search almost at once, and it is then answered in full however old the matches are. The limit is reached only when every attribute named is a broad one.
Where a search is limited, the response is 200 (OK) and carries a Warning header field naming the
earliest study date covered:
Warning: 299 {service}: Searched studies from 20241216 onward; earlier matches may exist
Results from that date onward are complete. Nothing is claimed about studies before it.
A PatientName search names no date. A PatientName filter matches leading components, so it
is answered from a range covering every name built on them — and inside that range entries are
ordered by name before date, so the search reaches the second patient only after exhausting the
first. Where such a search is limited, the warning states the limit without dating it:
Warning: 299 {service}: The search was limited before every matching study was examined; further matches may exist
Both spellings mean the same thing to a caller: the result set is not known to be complete. Only the first tells you from when it is.
A search on a single matching attribute is not limited at all, and neither is a search on none. Both are answered in full — a search for a modality last acquired three years ago returns it.
An empty result set carries the warning too, when the search was limited. 200 (OK) with an
empty array and no Warning header means no study matches. 200 (OK) with an empty array and this
warning means no study matches within the range searched. These are different answers, and they are
distinguished by the header rather than by the payload.
An explicit StudyDate narrows the search but does not remove the limit. It is the most
effective thing a caller can supply: it bounds every attribute at once, so a search that names a
date is normally answered in full and carries no warning whatever attributes accompany it.
A caller needing a longer history for a broad combination of attributes should page through it by date, a range at a time.
Unsupported Query Parameters
A query parameter this service does not match on is accepted, ignored, and announced. The
response is 200 (OK) and carries a Warning header field naming every parameter that was
ignored:
Warning: 299 {service}: The following query parameters are not supported and were ignored: PatientSex\StudyID
This applies to both search transactions, and to any parameter other than that level's matching
attributes listed above and the limit / offset controls — including an attribute the service
returns but cannot match on, and a parameter it does not recognize at all. The result set is
therefore wider than the request asked for: the ignored parameter narrowed nothing.
A 400 is not used here. PS3.18 reserves it for a query the service cannot parse, and PS3.4
§C.2.2.1.3 permits an Optional Key to be returned without being matched on — so a well-formed
query the service can only partly honor is answered, with the shortfall stated.
Parameter names are separated by \, the DICOM multi-valued delimiter, rather than by a comma.
Warning is a comma-delimited list field, so a comma inside one warn-text would make two warnings
impossible to tell apart.
A name this service cannot repeat back is reported as (unprintable). DICOM keywords and
Attribute IDs are alphanumeric, so a parameter name outside that shape is not one this service
defines, and echoing it would place caller-supplied text — a line break included — into a header
field. The substitution keeps the count honest: the caller is still told how many of its parameters
were ignored, even where one of them cannot be named. The parentheses are what make the token
impossible to mistake for an Attribute ID.
Warning: 299 {service}: The following query parameters are not supported and were ignored: PatientSex\(unprintable)
Both warnings are sent when both apply — a query naming an ignored attribute can still overflow its page — as two warn-values, the query's shortcoming before the response's:
Warning: 299 {service}: The following query parameters are not supported and were ignored: PatientSex
Warning: 299 {service}: There are more additional results that can be requested
Both parameters must be non-negative integers. A malformed value is rejected with 400 Bad
Request rather than ignored — silently dropping a limit would return the full result set to a
caller that asked for one page.
offset may not exceed 1000 — the same ceiling as limit, so a request may skip no more than
it may retrieve — and a larger one is rejected with 400 Bad Request rather than capped. Paging is
offset-based with no cursor, so reaching a match means loading every match in front of it, and a
skipped match costs the same storage reads as a returned one. A caller needing to go deeper should
narrow the query rather than page further into an unnarrowed one.
limit is capped rather than rejected because a capped page is still a prefix of the page
requested, and the Warning header says more remains — whereas a capped offset would silently
answer with a different page than the one asked for.
Results are ordered by study date and time, most recent first. One exception:
- A search on
PatientNamethat names fewer components than the stored name —SMITHmatchingSMITH^JOHN— is ordered most-recent-first within each matching patient, but is not ordered by date across several patients sharing those leading components.
Notes for Client Implementers
Do not treat 200 (OK) with an empty array as definitive without checking for a Warning header
field. A search limited to a window returns the same empty payload whether nothing matches at all
or nothing matches recently. The header is the only distinction.
Treat a 299 warning as information, not an error. It accompanies a successful response and
does not indicate a failed or degraded search. A response may carry more than one — an ignored
parameter, a limited window, and further pages available are independent conditions and can all
apply at once.
To search a longer history, page by date rather than widening the range. Take the date the
warning names, and issue the next request with a StudyDate range ending the day before it. Repeat
until a response arrives without the warning, or until far enough back to stop. Each request is
bounded, and together they cover the history without any single request being expensive.
Supply a StudyDate whenever one is known. It bounds every attribute at once, which is both
faster and the surest way to receive a complete answer rather than a limited one.
Prefer StudyInstanceUID when it is known. It is answered as a direct lookup, without reading
any index.
Supported Search Parameters (Series-Level)
The following query parameters are supported for series-level searches within a study:
| Parameter | Support | Description |
|---|---|---|
Modality |
List; matches any one, ignoring case | Filter by modality. A list separated by \ or , is an IN clause |
SeriesInstanceUID |
Exact match | Filter by series UID (a UID has no case to ignore) |
SeriesNumber |
Exact match | Filter by series number |
limit |
Supported (default 100, maximum 1000) | Maximum number of matches returned in one response |
offset |
Supported (default 0, maximum 1000) | Number of matches skipped before the first returned. A value above the maximum is rejected with 400, not capped |
Supported Search Parameters (Instance-Level)
The following query parameters are supported for instance-level searches, both within a series and within a whole study:
| Parameter | Support | Description |
|---|---|---|
SOPInstanceUID |
Exact match | Filter by SOP Instance UID (a UID has no case to ignore) |
InstanceNumber |
Exact match | Filter by instance number |
SeriesInstanceUID |
Exact match | Filter by series UID. On the study-level endpoint this narrows the search to one series; on the series-level endpoint the series is already fixed by the path, so asking for a different one returns an empty array |
limit |
Supported (default 100, maximum 1000) | Maximum number of matches returned in one response |
offset |
Supported (default 0, maximum 1000) | Number of matches skipped before the first returned. A value above the maximum is rejected with 400, not capped |
Instance-level searches do not use the search indexes, but they read data built by the same study-processing stage described under Index Requirements. As with series-level searches, a study that has not yet been processed returns an empty array.
Search Response
The response is an array of DICOM datasets in DICOM JSON format. The following attributes are returned by default for study-level searches:
Default Study Tags:
| Tag | Attribute Name |
|---|---|
| (0020,000D) | StudyInstanceUID |
| (0010,0020) | PatientID |
| (0010,0010) | PatientName |
| (0010,0030) | PatientBirthDate |
| (0010,0040) | PatientSex |
| (0020,0010) | StudyID |
| (0008,0020) | StudyDate |
| (0008,0030) | StudyTime |
| (0008,0050) | AccessionNumber |
| (0008,0061) | ModalitiesInStudy |
| (0008,1030) | StudyDescription |
| (0020,1206) | NumberOfStudyRelatedSeries |
| (0020,1208) | NumberOfStudyRelatedInstances |
Default Series Tags:
| Tag | Attribute Name |
|---|---|
| (0020,000D) | StudyInstanceUID |
| (0020,000E) | SeriesInstanceUID |
| (0020,0011) | SeriesNumber |
| (0008,0005) | SpecificCharacterSet |
| (0008,0060) | Modality |
| (0008,0021) | SeriesDate |
| (0008,0031) | SeriesTime |
| (0008,103E) | SeriesDescription |
| (0008,0070) | Manufacturer |
| (0008,0080) | InstitutionName |
| (0008,0090) | ReferringPhysicianName |
| (0008,1090) | ManufacturerModelName |
| (0018,0015) | BodyPartExamined |
| (0018,1030) | ProtocolName |
| (0020,1209) | NumberOfSeriesRelatedInstances |
Default Instance Tags:
The minimum set of PS3.18 Table 10.6.3-5, returned by both instance-level searches:
| Tag | Attribute Name |
|---|---|
| (0008,0016) | SOPClassUID |
| (0008,0018) | SOPInstanceUID |
| (0020,000D) | StudyInstanceUID |
| (0020,000E) | SeriesInstanceUID |
| (0020,0013) | InstanceNumber |
| (0028,0008) | NumberOfFrames |
Note: The service does not currently support the includefield parameter to return additional
attributes beyond the defaults.
Search Response Status Codes
| Code | Description |
|---|---|
200 (OK) |
The response payload contains all matching resources (an empty array when there are no matches) |
400 (Bad Request) |
The query cannot be honored as written: a range that cannot match (a StudyDate range whose end precedes its start), a limit or offset that is not a non-negative integer, an offset above 1000, or a query parameter supplied more than once |
401 (Unauthorized) |
Authorization is enabled and the request carries no valid bearer token; see Authorization |
403 (Forbidden) |
Authorization is enabled and a request for a study by UID, or for anything beneath it (series, instances, frames, metadata, etc.), names a Study Instance UID that is not in the token's scope; see Authorization |
406 (Not Acceptable) |
The specified Accept header does not allow application/dicom+json |
500 (Internal Server Error) |
The server encountered an unexpected error |
Search Notes
- An empty result set is returned with
200 (OK)and an empty JSON array —204 (No Content)is not used - A
200 (OK)always means the search ran to completion. A search that fails part-way through returns500, and never a partial or empty array with200— a client must be able to distinguish "no studies match" from "the search could not be completed". A query the service cannot satisfy because of how it is written returns400, so a caller can tell its own mistake from the server's. - A
200 (OK)does not by itself mean every parameter was applied. Two things narrow what the payload holds relative to what was asked, and both are stated in a Warning header field rather than left for the client to infer: - A parameter this service does not match on is ignored, so the result set is wider than the request — see Unsupported Query Parameters.
- Matches beyond
limitare not returned, so the result set is narrower than the whole match set — see themaxResultsnote above.
A response carrying no Warning header field is complete in every sense: every parameter was applied, no match was left behind, and no limit was placed on how far back the search reached.
Technical Specifications
Transfer Syntax Support
The following transfer syntaxes are recognized for ingest-time transcoding decisions. Transfer syntaxes not in this list are stored as-is (no transcoding is attempted).
Uncompressed:
- 1.2.840.10008.1.2 (Implicit VR Little Endian)
- 1.2.840.10008.1.2.1 (Explicit VR Little Endian)
- 1.2.840.10008.1.2.2 (Explicit VR Big Endian) — accepted on ingest, stored as Explicit VR Little Endian (see Ingest-Time Transcoding); available as a retrieve target
- 1.2.840.10008.1.2.1.99 (Deflated Explicit VR Little Endian) — accepted on ingest, stored as Explicit VR Little Endian (see Ingest-Time Transcoding); not available as a retrieve target
Compressed:
- 1.2.840.10008.1.2.5 (RLE Lossless)
- 1.2.840.10008.1.2.4.50 (JPEG Baseline Process 1)
- 1.2.840.10008.1.2.4.57 (JPEG Lossless, Non-Hierarchical)
- 1.2.840.10008.1.2.4.70 (JPEG Lossless, Non-Hierarchical, First-Order Prediction)
- 1.2.840.10008.1.2.4.80 (JPEG-LS Lossless)
- 1.2.840.10008.1.2.4.81 (JPEG-LS Lossy)
- 1.2.840.10008.1.2.4.90 (JPEG 2000 Lossless Only)
- 1.2.840.10008.1.2.4.91 (JPEG 2000)
- 1.2.840.10008.1.2.4.110 (JPEG XL Lossless)
- 1.2.840.10008.1.2.4.112 (JPEG XL)
- 1.2.840.10008.1.2.4.201 (High-Throughput JPEG 2000 Lossless Only)
- 1.2.840.10008.1.2.4.202 (High-Throughput JPEG 2000 with RPCL Options Lossless Only)
- 1.2.840.10008.1.2.4.203 (High-Throughput JPEG 2000)
Ingest Transcoding Rules
At store time the first matching rule determines the target transfer syntax; if the instance is already in the target syntax (or no rule matches), it is stored unchanged. Rules are evaluated against the post-normalization transfer syntax, so an instance sent as Deflated or Big Endian Explicit VR is evaluated as Explicit VR Little Endian:
| Modality | Condition | Target Transfer Syntax |
|---|---|---|
| CR, CT, DX, MG, MR | Always | 1.2.840.10008.1.2.4.202 (HTJ2K RPCL Lossless Only) |
| NM, OT, PT, RF, SM, US | Source transfer syntax is lossless | 1.2.840.10008.1.2.4.202 (HTJ2K RPCL Lossless Only) |
Transcoding can be disabled per request with the x-kastoria-disable-transcode: true header.
Retrieve-Time Transcoding
WADO-RS retrieve endpoints (study, series, instance, and frames) honor the transfer-syntax
Accept-header parameter. When the requested transfer syntax differs from the stored one, the service
transcodes on the fly using the same transfer syntax support table above. Deflated Explicit VR
Little Endian is not offered as a retrieve target. Transcoding between any other pair of supported
transfer syntaxes is available, Explicit VR Big Endian included; requesting an unsupported transfer
syntax (or one for which no codec is available) results in 406 Not Acceptable.
Character Set Support
The service supports all DICOM-defined character sets.
Limitations and Known Issues
Current Limitations
The following optional features are not supported:
-
Wildcard Matching: The optional wildcard matching capability is not supported, and wildcard characters (
*,?) are not treated as wildcards in any search parameter. For attributes with a PN VR, PS3.4 §C.2.2.2.4 makes wildcard matching implementation dependent and requires the position to be stated here. -
QIDO-RS includefield: The optional
includefieldparameter (PS3.18 §8.3.4.3) to return additional attributes beyond defaults is not currently supported. -
Rendered Image Viewport Cropping: Only the numeric
sx,sy,sw,shform (PS3.18 §8.3.5.1.3) is supported. Empty crop sub-values (which the standard defines as defaulting to 0 or the image edge) and negativesw/sh(which the standard defines as a horizontal/vertical flip) are rejected with400rather than honored. -
ETag/Cache Validation: ETag headers and If-None-Match cache validation (optional per PS3.18 §8.3.3) are not supported for metadata endpoints.
-
Fuzzy Matching: Fuzzy matching (optional per PS3.18 §10.6.3.2) is not supported in any search parameters.
References
DICOM® is the registered trademark of the National Electrical Manufacturers Association for its standards publications relating to digital communications of medical information.