Integration API

Reference: documents

Every document endpoint – parameters, fields, examples and errors.

Base address: https://<your CMS address>/api/ext/v1. Every request needs Authorization: Bearer <key>. Scope says what the key needs.

The document object

id
uuid
DDM's id.
externalRef
string | null
The reference it was pushed with.
sourceId
uuid | null
The push source or connector it came through.
name
string
The file name, including its extension.
fileType
string
The extension, e.g. pdf.
mimeType
string | null
sizeBytes
integer
status
draft | in_review | approved | archived
shareable
boolean
Whether readers may send it, open it elsewhere or download it.
highlighted
boolean
Highlighted now: put forward by somebody, or within its highlight window.
availableFrom, availableUntil
date-time | null
Readers see the document only within this window. Either end may be open.
highlightFrom, highlightUntil
date-time | null
The document is highlighted within this window, by itself.
watermarked
boolean
Every copy a reader views or downloads carries their e-mail address across each page. PDFs and Office files only; a watermarked document cannot be shared by link.
titles
object
A title per market code.
tags
string[]
categoryIds
uuid[]
Where it is filed – only categories the key can see.
categoryRefs
string[]
The references of those categories, where they have one.
currentVersion
object | null
id, versionNo, checksum (SHA-256, hex), sizeBytes, mimeType, createdAt.
createdAt, updatedAt
date-time
updatedAt is the last change – see Change feed.

PUT /documents/ref/{ref} – push

Scope write. Creates the document with this reference in the key's push source, or updates it. See Pushing documents.

Body: multipart/form-data with

file
file required
The file. Up to the plan's maximum file size.
metadata
JSON string
name, categoryPath, categoryIds, categoryRefs, mimeType, tags, titles, groupName – all optional. With categoryIds and/or categoryRefs the document is filed exactly there, with categoryPath in the path's category as well.

or application/json with the same fields as metadata, plus

fileUrl
string required
An HTTP(S) address DDM downloads the file from – up to the plan's maximum file size, like an upload.

Answer: 201 (created) or 200, with { "outcome": "created" | "versioned" | "unchanged" | "skipped", "document": Document | null }.

Errors: 400 invalid metadata · 403 read-only key, push source missing or switched off, missing permissions · 409 an approval is running · 413 file too large or storage full · 415 wrong Content-Type · 422 fileUrl could not be fetched.

Request

curl -X PUT "https://ddm.example.com/api/ext/v1/documents/ref/PIM-4711" \
  -H "Authorization: Bearer $DDM_API_KEY" \
  -F "file=@Price-list-2026.pdf;type=application/pdf" \
  -F 'metadata={"categoryPath": "Products/Price lists", "tags": ["Prices", "2026"], "titles": {"DE": "Preisliste 2026"}};type=application/json'

Response · 201 Created

{
  "outcome": "created",
  "document": {
    "id": "dc8594e0-0ead-4049-aaee-2ef899bcf76f",
    "externalRef": "PIM-4711",
    "sourceId": "5d02b7aa-5175-42e9-9277-aa19063833f2",
    "name": "Price-list-2026.pdf",
    "fileType": "pdf",
    "mimeType": "application/pdf",
    "sizeBytes": 589,
    "status": "draft",
    "shareable": true,
    "highlighted": false,
    "titles": {
      "DE": "Preisliste 2026"
    },
    "tags": [
      "2026",
      "Prices"
    ],
    "categoryIds": [
      "078a554f-19a2-4285-b854-8546de01f815"
    ],
    "currentVersion": {
      "id": "b5a8ce67-c8f1-439a-aadb-86e1b73223e2",
      "versionNo": 1,
      "checksum": "5db6ba22797a193286fdebf4919730b4571146bde75bb4ad3dc856a38f2f71c1",
      "sizeBytes": 589,
      "mimeType": "application/pdf",
      "createdAt": "2026-10-27T20:01:46.510Z"
    },
    "createdAt": "2026-10-27T20:01:46.510Z",
    "updatedAt": "2026-10-27T20:01:46.838Z"
  }
}

Sending the same file again, then a changed one:

  • 200, "outcome": "unchanged" – the same version
  • 200, "outcome": "versioned" – currentVersion.versionNo is now 2

PUT /documents/{id} – new bytes by id

Scope write. The same content as a push – multipart with file and metadata, or JSON with fileUrl – for a document you address by DDM's id:

  • If it belongs to the key's push source, this is the same as PUT /documents/ref/{ref} with its reference – by the source's rules.
  • Any other document, e.g. one uploaded in the CMS, gets a new version as an upload would. tags, titles, categoryIds and categoryRefs apply as for a push.

Answer: 200 with outcome and the document.

GET /documents – list and change feed

