Documents (DMS)
The Document Management System (DMS) REST API lets external systems upload, search, list, and
retrieve documents through a versioned, resource-oriented surface. All endpoints live under
/api/dms/public/v1/ and are protected by OAuth bearer tokens.
/api/dms/public/v1/
Authentication
Every /dms/public/ endpoint requires a valid bearer token. The controller validates the
token's jpt (principal-type) claim and the caller's API license on every request. See
Authentication to obtain a token, then send it as:
Authorization: Bearer <access_token>Upload a document
/api/dms/public/v1/documents
Upload a new document. On success the endpoint returns 201 Created with a
Location header that points at the newly created document, and a body containing the
generated document ID.
HTTP/1.1 201 Created
Location: /api/dms/public/v1/documents/123456{
"documentId": 123456
}Idempotency and duplicate detection
The upload endpoint uses header-based idempotency. Send an
Idempotency-Key header containing a client-generated UUID with the request. If a request
is replayed with the same key, the server returns 201 Created with the original
documentId and a Location header pointing at the original document — no
second document is created. The header is optional; omitting it means every request creates a new
document, even if the metadata is identical.
Idempotency-Key: 3fa85f64-5717-4562-b3fc-2c963f66afa6
The key must be a valid UUID; otherwise the request is rejected with 400 Bad Request.
There is no content-based uniqueness check — category, type, and document
number are not used to detect duplicates, and there is no 409 Conflict
response from this endpoint.
Validation
The metadata part is a JSON object with category (required),
type (required), documentNumber, documentName,
description, and attributes (an object of attribute name → value), sent
alongside the binary file in a multipart/form-data body.
| Status | Cause |
|---|---|
400 Bad Request | Missing file, missing/invalid metadata JSON, missing category/type, or a required index attribute for the category/type is missing or empty. |
422 Unprocessable Entity | category or type does not match a recognised value. |
500 Internal Server Error | The document could not be saved. |
Use Get categories and types and Get category/type attributes to discover valid values and required attributes before uploading.
Search documents
/api/dms/public/v1/documents/search
Search accepts its filter criteria as a JSON body rather than query parameters. Index attribute
filters can exceed safe URL length limits (~2000 characters) and cannot be passed reliably as query
parameters, so a POST body is used. Pagination remains in the query string.
POST /api/dms/public/v1/documents/search?page=1&pageSize=50{
"category": "Invoices",
"type": "AP",
"documentNumber": "INV-100234",
"rangeFilter": "Last 6 months",
"attributes": {
"VendorCode": "ACME",
"JobNumber": "J-1001"
}
}| Field | Description |
|---|---|
category | Document category to filter by. Must be a recognised category, or the request fails with 422 Unprocessable Entity. |
type | Document type within the category. Must be a recognised type, or the request fails with 422 Unprocessable Entity. |
documentNumber | Filters to documents matching this DMS document number. |
rangeFilter | Named date range to restrict results by creation date (e.g. "Last 6 months"). Defaults to "Last 6 months" when omitted. |
attributes | Object of index-attribute filters (attribute name → value). Each attribute value must be a single string; multi-value filtering is not supported in v1. |
| Query parameter | Description |
|---|---|
page | 1-based page number. Defaults to 1. |
pageSize | Number of documents per page. |
List documents
/api/dms/public/v1/documents
A plain GET on the collection returns an unfiltered listing of documents, paged with
the same page and pageSize query parameters. Use
search when you need to filter.
GET /api/dms/public/v1/documents?page=1&pageSize=50Download a document
/api/dms/public/v1/documents/{documentId}
Downloads the document's raw binary content by its ID. The response is the file itself — not a JSON
object — with Content-Type set from the file's extension and a
Content-Disposition header carrying the original document name. Returns
404 Not Found when the document does not exist or its file content is unavailable.
Download by DMS number
/api/dms/public/v1/documents/dms-number/{dmsNumber}
Downloads a document's binary content looked up by its DMS document number instead of its internal
document ID. If multiple documents share the same DMS number, the most recently created
document is returned. Returns 400 Bad Request if dmsNumber is empty, and
404 Not Found if no document matches or its file content is unavailable.
Retrieve document metadata
/api/dms/public/v1/documents/{documentId}/info
Returns metadata for the document without downloading the document content itself. Useful when
you only need to inspect index attributes, category, type, or creation details. Returns
404 Not Found when the document does not exist or is not visible to the caller.
Get categories and types
/api/dms/public/v1/documents/metadata
Returns every valid document category along with the types associated with it. Use this to populate category/type pickers or to validate values before calling upload or search.
{
"categories": [
{
"category": "Invoices",
"types": ["AP", "AR"]
}
]
}Get category/type attributes
/api/dms/public/v1/documents/CategoryTypeAttributes
Returns the index attributes configured for a specific category/type combination, including which attributes are required. Use this to build an upload form dynamically and to know which attribute values must be supplied so upload doesn't fail validation.
GET /api/dms/public/v1/documents/CategoryTypeAttributes?category=Invoices&type=AP| Query parameter | Description |
|---|---|
category | Document category. Returns 400 Bad Request if it does not exist. |
type | Document type. Returns 400 Bad Request if it does not exist, or if the category/type combination is invalid. |
Rate limiting
All DMS public endpoints enforce a sliding-window rate limit of 100 requests per minute per client. The client is identified by the Bearer token; if no token can be resolved the caller's IP address is used as a fallback.
Every response includes the current rate-limit state:
| Header | Description |
|---|---|
X-RateLimit-Limit | The request limit for the current window (100). |
X-RateLimit-Remaining | Requests remaining in the current window. |
X-RateLimit-Reset | Unix epoch timestamp indicating when the window resets. |
When the limit is exceeded the server returns 429 Too Many Requests with a
Retry-After header (seconds until the window resets) in addition to the headers above.
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1750384200
Retry-After: 42Errors
Errors are returned as RFC 7807 problem detail documents. See REST API Overview → Error responses for the common status codes and shape. DMS endpoints additionally use:
| Status | Meaning |
|---|---|
403 Forbidden | The token's jpt claim is not user_api, or its account code doesn't match this site. |
422 Unprocessable Entity | category or type supplied in a request is not a recognised value. |