Inhalte abrufen
Ein anderes System kann Inhalte aus DDM abrufen: eine Website mit den aktuellen Preislisten, ein Shop, der Datenblätter an Produkte hängt, ein Suchindex, ein Archiv. Es braucht nur einen Nur-Lesen-Schlüssel.
1. Einen Nur-Lesen-Schlüssel anlegen
Unter Einstellungen › API-Zugang einen Schlüssel nur mit Lesen anlegen. Wählen Sie, was er sieht:
- Nur freigegebene Inhalte ist richtig für alles Öffentliche. Er sieht, was Leser in der App sehen: nichts Archiviertes, und mit Verteilung erst nach Freigabe nichts Unfreigegebenes. Er kann nur Dateien herunterladen, die die App verlassen dürfen.
- Alles in Dokumente schließt Entwürfe ein, für ein internes Archiv oder eine Migration.
Lassen Sie ihn als eine Person handeln, die genau die Kategorien sieht, die das andere System bekommen soll.
2. Das erste vollständige Laden
Holen Sie die Kategorien, blättern Sie dann durch alle Dokumente und laden Sie die Dateien:
curl https://ddm.example.com/api/ext/v1/categories -H "Authorization: Bearer $DDM_API_KEY"
curl "https://ddm.example.com/api/ext/v1/documents?limit=500" -H "Authorization: Bearer $DDM_API_KEY"
curl -o Preisliste.pdf https://ddm.example.com/api/ext/v1/documents/8d0c1f5e-…/content -H "Authorization: Bearer $DDM_API_KEY"
Folgen Sie nextCursor, bis er null ist. Speichern Sie zu jedem Dokument id, updatedAt und currentVersion.checksum.
3. Jeder weitere Lauf: was sich geändert hat
Fragen Sie nur nach dem, was sich seit dem neuesten updatedAt geändert hat, das Sie haben:
curl "https://ddm.example.com/api/ext/v1/documents?updatedSince=2026-10-27T03:00:00Z&limit=500" \
-H "Authorization: Bearer $DDM_API_KEY"
Vergleichen Sie für jedes zurückgegebene Dokument currentVersion.checksum mit Ihrer. Laden Sie die Datei nur, wenn sie abweicht, und aktualisieren Sie die Angaben (Name, Titel, Schlagwörter, Kategorien) in jedem Fall.
4. Jeder weitere Lauf: was weg ist
Ein gelöschtes Dokument steht in keiner Liste, weil es nicht mehr existiert. Ebenso wenig eines, das aus der freigegebenen Sicht archiviert wurde oder dorthin verschoben, wo die Person des Schlüssels es nicht sieht. Um diese zu finden, holen Sie das Manifest:
curl https://ddm.example.com/api/ext/v1/sync -H "Authorization: Bearer $DDM_API_KEY"
Es listet jedes Dokument, das der Schlüssel sieht, mit wenigen Feldern. Löschen Sie in Ihrem System, was Sie haben und was nicht im Manifest steht – aber nur, wenn complete true ist. Über 50.000 Dokumenten wird das Manifest abgeschnitten, und dann kann es nicht sagen, was weg ist. Ein ausgearbeitetes Beispiel in vier Sprachen steht unter Gelöschte Dokumente finden.
Ein vollständiges Beispiel
Ein Abgleich-Skript in JavaScript (Node 20+). Es läuft so oft Sie möchten und hält seinen Stand in einer JSON-Datei:
import { readFile, writeFile, mkdir, rm } from 'node:fs/promises'
const BASE = 'https://ddm.example.com/api/ext/v1'
const headers = { Authorization: `Bearer ${process.env.DDM_API_KEY}` }
const STATE = './ddm-state.json'
const FILES = './files'
const state = JSON.parse(await readFile(STATE, 'utf8').catch(() => '{"since":null,"documents":{}}'))
await mkdir(FILES, { recursive: true })
async function get(path, params = {}) {
for (let attempt = 0; ; attempt++) {
const response = await fetch(`${BASE}${path}?${new URLSearchParams(params)}`, { headers })
if (response.ok) return response
if ((response.status === 429 || response.status >= 500) && attempt < 5) {
await new Promise(resolve => setTimeout(resolve, 1000 * (Number(response.headers.get('retry-after')) || 2 ** attempt)))
continue
}
throw new Error(`${response.status} ${path}: ${await response.text()}`)
}
}
// Was sich geändert hat – beim ersten Lauf alles.
let cursor
do {
const page = await (await get('/documents', {
limit: '500',
...(state.since ? { updatedSince: state.since } : {}),
...(cursor ? { cursor } : {})
})).json()
for (const document of page.data) {
const known = state.documents[document.id]
if (document.currentVersion && known?.checksum !== document.currentVersion.checksum) {
const file = await get(`/documents/${document.id}/content`)
await writeFile(`${FILES}/${document.id}`, Buffer.from(await file.arrayBuffer()))
}
state.documents[document.id] = { name: document.name, checksum: document.currentVersion?.checksum, titles: document.titles }
state.since = document.updatedAt
}
cursor = page.nextCursor
} while (cursor)
// Was weg ist.
const manifest = await (await get('/sync')).json()
if (manifest.complete) {
const present = new Set(manifest.documents.map(document => document.id))
for (const id of Object.keys(state.documents)) {
if (!present.has(id)) {
await rm(`${FILES}/${id}`, { force: true })
delete state.documents[id]
}
}
}
await writeFile(STATE, JSON.stringify(state, null, 2))
Tipps
- Titel pro Markt:
titlesenthält einen Titel pro Marktcode (GET /marketslistet sie). Zeigen Sietitles[code] ?? name. - Text für einen Suchindex:
GET /documents/{id}/textliefert den Text, den DDM aus der Datei gelesen hat. - Vorschaubilder:
GET /documents/{id}/thumbnailliefert das Vorschaubild der ersten Seite. - Nicht umsonst neu laden: Schicken Sie das letzte
ETagalsIf-None-Match; eine unveränderte Datei antwortet mit304. - Wie oft: alle paar Minuten ist in Ordnung. Jede Anfrage zählt gegen die 600 pro Minute des Schlüssels.