Scope read. Documents the key can see, oldest change first.

limit
1–500
Page size, default 100.
cursor
string
nextCursor of the previous page.
updatedSince
date-time
Only documents changed at or after this time.
categoryId
uuid
Only documents filed in this category.
categoryRef
string
The same category by its reference, instead of categoryId.
deep
boolean
With categoryId or categoryRef: include the categories below it.
externalRef
string
Only documents with this reference.
tag
string
Only documents with this tag.
status
draft | in_review | approved | archived
own
boolean
Only documents pushed through this key's push source.

Answer: { "data": Document[], "nextCursor": string | null }.

Request

curl "https://ddm.example.com/api/ext/v1/documents?limit=2&own=true" \
  -H "Authorization: Bearer $DDM_API_KEY"

Response · 200 OK

{
  "data": [
    {
      "id": "dc8594e0-0ead-4049-aaee-2ef899bcf76f",
      "externalRef": "PIM-4711",
      "sourceId": "5d02b7aa-5175-42e9-9277-aa19063833f2",
      "name": "Price-list-2026.pdf",
      "fileType": "pdf",
      "mimeType": "application/pdf",
      "sizeBytes": 605,
      "status": "draft",
      "shareable": true,
      "highlighted": false,
      "titles": {
        "DE": "Preisliste 2026"
      },
      "tags": [
        "2026",
        "Prices"
      ],
      "categoryIds": [
        "078a554f-19a2-4285-b854-8546de01f815"
      ],
      "currentVersion": {
        "id": "1730e7bb-2f98-4761-aa9b-964c521351b3",
        "versionNo": 2,
        "checksum": "0bcb7c3b4886f699a985563d7bc9476bf75b4af35a57ff959f46c37e386cf54f",
        "sizeBytes": 605,
        "mimeType": "application/pdf",
        "createdAt": "2026-10-27T20:01:46.904Z"
      },
      "createdAt": "2026-10-27T20:01:46.510Z",
      "updatedAt": "2026-10-27T20:01:47.169Z"
    }
  ],
  "nextCursor": null
}

GET /documents/{id} · GET /documents/ref/{ref}

Scope read. One document. 404 if it does not exist or the key cannot see it. By reference only within the key's push source.

Request

curl https://ddm.example.com/api/ext/v1/documents/dc8594e0-0ead-4049-aaee-2ef899bcf76f \
  -H "Authorization: Bearer $DDM_API_KEY"

Response · 200 OK

{
  "id": "dc8594e0-0ead-4049-aaee-2ef899bcf76f",
  "externalRef": "PIM-4711",
  "sourceId": "5d02b7aa-5175-42e9-9277-aa19063833f2",
  "name": "Price-list-2026.pdf",
  "fileType": "pdf",
  "mimeType": "application/pdf",
  "sizeBytes": 605,
  "status": "draft",
  "shareable": true,
  "highlighted": false,
  "titles": {
    "DE": "Preisliste 2026"
  },
  "tags": [
    "2026",
    "Prices"
  ],
  "categoryIds": [
    "078a554f-19a2-4285-b854-8546de01f815"
  ],
  "currentVersion": {
    "id": "1730e7bb-2f98-4761-aa9b-964c521351b3",
    "versionNo": 2,
    "checksum": "0bcb7c3b4886f699a985563d7bc9476bf75b4af35a57ff959f46c37e386cf54f",
    "sizeBytes": 605,
    "mimeType": "application/pdf",
    "createdAt": "2026-10-27T20:01:46.904Z"
  },
  "createdAt": "2026-10-27T20:01:46.510Z",
  "updatedAt": "2026-10-27T20:01:47.169Z"
}

PATCH /documents/{id} · PATCH /documents/ref/{ref}

Scope write. Changes only what is sent:

name
string
status
archived | draft
Archive, or bring back. Approval statuses are set only by the approval workflow.
shareable
boolean
highlighted
boolean
availableFrom, availableUntil, highlightFrom, highlightUntil
date-time | null
The availability and highlight windows; null clears an end.
watermarked
boolean
Stamp each reader's e-mail address on the pages they get. PDFs and Office files only.
tags
string[]
Replaces all tags.
titles
object
Merged per market. An empty string removes that market's title.
categoryIds
uuid[]
Replaces where it is filed. Needs full rights on the old and the new categories.
categoryRefs
string[]
The same by reference. With categoryIds both count: 1–20 categories in all.

Answer: the document. Errors: 400, 403, 404, 409 (approval running).

Request

curl -X PATCH https://ddm.example.com/api/ext/v1/documents/dc8594e0-0ead-4049-aaee-2ef899bcf76f \
  -H "Authorization: Bearer $DDM_API_KEY" -H "Content-Type: application/json" \
  -d '{"shareable":false,"tags":["Prices","2026","Export"]}'

Response · 200 OK

{
  "id": "dc8594e0-0ead-4049-aaee-2ef899bcf76f",
  "externalRef": "PIM-4711",
  "sourceId": "5d02b7aa-5175-42e9-9277-aa19063833f2",
  "name": "Price-list-2026.pdf",
  "fileType": "pdf",
  "mimeType": "application/pdf",
  "sizeBytes": 605,
  "status": "draft",
  "shareable": false,
  "highlighted": false,
  "titles": {
    "DE": "Preisliste 2026"
  },
  "tags": [
    "2026",
    "Export",
    "Prices"
  ],
  "categoryIds": [
    "078a554f-19a2-4285-b854-8546de01f815"
  ],
  "currentVersion": {
    "id": "1730e7bb-2f98-4761-aa9b-964c521351b3",
    "versionNo": 2,
    "checksum": "0bcb7c3b4886f699a985563d7bc9476bf75b4af35a57ff959f46c37e386cf54f",
    "sizeBytes": 605,
    "mimeType": "application/pdf",
    "createdAt": "2026-10-27T20:01:46.904Z"
  },
  "createdAt": "2026-10-27T20:01:46.510Z",
  "updatedAt": "2026-10-27T20:01:47.260Z"
}

DELETE /documents/{id} · DELETE /documents/ref/{ref}

Scope write. Deletes the document. Answer: 204. Errors: 403, 404, 409 (retention hold, approval running).

Request

curl -X DELETE https://ddm.example.com/api/ext/v1/documents/dc8594e0-0ead-4049-aaee-2ef899bcf76f \
  -H "Authorization: Bearer $DDM_API_KEY"

Response · 204 No Content – No body.

GET /documents/{id}/content · GET /documents/ref/{ref}/content

Scope read. The file.

versionId
uuid
A particular version; default the current one.

Headers: Range, If-None-Match. Answer: 200, 206 or 304, with Content-Type, Content-Length, ETag and Content-Disposition. With a released content key, only documents that may leave the app (shareable) can be downloaded (otherwise 403).

Request

curl -o Price-list-2026.pdf -D - \
  https://ddm.example.com/api/ext/v1/documents/dc8594e0-0ead-4049-aaee-2ef899bcf76f/content \
  -H "Authorization: Bearer $DDM_API_KEY"

Response · 200 OK – Headers of the answer – the body is the file itself:

HTTP/1.1 200 OK
accept-ranges: bytes
content-disposition: attachment; filename="Price-list-2026.pdf"; filename*=UTF-8''Price-list-2026.pdf
content-length: 605
content-type: application/pdf
etag: "1730e7bb-2f98-4761-aa9b-964c521351b3"

With the last ETag as If-None-Match, an unchanged file answers without a body:

HTTP/1.1 304 Not Modified
cache-control: private, max-age=300, must-revalidate
etag: "1730e7bb-2f98-4761-aa9b-964c521351b3"

With Range: bytes=0-99, only part of it:

HTTP/1.1 206 Partial Content
accept-ranges: bytes
content-disposition: attachment; filename="Price-list-2026.pdf"; filename*=UTF-8''Price-list-2026.pdf
content-length: 100
content-range: bytes 0-99/605
content-type: application/pdf
etag: "1730e7bb-2f98-4761-aa9b-964c521351b3"

GET /documents/{id}/text · GET /documents/ref/{ref}/text

Scope read. The text DDM read out of the current version, for a search index: { "versionId", "versionNo", "language", "content" }. Follows the readers' rules, including for a key that sees everything.

Request

curl https://ddm.example.com/api/ext/v1/documents/dc8594e0-0ead-4049-aaee-2ef899bcf76f/text \
  -H "Authorization: Bearer $DDM_API_KEY"

Response · 200 OK

{
  "versionId": "1730e7bb-2f98-4761-aa9b-964c521351b3",
  "versionNo": 2,
  "language": null,
  "content": "Price list 2026, second edition"
}

GET /documents/{id}/thumbnail · GET /documents/ref/{ref}/thumbnail

Scope read. The preview image of the first page. versionId as for content.

Request

curl -o preview.webp https://ddm.example.com/api/ext/v1/documents/dc8594e0-0ead-4049-aaee-2ef899bcf76f/thumbnail \
  -H "Authorization: Bearer $DDM_API_KEY"

Response · 200 OK – Headers of the answer – the body is the file itself:

HTTP/1.1 200 OK
cache-control: private, max-age=300, must-revalidate
content-length: 5052
content-type: image/webp
etag: "1730e7bb-2f98-4761-aa9b-964c521351b3"