Kulturpool APIs

Die Kulturpool APIs ermöglichen den programmatischen Zugriff auf digitale Kultur- und Kunstsammlungen österreichischer Institutionen. Die interaktive OpenAPI-Dokumentation ist verfügbar unter: api.kulturpool.at/docs

Einstieg: Kulturpool APIs

Die Kulturpool APIs ermöglichen den programmatischen Zugriff auf digitale Kultur- und Kunstsammlungen österreichischer Institutionen. Sie bietet strukturierte Endpunkte für Institutionen, redaktionelle Inhalte und Assets mit umfangreichen Metadaten und mehrsprachiger Unterstützung.

APIs für Digitalisate

Suche

Die Suche API ermöglicht Volltext- und Facettensuche über die gesamte Kulturpool-Sammlung.

Objekt

Die Objekte API bietet direkten Zugriff auf die detaillierten Metadaten und Mediendateien einzelner Kulturgüter im Kulturpool.

OAI-PMH

OAI-PMH ist ein Standard-Protokoll für das Harvesting von Metadaten aus digitalen Archiven und Repositorien, das eine standardisierte Schnittstelle für die Übertragung von Metadaten zwischen verschiedenen Systemen bietet.

APIs für Redaktionelle Inhalte

Institutionen

Die Institutionen API bietet Zugriff auf Informationen über alle teilnehmenden Museen, Bibliotheken und Kultureinrichtungen im Kulturpool. Sie liefert strukturierte Daten mit Standortinformationen, Kontaktdaten und mehrsprachigen Beschreibungen.

Inhalte

Die Inhalte API ermöglicht den Zugriff auf redaktionelle Inhalte des Kulturpools. Sie liefert strukturierte Content-Seiten mit verschiedenen Block-Typen, SEO-Metadaten und mehrsprachigen Übersetzungen für die Website-Darstellung.

Assets

Die Assets API ermöglicht den Zugriff auf Bilder und andere Medien-Dateien mit dynamischen Transformationsparametern.


Authentifizierung

Die APIs sind öffentlich zugänglich und erfordert keine Authentifizierung. Alle Endpunkte sind öffentlich verfügbar.

Rate Limiting

Aktuell sind keine expliziten Rate Limits implementiert. Die API nutzt Caching zur Performance-Optimierung.


API-Dokumentation

Die interaktive OpenAPI-Dokumentation ist verfügbar unter:

Suche API

Der /search Endpunkt ermöglicht es, die gesamte Kulturpool-Sammlung über die integrierte Typesense-Suchmaschine zu durchsuchen. Die API leitet Anfragen automatisch an den Typesense-Server weiter und fügt den erforderlichen API-Schlüssel hinzu, sodass Nutzer ohne Authentifizierung suchen können.

Nähere Informationen zur Typesense-Suchmaschine finden Sie in der Typesense-Dokumentation.

Basis-URL

https://api.kulturpool.at/search

Parameter

Pflichtparameter

Optionale Parameter

Verfügbare Suchfelder

Hauptfelder für Volltextsuche

Weitere durchsuchbare Felder

Verfügbare Facetten

Institutionen und Anbieter

Objekttypen

Inhaltliche Kategorien

Rechtliche Informationen

Zeitangaben

Personen

Filterbeispiele

# Nur Objekte der Albertina
filter_by=dataProvider:=Albertina

# Nur Bilder
filter_by=edmType:=IMAGE

# Nur gemeinfreie Objekte
filter_by=edmRightsName:="Public Domain"

# Nach 1900 entstanden
filter_by=dateMin:>=-2208988800

# Kombinierte Filter (UND-Verknüpfung)
filter_by=dataProvider:=Albertina && edmType:=IMAGE

# ODER-Verknüpfung
filter_by=dataProvider:=[Albertina,Belvedere]

# Enthält-Filter
filter_by=creator:*Mozart*

Sortieroptionen

Beispielanfragen

Einfache Suche

GET /search/?q=Wien

Erweiterte Suche mit Filtern

GET /search/?q=Porträt&filter_by=dataProvider:=Albertina&sort_by=dateMin:asc

Suche mit Facetten

GET /search/?q=Landschaft&facet_by=creator,medium,dateMin&max_facet_values=20

Paginierte Suche

GET /search/?q=Fotografie&page=2&per_page=50

Antwortformat

Die API gibt eine JSON-Antwort im Typesense-Format zurück:

Struktur der Antwort

{
  "found": 1234,
  "hits": [
    {
      "document": {
        "id": "67f4fc8fbb263def5311bac4",
        "title": ["Wien. - Praterleben. Aussenseiter."],
        "creator": ["Emil Mayer", "Brüder Kohn Wien (Postkartenverlag)"],
        "dataProvider": "Albertina",
        "edmType": "IMAGE",
        "dcType": ["Fotografie"],
        "medium": ["Bromsilbergelatinepapier (Postkarte, Rotationsverfahren)"],
        "isShownAt": "https://sammlungenonline.albertina.at/...",
        "isShownBy": "https://sammlungenonline.albertina.at/...",
        "previewImage": "https://static.kulturpool.at/images/...",
        "edmRights": "http://creativecommons.org/publicdomain/mark/1.0/",
        "edmRightsName": "Public Domain",
        "edmRightsReusePolicy": "OPEN",
        "dateMin": -1893456000,
        "dateMax": -1862006400,
        // ... weitere Felder
      },
      "highlight": {
        "title": [
          {
            "matched_tokens": ["Wien"],
            "snippet": "<mark>Wien</mark>. - Praterleben. Aussenseiter.",
            "value": "<mark>Wien</mark>. - Praterleben. Aussenseiter."
          }
        ]
      },
      "text_match": 578730123365187700
    }
  ],
  "facet_counts": [
    {
      "field_name": "dataProvider",
      "counts": [
        {"count": 456, "highlighted": "Albertina", "value": "Albertina"},
        {"count": 234, "highlighted": "Belvedere", "value": "Belvedere"}
      ]
    }
  ],
  "search_time_ms": 12,
  "page": 1
}

Wichtige Felder in den Objektdaten

Anzeige und URLs

Verknüpfung zu Objektdetails

Metadaten

Zeitangaben

Klassifikation

Rechteinformationen

Sammlungskontext

Räumliche Angaben

Technische Daten

Tipps für effektive Suchen

  1. Kombination von Suchbegriffen: Nutzen Sie mehrere Begriffe für präzisere Ergebnisse
  2. Facetten nutzen: Verwenden Sie Facetten zur Eingrenzung großer Ergebnismengen
  3. Wildcards: * am Ende von Begriffen für Teilworttreffer
  4. Institutionen: Filtern Sie nach spezifischen Institutionen für fokussierte Suchen
  5. Zeiträume: Nutzen Sie dateMin/dateMax-Filter für chronologische Eingrenzung
  6. Nutzungsrecht: Filtern Sie nach Nutzungsrechten bei Verwendung der Objekte

Die Typesense-Suchmaschine bietet fuzzy matching und kann auch bei Tippfehlern relevante Ergebnisse liefern.

Objekt API

Die Objekte API bietet direkten Zugriff auf die detaillierten Metadaten und Mediendateien einzelner Kulturgüter im Kulturpool. Sie liefert strukturierte Daten im Europeana Data Model (EDM) als JSON-LD sowie eine aufbereitete Liste aller zugehörigen Medien.

Basis-URL

https://api.kulturpool.at/object

Endpunkte

Einzelnes Objekt abrufen

GET /object/

Ruft detaillierte Informationen zu einem spezifischen Objekt anhand seiner Kulturpool-ID ab.

Parameter

Parameter Typ Beschreibung Beispiel
id string Die Kulturpool-ID als eindeutige UUID des Originaldatensatzes b1eaac0f-69a1-4174-8ac6-90a61615d0ae

Beispiel-URL

https://api.kulturpool.at/object/?id=b1eaac0f-69a1-4174-8ac6-90a61615d0ae

Antwort

Die Antwort der API besteht aus zwei Hauptteilen: metadata und media.

{
  "metadata": {
    "@context": "https://api.kulturpool.at/ns/v1/edm.json",
    "id": "https://id.kulturpool.at/b1eaac0f-69a1-4174-8ac6-90a61615d0ae/aggregation",
    "type": "Aggregation",
    "provider": "Kulturpool",
    "dataProvider": "Wienbibliothek im Rathaus",
    "edmRights": "http://creativecommons.org/publicdomain/mark/1.0/",
    "isShownAt": "https://www.digital.wienbibliothek.at/id/475632",
    "isShownBy": {
      "id": "https://www.digital.wienbibliothek.at/download/webcache/1000/475634",
      "type": "WebResource",
      "hasService": {
        "id": "https://www.digital.wienbibliothek.at/i3f/v20/475634",
        "type": "Service",
        "conformsTo": [{ "id": "http://iiif.io/api/image" }],
        "implements": { "id": "http://iiif.io/api/image/2/level2.json" }
      },
      "isReferencedBy": [
        { "id": "https://www.digital.wienbibliothek.at/i3f/v20/475632/manifest" }
      ]
    },
    "hasView": [
      {
        "id": "https://www.digital.wienbibliothek.at/download/pdf/475632",
        "type": "WebResource"
      }
    ],
    "aggregatedCHO": {
      "id": "https://id.kulturpool.at/b1eaac0f-69a1-4174-8ac6-90a61615d0ae/cho",
      "type": "ProvidedCHO",
      "title": [
        "Neueste Nachrichten. Alpenländisches Morgenblatt mit Handels-Zeitung ... Nr. 207/ 2. Jahrgang/ 28. Juli 1915"
      ],
      "dcType": ["Plakat", "book", "poster"],
      "issued": ["1915"],
      "edmType": "TEXT",
      "spatial": ["Salzburg <Stadt>"],
      "language": ["ger"],
      "publisher": ["Neueste Nachrichten"],
      "identifier": ["urn:nbn:at:AT-WBR-22887"],
      "extent": ["1 Bogen, 48 x 32 cm"],
      "currentLocation": " ; P-226563 ; PS-A2-0003"
    }
  },
  "media": [
    {
      "url": "https://www.digital.wienbibliothek.at/i3f/v20/475632/manifest",
      "type": "iiif",
      "content_type": "application/json"
    },
    {
      "url": "https://www.digital.wienbibliothek.at/download/pdf/475632",
      "type": "pdf",
      "content_type": "application/pdf"
    }
  ]
}

Datenstruktur

Hauptobjekt

Feld Typ Beschreibung
metadata object Ein JSON-LD-Objekt mit den Metadaten gemäß dem Europeana Data Model.
media Media[] Ein Array von Media-Objekten, die alle zugehörigen Dateien repräsentieren.

Media

Feld Typ Beschreibung
url string Die direkte URL zur Mediendatei oder zum IIIF-Manifest.
type string Der Typ der Mediendatei. Mögliche Werte: iiif, image, video, audio, 3d, pdf, embed, other.
content_type string Der MIME-Typ der Ressource (z.B. application/json, image/jpeg).

Verbindung zur Suche API

In den Ergebnissen der Suche API finden Sie für jedes Objekt das Feld kp_id. Der Wert dieses Feldes ist die Kulturpool-ID, die zum Abrufen der detaillierten Informationen über die Objekte API verwendet werden kann.

Fehlerbehandlung

404 - Objekt nicht gefunden

Wird zurückgegeben, wenn keine passende Kulturpool-ID gefunden wurde.

{
  "detail": "Error fetching data from upstream API"
}

500 - Server-Fehler

Wird bei unerwarteten Fehlern auf dem Server zurückgegeben.

{
  "detail": "Error fetching data from upstream API"
}

Institutionen API

Die Institutionen API bietet Zugriff auf Informationen über alle teilnehmenden Museen, Bibliotheken und Kultureinrichtungen im Kulturpool. Sie liefert strukturierte Daten mit Standortinformationen, Kontaktdaten und mehrsprachigen Beschreibungen.

Basis-URL

https://api.kulturpool.at/institutions

Endpunkte

Alle Institutionen abrufen

GET /institutions

Ruft eine vollständige Liste aller registrierten Institutionen ab.

Antwort

{
  "data": [
    {
      "id": 42,
      "name": "Kulturinstitution Musterhausen",
      "intermediate_provider": null,
      "location": {
        "type": "MultiPoint",
        "coordinates": [[10.12345, 52.67890]]
      },
      "web_collection_url": "https://www.kultur-musterhausen.example",
      "website_url": "https://www.kultur-musterhausen.example",
      "favicon": {
        "id": "12345678-1234-5678-9abc-123456789abc"
      },
      "hero_image": {
        "id": "87654321-8765-4321-9def-987654321fed",
        "title": "Hauptgebäude der Kulturinstitution Musterhausen",
        "author": "Max Mustermann",
        "license": "CC BY-SA",
        "license_url": "https://creativecommons.org/licenses/by-sa/4.0/deed.de"
      },
      "logo": {
        "id": "11111111-2222-3333-4444-555555555555"
      },
      "translations": [
        {
          "place": "Musterhausen",
          "title_official": "Kulturinstitution Musterhausen (GmbH)",
          "title": "Kulturinstitution Musterhausen",
          "slug": "kulturinstitution-musterhausen",
          "summary": "Die Kulturinstitution Musterhausen sammelt und bewahrt bedeutende Werke der regionalen Kunst und Kultur.",
          "content": "<p>Die Kulturinstitution wurde 1950 gegründet und ist seitdem ein wichtiger Ort für Kunst und Kultur in der Region.</p>",
          "languages_code": "de"
        }
      ]
    }
  ]
}

Einzelne Institution abrufen

GET /institutions/{institution_id}

Ruft detaillierte Informationen zu einer spezifischen Institution ab.

Parameter

Parameter Typ Beschreibung
institution_id integer Die eindeutige ID der Institution (Pfad-Parameter)

Beispiel

curl -X GET "https://api.kulturpool.at/institutions/42"

Antwort

{
  "data": {
    "id": 42,
    "name": "Kulturinstitution Musterhausen",
    "intermediate_provider": null,
    "location": {
      "type": "MultiPoint",
      "coordinates": [[10.12345, 52.67890]]
    },
    "web_collection_url": "https://www.kultur-musterhausen.example",
    "website_url": "https://www.kultur-musterhausen.example",
    "favicon": {
      "id": "12345678-1234-5678-9abc-123456789abc"
    },
    "hero_image": {
      "id": "87654321-8765-4321-9def-987654321fed",
      "title": "Hauptgebäude der Kulturinstitution Musterhausen",
      "author": "Max Mustermann",
      "license": "CC BY-SA",
      "license_url": "https://creativecommons.org/licenses/by-sa/4.0/deed.de"
    },
    "logo": {
      "id": "11111111-2222-3333-4444-555555555555"
    },
    "translations": [
      {
        "place": "Musterhausen",
        "title_official": "Kulturinstitution Musterhausen (GmbH)",
        "title": "Kulturinstitution Musterhausen",
        "slug": "kulturinstitution-musterhausen",
        "summary": "Die Kulturinstitution Musterhausen sammelt und bewahrt bedeutende Werke der regionalen Kunst und Kultur.",
        "content": "<p>Die Kulturinstitution wurde 1950 gegründet und ist seitdem ein wichtiger Ort für Kunst und Kultur in der Region.</p>",
        "languages_code": "de"
      }
    ]
  }
}

Datenstruktur

Institution

Feld Typ Beschreibung
id integer Eindeutige ID der Institution
name string Offizieller Name der Institution
intermediate_provider string/null Zwischenanbieter (falls vorhanden)
location Location Geografische Koordinaten
web_collection_url string URL zur digitalen Sammlung
website_url string Offizielle Website
favicon File Favicon der Institution
hero_image HeroImage Hauptbild mit Metadaten
logo File Logo der Institution
translations Translation[] Mehrsprachige Beschreibungen

Location

Feld Typ Beschreibung
type string GeoJSON-Typ (meist "MultiPoint")
coordinates number[][] Array von Koordinaten-Paaren [Längengrad, Breitengrad]

HeroImage

Feld Typ Beschreibung
id string Asset-ID des Bildes
title string Bildtitel
author string Fotograf/Künstler
license string Lizenztyp (z.B. "CC BY-SA")
license_url string URL zur vollständigen Lizenz

Translation

Feld Typ Beschreibung
place string Ortsname
title_official string Offizieller Titel mit Rechtsform
title string Anzeigename
slug string URL-freundlicher Bezeichner
summary string Kurzbeschreibung
content string Ausführliche Beschreibung (HTML)
languages_code string Sprachcode (ISO 639-1)

File

Feld Typ Beschreibung
id string UUID des Assets im CMS

Beispiel-Code

JavaScript/Fetch

// Alle Institutionen abrufen
const response = await fetch('https://api.kulturpool.at/institutions');
const { data: institutions } = await response.json();

// Einzelne Institution abrufen
const institutionResponse = await fetch('https://api.kulturpool.at/institutions/42');
const { data: institution } = await institutionResponse.json();

console.log(`Institution: ${institution.name}`);
console.log(`Ort: ${institution.translations[0]?.place}`);

Python/requests

import requests

# Alle Institutionen abrufen
response = requests.get('https://api.kulturpool.at/institutions')
institutions = response.json()['data']

# Einzelne Institution abrufen
institution_response = requests.get('https://api.kulturpool.at/institutions/42')
institution = institution_response.json()['data']

print(f"Institution: {institution['name']}")
print(f"Ort: {institution['translations'][0]['place'] if institution['translations'] else 'N/A'}")

cURL

# Alle Institutionen abrufen
curl -X GET "https://api.kulturpool.at/institutions" \
  -H "Accept: application/json"

# Einzelne Institution abrufen
curl -X GET "https://api.kulturpool.at/institutions/42" \
  -H "Accept: application/json"

Anwendungsfälle

Institutionen-Verzeichnis erstellen

async function createInstitutionDirectory() {
  const response = await fetch('https://api.kulturpool.at/institutions');
  const { data: institutions } = await response.json();

  const directory = institutions.map(institution => ({
    id: institution.id,
    name: institution.name,
    place: institution.translations[0]?.place,
    website: institution.website_url,
    collection: institution.web_collection_url
  }));

  return directory;
}

Karte mit Institutionen

async function getInstitutionLocations() {
  const response = await fetch('https://api.kulturpool.at/institutions');
  const { data: institutions } = await response.json();

  return institutions
    .filter(institution => institution.location)
    .map(institution => ({
      id: institution.id,
      name: institution.name,
      coordinates: institution.location.coordinates[0], // [lng, lat]
      title: institution.translations[0]?.title
    }));
}

Institution mit Assets

async function getInstitutionWithImages(institutionId) {
  const response = await fetch(`https://api.kulturpool.at/institutions/${institutionId}`);
  const { data: institution } = await response.json();

  const enriched = {
    ...institution,
    faviconUrl: institution.favicon ?
      `https://api.kulturpool.at/assets/${institution.favicon.id}?format=png&width=32&height=32` : null,
    logoUrl: institution.logo ?
      `https://api.kulturpool.at/assets/${institution.logo.id}?format=png&width=200&height=100&fit=contain` : null,
    heroImageUrl: institution.hero_image ?
      `https://api.kulturpool.at/assets/${institution.hero_image.id}?format=webp&width=1200&height=400&fit=cover` : null
  };

  return enriched;
}

Fehlerbehandlung

404 - Institution nicht gefunden

{
  "detail": "Error fetching data from upstream API"
}

500 - Server-Fehler

{
  "detail": "Error fetching data from upstream API"
}

Inhalte API

Die Content API ermöglicht den Zugriff auf redaktionelle Inhalte des Kulturpools. Sie liefert strukturierte Content-Seiten mit verschiedenen Block-Typen, SEO-Metadaten und mehrsprachigen Übersetzungen für die Website-Darstellung.

Basis-URL

https://api.kulturpool.at/content

Endpunkte

Alle Inhalte abrufen

GET /content

Ruft alle verfügbaren redaktionellen Inhalte vom CMS ab.

Antwort

{
  "data": [
    {
      "id": 1,
      "status": "published",
      "sort": 1,
      "date_published": "2024-01-15T09:00:00Z",
      "color_text": "#333333",
      "color_background": "#ffffff",
      "seo": {
        "id": 1,
        "title": "Willkommen im Kulturpool - Digitale Kunst entdecken",
        "meta_description": "Entdecken Sie die Vielfalt österreichischer Kultur im digitalen Raum",
        "canonical_url": "https://kulturpool.at/willkommen"
      },
      "category": {
        "id": 1,
        "sort": 1,
        "translations": []
      },
      "translations": [
        {
          "id": 1,
          "languages_code": "de",
          "title": "Willkommen im Kulturpool",
          "slug": "willkommen",
          "summary": "Entdecken Sie die Vielfalt österreichischer Kultur",
          "items": [
            {
              "id": 1,
              "collection": "block_text",
              "item": {
                "id": 1,
                "type": "hero",
                "heading": "Willkommen im Kulturpool",
                "body": "<p>Hier finden Sie digitalisierte Kunst und Kultur aus österreichischen Institutionen.</p>",
                "heading_tag": "h1",
                "is_enabled": true
              }
            }
          ]
        }
      ]
    }
  ]
}

Einzelnen Content-Eintrag abrufen

GET /content/{content_id}

Ruft einen spezifischen Content-Eintrag anhand seiner ID ab.

Parameter

Parameter Typ Beschreibung
content_id integer Die eindeutige ID des Content-Eintrags (Pfad-Parameter)

Beispiel

curl -X GET "https://api.kulturpool.at/content/1"

Antwort

{
  "data": {
    "id": 1,
    "status": "published",
    "sort": 1,
    "date_published": "2024-01-15T09:00:00Z",
    "color_text": "#333333",
    "color_background": "#ffffff",
    "seo": {
      "id": 1,
      "title": "Willkommen im Kulturpool - Digitale Kunst entdecken",
      "meta_description": "Entdecken Sie die Vielfalt österreichischer Kultur im digitalen Raum",
      "canonical_url": "https://kulturpool.at/willkommen"
    },
    "category": {
      "id": 1,
      "sort": 1,
      "translations": []
    },
    "translations": [
      {
        "id": 1,
        "languages_code": "de",
        "title": "Willkommen im Kulturpool",
        "slug": "willkommen",
        "summary": "Entdecken Sie die Vielfalt österreichischer Kultur",
        "items": [
          {
            "id": 1,
            "collection": "block_text",
            "item": {
              "id": 1,
              "type": "hero",
              "heading": "Willkommen im Kulturpool",
              "body": "<p>Hier finden Sie digitalisierte Kunst und Kultur aus österreichischen Institutionen.</p>",
              "heading_tag": "h1",
              "is_enabled": true
            }
          }
        ]
      }
    ]
  }
}

Datenstruktur

Content

Feld Typ Beschreibung
id integer Eindeutige ID des Content-Eintrags
status string Veröffentlichungsstatus ("published", "draft")
sort integer Sortierreihenfolge
date_published string Veröffentlichungsdatum (ISO 8601)
color_text string Textfarbe (Hex-Code)
color_background string Hintergrundfarbe (Hex-Code)
seo SEO SEO-Metadaten
category ContentCategory Zugeordnete Kategorie
translations ContentTranslation[] Mehrsprachige Versionen

SEO

Feld Typ Beschreibung
id integer SEO-Eintrag ID
title string Meta-Titel für Suchmaschinen
meta_description string Meta-Beschreibung
canonical_url string Kanonische URL
no_index boolean Suchmaschinenindexierung verhindern
no_follow boolean Link-Verfolgung verhindern
og_image File Open Graph Bild

ContentTranslation

Feld Typ Beschreibung
id integer Übersetzungs-ID
languages_code string Sprachcode (ISO 639-1)
title string Seitentitel
slug string URL-Slug
summary string Kurzzusammenfassung
items ContentTranslationsItem[] Content-Blöcke

ContentTranslationsItem

Feld Typ Beschreibung
id integer Item-ID
collection string Block-Typ ("block_text", "block_slider", etc.)
item ContentItem Der eigentliche Content-Block
sort integer Sortierreihenfolge

Content-Block-Typen

BlockText

Textblöcke für Überschriften, Fließtext und Hero-Bereiche.

Feld Typ Beschreibung
id integer Block-ID
type string Block-Untertyp ("hero", "text", "quote")
heading string Überschrift
body string Haupttext (HTML)
summary string Zusammenfassung
heading_tag string HTML-Tag für Überschrift ("h1", "h2", etc.)
heading_size string Überschriftsgröße
is_enabled boolean Block ist aktiv

BlockSlider

Bildergalerien und Slider-Komponenten.

Feld Typ Beschreibung
id integer Block-ID
type string Slider-Typ
aspect_ratio string Seitenverhältnis (z.B. "16:9")
row_mode boolean Reihen-Modus aktiviert
pick_items integer Anzahl anzuzeigender Items
randomize boolean Zufällige Reihenfolge
items object Slider-Inhalte

Linksammlungen und Navigationsblöcke.

Feld Typ Beschreibung
id integer Block-ID
heading string Block-Überschrift
type string Link-Block-Typ
summary string Beschreibung
item object Link-Daten

BlockEmbed

Eingebettete Inhalte wie Videos oder externe Widgets.

Feld Typ Beschreibung
id integer Block-ID
type string Embed-Typ
link string URL des eingebetteten Inhalts
code string Embed-Code
aspect_ratio string Seitenverhältnis
max_width integer Maximale Breite in Pixeln
file File Eingebettete Datei

BlockList

Listen-Darstellungen für Sammlungen und Aufzählungen.

Feld Typ Beschreibung
id integer Block-ID
type string Listen-Typ
heading string Listen-Überschrift
summary string Listen-Beschreibung
collection string Quell-Collection
mode string Darstellungsmodus
pick_items integer Anzahl Items
show_filter boolean Filter anzeigen
row_mode boolean Reihen-Layout
randomize boolean Zufällige Sortierung
items object[] Listen-Items

Beispiel-Code

JavaScript/Fetch

// Alle Inhalte abrufen
const response = await fetch('https://api.kulturpool.at/content');
const { data: contentPages } = await response.json();

// Einzelne Seite abrufen
const pageResponse = await fetch('https://api.kulturpool.at/content/1');
const { data: page } = await pageResponse.json();

// Deutsche Übersetzung extrahieren
const germanTranslation = page.translations.find(t => t.languages_code === 'de');
console.log(`Titel: ${germanTranslation.title}`);
console.log(`Slug: ${germanTranslation.slug}`);

Python/requests

import requests

# Alle Inhalte abrufen
response = requests.get('https://api.kulturpool.at/content')
content_pages = response.json()['data']

# Einzelne Seite abrufen
page_response = requests.get('https://api.kulturpool.at/content/1')
page = page_response.json()['data']

# Deutsche Übersetzung finden
german_translation = next(
    (t for t in page['translations'] if t['languages_code'] == 'de'),
    None
)

if german_translation:
    print(f"Titel: {german_translation['title']}")
    print(f"Slug: {german_translation['slug']}")

Content-Blöcke verarbeiten

function processContentBlocks(translation) {
  return translation.items.map(item => {
    const { collection, item: block } = item;

    switch (collection) {
      case 'block_text':
        return {
          type: 'text',
          heading: block.heading,
          body: block.body,
          tag: block.heading_tag || 'h2'
        };

      case 'block_slider':
        return {
          type: 'slider',
          aspectRatio: block.aspect_ratio,
          items: block.items || []
        };

      case 'block_embed':
        return {
          type: 'embed',
          url: block.link,
          code: block.code,
          maxWidth: block.max_width
        };

      default:
        return { type: 'unknown', data: block };
    }
  });
}

Anwendungsfälle

Dynamische Website-Seiten

async function renderContentPage(slug) {
  // Alle Seiten abrufen und nach Slug filtern
  const response = await fetch('https://api.kulturpool.at/content');
  const { data: pages } = await response.json();

  const page = pages.find(page =>
    page.translations.some(t => t.slug === slug)
  );

  if (!page) {
    throw new Error(`Seite mit Slug "${slug}" nicht gefunden`);
  }

  const translation = page.translations.find(t => t.languages_code === 'de');

  return {
    title: translation.title,
    seoTitle: page.seo?.title || translation.title,
    metaDescription: page.seo?.meta_description || translation.summary,
    canonicalUrl: page.seo?.canonical_url,
    blocks: processContentBlocks(translation),
    theme: {
      textColor: page.color_text,
      backgroundColor: page.color_background
    }
  };
}

SEO-Metadaten extrahieren

function extractSEOMetadata(page, language = 'de') {
  const translation = page.translations.find(t => t.languages_code === language);

  return {
    title: page.seo?.title || translation?.title,
    description: page.seo?.meta_description || translation?.summary,
    canonical: page.seo?.canonical_url,
    noIndex: page.seo?.no_index || false,
    noFollow: page.seo?.no_follow || false,
    ogImage: page.seo?.og_image?.id ?
      `https://api.kulturpool.at/assets/${page.seo.og_image.id}?format=jpg&width=1200&height=630&fit=cover` : null
  };
}

Content-Management für Headless CMS

class ContentManager {
  constructor(baseUrl = 'https://api.kulturpool.at') {
    this.baseUrl = baseUrl;
    this.cache = new Map();
  }

  async getPage(id) {
    if (this.cache.has(id)) {
      return this.cache.get(id);
    }

    const response = await fetch(`${this.baseUrl}/content/${id}`);
    const { data: page } = await response.json();

    this.cache.set(id, page);
    return page;
  }

  async getPageBySlug(slug, language = 'de') {
    const response = await fetch(`${this.baseUrl}/content`);
    const { data: pages } = await response.json();

    return pages.find(page =>
      page.translations.some(t =>
        t.slug === slug && t.languages_code === language
      )
    );
  }

  getBlocks(page, language = 'de') {
    const translation = page.translations.find(t => t.languages_code === language);
    return translation?.items || [];
  }

  getActiveBlocks(page, language = 'de') {
    return this.getBlocks(page, language)
      .filter(item => item.item.is_enabled !== false)
      .sort((a, b) => (a.sort || 0) - (b.sort || 0));
  }
}

Mehrsprachige Navigation

async function buildNavigation() {
  const response = await fetch('https://api.kulturpool.at/content');
  const { data: pages } = await response.json();

  const navigation = {};

  pages.forEach(page => {
    page.translations.forEach(translation => {
      const { languages_code, title, slug } = translation;

      if (!navigation[languages_code]) {
        navigation[languages_code] = [];
      }

      navigation[languages_code].push({
        title,
        slug,
        url: `/${languages_code}/${slug}`,
        sort: page.sort || 999
      });
    });
  });

  // Sortieren nach sort-Wert
  Object.keys(navigation).forEach(lang => {
    navigation[lang].sort((a, b) => a.sort - b.sort);
  });

  return navigation;
}

Fehlerbehandlung

404 - Content nicht gefunden

{
  "detail": "Content not found"
}

500 - Validierungsfehler

{
  "detail": "Response validation error for content 1: ..."
}

Assets API

Die Assets API ermöglicht den Zugriff auf Bilder und andere Medien-Dateien mit dynamischen Transformationsparametern. Sie bietet optimierte Bilddelivery mit Format-Konvertierung, Größenanpassung und verschiedenen Anpassungsoptionen.

Basis-URL

https://api.kulturpool.at/assets

Endpunkt

Asset abrufen

GET /assets/{asset_id}

Ruft ein Asset vom CMS ab und wendet die angegebenen Transformationsparameter an.

Parameter

Parameter Typ Beschreibung Beispiel
asset_id string Asset-ID (UUID) aus dem CMS 8e1cf6a9-d1d6-4090-9a36-303f1f57a016
width integer Breite in Pixeln 1500
height integer Höhe in Pixeln 700
quality integer Bildqualität (1-100) 80
withoutEnlargement boolean Automatische Vergrößerung deaktivieren true
format string Ausgabeformat webp, jpg, png, avif, tiff, auto
fit string Anpassungsmodus cover, contain, inside, outside

Beispiele

# Einfacher Asset-Abruf
curl "https://api.kulturpool.at/assets/8e1cf6a9-d1d6-4090-9a36-303f1f57a016"

# Optimiertes Thumbnail
curl "https://api.kulturpool.at/assets/8e1cf6a9-d1d6-4090-9a36-303f1f57a016?format=webp&width=300&height=200&fit=cover&quality=85"

# Hero-Image für moderne Browser
curl "https://api.kulturpool.at/assets/8e1cf6a9-d1d6-4090-9a36-303f1f57a016?format=avif&width=1920&height=800&fit=cover&withoutEnlargement=true"

Parameter im Detail

Format-Optionen

Format Beschreibung Verwendung
auto Automatische Format-Auswahl (Standard) Versucht WebP/AVIF für moderne Browser, sonst JPEG
webp WebP-Format Gute Kompression, breite Browser-Unterstützung
avif AVIF-Format Beste Kompression, neuere Browser
jpg JPEG-Format Universelle Kompatibilität
png PNG-Format Für Transparenz und verlustfreie Kompression
tiff TIFF-Format Hochqualitative Archivierung

Anpassungsmodi (fit)

Modus Beschreibung Verwendung
cover Bild vollständig in Dimensionen einpassen (Standard) Hero-Images, Thumbnails
contain Bild mit Letterboxing in Dimensionen einpassen Logos, vollständige Bilder
inside So groß wie möglich innerhalb der Dimensionen Responsive Bilder
outside So klein wie möglich innerhalb/außerhalb der Dimensionen Spezielle Layouts

Qualitätseinstellungen

Qualität Beschreibung Dateigröße Verwendung
95-100 Höchste Qualität Sehr groß Druckvorbereitung
85-95 Hohe Qualität Groß Hero-Images
75-85 Gute Qualität Mittel Standard-Bilder
60-75 Moderate Qualität Klein Thumbnails
40-60 Niedrige Qualität Sehr klein Vorschaubilder

Antwort

Die API gibt eine HTTP 302 Redirect zum optimierten Asset im CMS zurück:

HTTP/1.1 302 Found
Location: https://cms.kulturpool.at/assets/8e1cf6a9-d1d6-4090-9a36-303f1f57a016/?format=webp&width=1500&height=700&fit=cover
Content-Type: application/json

Beispiel-Code

Responsive Bilder in HTML

<picture>
  <source
    srcset="https://api.kulturpool.at/assets/8e1cf6a9-d1d6-4090-9a36-303f1f57a016?format=avif&width=1920&height=800&fit=cover"
    type="image/avif"
    media="(min-width: 1200px)">
  <source
    srcset="https://api.kulturpool.at/assets/8e1cf6a9-d1d6-4090-9a36-303f1f57a016?format=webp&width=1200&height=600&fit=cover"
    type="image/webp"
    media="(min-width: 768px)">
  <source
    srcset="https://api.kulturpool.at/assets/8e1cf6a9-d1d6-4090-9a36-303f1f57a016?format=webp&width=800&height=400&fit=cover"
    type="image/webp">
  <img
    src="https://api.kulturpool.at/assets/8e1cf6a9-d1d6-4090-9a36-303f1f57a016?format=jpg&width=800&height=400&fit=cover"
    alt="Beschreibung"
    loading="lazy">
</picture>

JavaScript Asset-URL Generator

class AssetUrlBuilder {
  constructor(baseUrl = 'https://api.kulturpool.at/assets') {
    this.baseUrl = baseUrl;
  }

  build(assetId, options = {}) {
    const {
      width,
      height,
      quality = 85,
      format = 'auto',
      fit = 'cover',
      withoutEnlargement = false
    } = options;

    const params = new URLSearchParams();

    if (width) params.set('width', width);
    if (height) params.set('height', height);
    if (quality !== 85) params.set('quality', quality);
    if (format !== 'auto') params.set('format', format);
    if (fit !== 'cover') params.set('fit', fit);
    if (withoutEnlargement) params.set('withoutEnlargement', 'true');

    const queryString = params.toString();
    return `${this.baseUrl}/${assetId}${queryString ? `?${queryString}` : ''}`;
  }

  // Vordefinierte Größen
  thumbnail(assetId, size = 150) {
    return this.build(assetId, {
      width: size,
      height: size,
      format: 'webp',
      quality: 80
    });
  }

  hero(assetId, width = 1920, height = 800) {
    return this.build(assetId, {
      width,
      height,
      format: 'webp',
      quality: 85,
      fit: 'cover'
    });
  }

  logo(assetId, maxWidth = 200) {
    return this.build(assetId, {
      width: maxWidth,
      format: 'png',
      fit: 'contain',
      withoutEnlargement: true
    });
  }
}

// Verwendung
const assetBuilder = new AssetUrlBuilder();
const thumbnailUrl = assetBuilder.thumbnail('8e1cf6a9-d1d6-4090-9a36-303f1f57a016');
const heroUrl = assetBuilder.hero('8e1cf6a9-d1d6-4090-9a36-303f1f57a016', 1500, 600);

Python Asset-Manager

from urllib.parse import urlencode

class AssetManager:
    def __init__(self, base_url='https://api.kulturpool.at/assets'):
        self.base_url = base_url

    def build_url(self, asset_id, **kwargs):
        """Asset-URL mit Parametern erstellen"""
        params = {k: v for k, v in kwargs.items() if v is not None}

        # Boolean-Werte in Strings konvertieren
        for key, value in params.items():
            if isinstance(value, bool):
                params[key] = str(value).lower()

        url = f"{self.base_url}/{asset_id}"
        if params:
            url += f"?{urlencode(params)}"

        return url

    def get_responsive_urls(self, asset_id, format_type='webp'):
        """Responsive Bild-URLs für verschiedene Bildschirmgrößen"""
        return {
            'mobile': self.build_url(asset_id, width=480, height=320, format=format_type, fit='cover'),
            'tablet': self.build_url(asset_id, width=768, height=512, format=format_type, fit='cover'),
            'desktop': self.build_url(asset_id, width=1200, height=800, format=format_type, fit='cover'),
            'large': self.build_url(asset_id, width=1920, height=1080, format=format_type, fit='cover')
        }

    def get_optimized_thumbnail(self, asset_id, size=300):
        """Optimiertes Thumbnail"""
        return self.build_url(
            asset_id,
            width=size,
            height=size,
            format='webp',
            quality=80,
            fit='cover'
        )

# Verwendung
asset_manager = AssetManager()
asset_id = '8e1cf6a9-d1d6-4090-9a36-303f1f57a016'

# Responsive URLs
responsive_urls = asset_manager.get_responsive_urls(asset_id)
print(f"Mobile: {responsive_urls['mobile']}")

# Thumbnail
thumbnail_url = asset_manager.get_optimized_thumbnail(asset_id, 150)
print(f"Thumbnail: {thumbnail_url}")

Anwendungsfälle

Content Management System Integration

// Asset-URLs für Institution Hero-Images generieren
async function getInstitutionWithOptimizedImages(institutionId) {
  const response = await fetch(`https://api.kulturpool.at/institutions/${institutionId}`);
  const { data: institution } = await response.json();

  const assetBuilder = new AssetUrlBuilder();

  return {
    ...institution,
    optimizedImages: {
      favicon: institution.favicon?.id ?
        assetBuilder.build(institution.favicon.id, {
          width: 32,
          height: 32,
          format: 'png'
        }) : null,
      logo: institution.logo?.id ?
        assetBuilder.logo(institution.logo.id, 200) : null,
      hero: institution.hero_image?.id ?
        assetBuilder.hero(institution.hero_image.id) : null,
      heroMobile: institution.hero_image?.id ?
        assetBuilder.build(institution.hero_image.id, {
          width: 768,
          height: 400,
          format: 'webp',
          fit: 'cover'
        }) : null
    }
  };
}

Bildergalerie mit Lazy Loading

class ImageGallery {
  constructor(containerId) {
    this.container = document.getElementById(containerId);
    this.assetBuilder = new AssetUrlBuilder();
    this.observer = new IntersectionObserver(this.handleIntersection.bind(this));
  }

  addImage(assetId, alt = '') {
    const imageContainer = document.createElement('div');
    imageContainer.className = 'gallery-item';
    imageContainer.dataset.assetId = assetId;
    imageContainer.dataset.alt = alt;

    // Placeholder
    const placeholder = document.createElement('div');
    placeholder.className = 'image-placeholder';
    placeholder.style.backgroundColor = '#f0f0f0';
    placeholder.style.aspectRatio = '16/9';

    imageContainer.appendChild(placeholder);
    this.container.appendChild(imageContainer);

    // Für Lazy Loading beobachten
    this.observer.observe(imageContainer);
  }

  handleIntersection(entries) {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        this.loadImage(entry.target);
        this.observer.unobserve(entry.target);
      }
    });
  }

  loadImage(container) {
    const assetId = container.dataset.assetId;
    const alt = container.dataset.alt;

    const picture = document.createElement('picture');

    // WebP für moderne Browser
    const sourceWebP = document.createElement('source');
    sourceWebP.srcset = this.assetBuilder.build(assetId, {
      width: 800,
      height: 450,
      format: 'webp',
      fit: 'cover'
    });
    sourceWebP.type = 'image/webp';

    // JPEG Fallback
    const img = document.createElement('img');
    img.src = this.assetBuilder.build(assetId, {
      width: 800,
      height: 450,
      format: 'jpg',
      fit: 'cover'
    });
    img.alt = alt;
    img.loading = 'lazy';

    picture.appendChild(sourceWebP);
    picture.appendChild(img);

    container.innerHTML = '';
    container.appendChild(picture);
  }
}

CDN-Integration und Caching

class CachedAssetManager {
  constructor() {
    this.assetBuilder = new AssetUrlBuilder();
    this.cache = new Map();
    this.cacheTimeout = 5 * 60 * 1000; // 5 Minuten
  }

  async preloadAsset(assetId, options = {}) {
    const url = this.assetBuilder.build(assetId, options);
    const cacheKey = `${assetId}_${JSON.stringify(options)}`;

    if (this.cache.has(cacheKey)) {
      const cached = this.cache.get(cacheKey);
      if (Date.now() - cached.timestamp < this.cacheTimeout) {
        return cached.blob;
      }
    }

    try {
      const response = await fetch(url);
      const blob = await response.blob();

      this.cache.set(cacheKey, {
        blob,
        timestamp: Date.now()
      });

      return blob;
    } catch (error) {
      console.error(`Fehler beim Laden von Asset ${assetId}:`, error);
      return null;
    }
  }

  createObjectUrl(assetId, options = {}) {
    const cacheKey = `${assetId}_${JSON.stringify(options)}`;
    const cached = this.cache.get(cacheKey);

    if (cached?.blob) {
      return URL.createObjectURL(cached.blob);
    }

    // Fallback: Direkte URL zurückgeben
    return this.assetBuilder.build(assetId, options);
  }

  // Cache aufräumen
  clearExpiredCache() {
    const now = Date.now();
    for (const [key, value] of this.cache.entries()) {
      if (now - value.timestamp >= this.cacheTimeout) {
        this.cache.delete(key);
      }
    }
  }
}

SEO-optimierte Asset-Integration

function generateSEOOptimizedAssetUrls(assetId, title = '') {
  const assetBuilder = new AssetUrlBuilder();

  return {
    // Open Graph Image
    ogImage: assetBuilder.build(assetId, {
      width: 1200,
      height: 630,
      format: 'jpg',
      fit: 'cover',
      quality: 85
    }),

    // Twitter Card Image
    twitterImage: assetBuilder.build(assetId, {
      width: 1024,
      height: 512,
      format: 'jpg',
      fit: 'cover',
      quality: 85
    }),

    // JSON-LD Structured Data Image
    structuredDataImage: assetBuilder.build(assetId, {
      width: 1200,
      height: 800,
      format: 'jpg',
      fit: 'cover',
      quality: 90
    }),

    // Apple Touch Icon
    appleTouchIcon: assetBuilder.build(assetId, {
      width: 180,
      height: 180,
      format: 'png',
      fit: 'cover'
    })
  };
}

Performance-Optimierung

Bildformate nach Browser-Unterstützung

function getBestSupportedFormat() {
  // Feature Detection für moderne Bildformate
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');

  // AVIF Support
  if (canvas.toDataURL('image/avif').indexOf('data:image/avif') === 0) {
    return 'avif';
  }

  // WebP Support
  if (canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0) {
    return 'webp';
  }

  return 'jpg'; // Fallback
}

// Automatische Format-Auswahl
const optimalFormat = getBestSupportedFormat();
const optimizedUrl = assetBuilder.build(assetId, {
  width: 800,
  height: 600,
  format: optimalFormat
});

Batch-Preloading für bessere Performance

async function preloadAssetBatch(assetIds, options = {}) {
  const promises = assetIds.map(async (assetId) => {
    const link = document.createElement('link');
    link.rel = 'preload';
    link.as = 'image';
    link.href = assetBuilder.build(assetId, options);

    document.head.appendChild(link);

    return new Promise((resolve) => {
      link.onload = resolve;
      link.onerror = resolve; // Auch bei Fehlern fortfahren
    });
  });

  await Promise.allSettled(promises);
}

// Verwendung für kritische Bilder
const criticalAssets = ['asset-1', 'asset-2', 'asset-3'];
await preloadAssetBatch(criticalAssets, {
  width: 1200,
  height: 600,
  format: 'webp'
});

Fehlerbehandlung

404 - Asset nicht gefunden

{
  "detail": "Asset mit ID 'invalid-id' wurde nicht gefunden"
}

500 - CMS-Fehler

{
  "detail": "Fehler beim Abrufen des Assets vom CMS"
}

Fehlerbehandlung im Frontend

function createAssetWithFallback(assetId, options = {}, fallbackSrc = '/placeholder.jpg') {
  const img = new Image();
  const primaryUrl = assetBuilder.build(assetId, options);

  img.onerror = () => {
    img.src = fallbackSrc;
  };

  img.src = primaryUrl;
  return img;
}

OAI-PMH

Der /oai Endpunkt stellt einen OAI-PMH (Open Archives Initiative Protocol for Metadata Harvesting) Server zur Verfügung, der einen Großteil der Digitalisate aus dem Kulturpool bereitstellt.

OAI-PMH ist ein Standard-Protokoll für das Harvesting von Metadaten aus digitalen Archiven und Repositorien, das eine standardisierte Schnittstelle für die Übertragung von Metadaten zwischen verschiedenen Systemen bietet.

Basis-URL

https://api.kulturpool.at/oai

OAI-PMH Verben

Das OAI-PMH Protokoll unterstützt sechs Standard-Verben (Befehle):

Identify

Gibt grundlegende Informationen über das Repository zurück.

Parameter:

Beispiel:

GET /oai?verb=Identify

ListMetadataFormats

Listet alle verfügbaren Metadatenformate auf.

Parameter:

Beispiel:

GET /oai?verb=ListMetadataFormats

ListSets

Listet alle verfügbaren Sets (Sammlungen) auf.

Parameter:

Beispiel:

GET /oai?verb=ListSets

ListIdentifiers

Listet die Identifikatoren aller verfügbaren Datensätze auf.

Parameter:

Beispiel:

GET /oai?verb=ListIdentifiers&metadataPrefix=edm&set=kulturpool-europeana:wien-bibliothek

ListRecords

Ruft die Metadaten aller verfügbaren Datensätze ab.

Parameter:

Beispiel:

GET /oai?verb=ListRecords&metadataPrefix=edm&set=kulturpool-europeana:wien-bibliothek

GetRecord

Ruft einen einzelnen Datensatz ab.

Parameter:

Beispiel:

GET /oai?verb=GetRecord&metadataPrefix=edm&identifier=https://id.kulturpool.at/b1eaac0f-69a1-4174-8ac6-90a61615d0ae

Verfügbare Metadatenformate

EDM (Europeana Data Model)

Beispielanfragen

Repository-Informationen abrufen

GET /oai?verb=Identify

Alle verfügbaren Sets anzeigen

GET /oai?verb=ListSets

Identifikatoren aus der Wienbibliothek

GET /oai?verb=ListIdentifiers&metadataPrefix=edm&set=kulturpool-europeana:wien-bibliothek

Vollständige Datensätze aus der Wienbibliothek

GET /oai?verb=ListRecords&metadataPrefix=edm&set=kulturpool-europeana:wien-bibliothek

Spezifischen Datensatz abrufen

GET /oai?verb=GetRecord&metadataPrefix=edm&identifier=https://id.kulturpool.at/b1eaac0f-69a1-4174-8ac6-90a61615d0ae

Datensätze aus einem bestimmten Zeitraum

GET /oai?verb=ListRecords&metadataPrefix=edm&from=2024-01-01&until=2024-12-31

Antwortformat

Alle OAI-PMH Antworten sind im XML-Format strukturiert:

Erfolgreiche Antwort (GetRecord Beispiel)

<?xml version="1.0" encoding="UTF-8"?>
<OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/
         http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd">
  <responseDate>2025-08-05T10:30:00Z</responseDate>
  <request verb="GetRecord" metadataPrefix="edm"
           identifier="https://id.kulturpool.at/b1eaac0f-69a1-4174-8ac6-90a61615d0ae">
    https://api.kulturpool.at/oai
  </request>
  <GetRecord>
    <record>
      <header>
        <identifier>https://id.kulturpool.at/b1eaac0f-69a1-4174-8ac6-90a61615d0ae</identifier>
        <datestamp>2024-12-15T09:22:13Z</datestamp>
        <setSpec>kulturpool-europeana:wien-bibliothek</setSpec>
      </header>
      <metadata>
        <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
                 xmlns:edm="http://www.europeana.eu/schemas/edm/"
                 xmlns:dc="http://purl.org/dc/elements/1.1/"
                 xmlns:dcterms="http://purl.org/dc/terms/"
                 xmlns:ore="http://www.openarchives.org/ore/terms/">
          <!-- EDM/RDF Metadaten hier -->
          <edm:ProvidedCHO rdf:about="https://id.kulturpool.at/b1eaac0f-69a1-4174-8ac6-90a61615d0ae">
            <dc:title>Beispiel Titel</dc:title>
            <dc:creator>Beispiel Künstler</dc:creator>
            <dc:description>Beispiel Beschreibung</dc:description>
            <!-- weitere Metadatenfelder -->
          </edm:ProvidedCHO>
        </rdf:RDF>
      </metadata>
    </record>
  </GetRecord>
</OAI-PMH>

Fehlerantwort

<?xml version="1.0" encoding="UTF-8"?>
<OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/">
  <responseDate>2025-08-05T10:30:00Z</responseDate>
  <request>https://api.kulturpool.at/oai</request>
  <error code="badVerb">Illegal OAI verb</error>
</OAI-PMH>

Fehlerbehandlung

Das OAI-PMH Protokoll definiert standardisierte Fehlercodes:

Paginierung

Bei großen Datenmengen verwendet OAI-PMH Resumption Tokens für die Paginierung:

<resumptionToken completeListSize="5000" cursor="100">
  token123456789
</resumptionToken>

Um die nächste Seite abzurufen:

GET /oai?verb=ListRecords&resumptionToken=token123456789

Datensets zum Herunterladen

Der Kulturpool stellt täglich aktualisierte Komplett-Exporte aller Objektdaten zum Download bereit. Diese Datensets ermöglichen die lokale Verarbeitung, Analyse und Wiederverwendung des gesamten Datenbestands für Forschung, eigene Anwendungen oder Archivierungszwecke.

Download-URL

Die tagesaktuellen Datensets sind als komprimiertes TAR-Archiv unter der folgenden, stabilen URL verfügbar:

https://s3.kpool.at/nightly/full_records.tar.gz

Datenformat

1. Archiv (.tar.gz)

Der Download ist eine einzelne, mit gzip komprimierte TAR-Archivdatei. Sie müssen diese Datei nach dem Herunterladen entpacken, um auf die eigentlichen Datensätze zugreifen zu können.

2. Datendateien (.jsonl)

Das entpackte Archiv enthält mehrere Dateien mit der Endung .jsonl – für jede datenliefernde Institution eine. Das JSONL-Format (JSON Lines) bedeutet, dass jede Datei aus mehreren Zeilen besteht, wobei jede Zeile ein vollständiges, eigenständiges JSON-Objekt darstellt.

3. Datensatz (JSON-LD / EDM)

Jedes JSON-Objekt (also jede Zeile in einer .jsonl-Datei) repräsentiert ein einzelnes Kulturgut. Der Datensatz ist im JSON-LD-Format strukturiert und folgt dem Europeana Data Model (EDM). Die Struktur entspricht exakt dem metadata-Objekt, das auch von der Objekte API ausgeliefert wird.

Struktur eines Datensatzes

Jede Zeile in den .jsonl-Dateien ist ein JSON-Objekt, das wie folgt aussehen kann:

{
  "@context": {
    "ore": "[http://www.openarchives.org/ore/terms/](http://www.openarchives.org/ore/terms/)",
    "edm": "[http://www.europeana.eu/schemas/edm/](http://www.europeana.eu/schemas/edm/)",
    "dc": "[http://purl.org/dc/elements/1.1/](http://purl.org/dc/elements/1.1/)",
    "...": "..."
  },
  "id": "#belvedere_5420_AGG",
  "type": "Aggregation",
  "aggregatedCHO": {
    "id": "#belvedere_5420",
    "type": "ProvidedCHO",
    "dc:title": [
      {
        "lang": "de",
        "value": "Der Kuss"
      }
    ],
    "dc:creator": [
      {
        "value": "Gustav Klimt"
      }
    ]
  },
  "provider": {
    "id": "[https://www.belvedere.at/](https://www.belvedere.at/)",
    "type": "Agent",
    "dc:title": [
      {
        "lang": "de",
        "value": "Belvedere"
      }
    ]
  },
  "edm:dataProvider": {
    "id": "[https://www.belvedere.at/](https://www.belvedere.at/)",
    "type": "Agent",
    "dc:title": [
      {
        "lang": "de",
        "value": "Belvedere"
      }
    ]
  },
  "edm:isShownAt": {
    "id": "[https://digital.belvedere.at/objects/5420/der-kuss-liebespaar](https://digital.belvedere.at/objects/5420/der-kuss-liebespaar)",
    "type": "WebResource"
  },
  "edm:isShownBy": {
    "id": "[https://digital.belvedere.at/resources/images/xl/5420.jpg](https://digital.belvedere.at/resources/images/xl/5420.jpg)",
    "type": "WebResource"
  },
  "edm:rights": {
    "id": "[http://creativecommons.org/publicdomain/mark/1.0/](http://creativecommons.org/publicdomain/mark/1.0/)",
    "type": "RightStatement"
  }
}

Beispiel zur Verarbeitung (Python)

Das folgende Python-Skript zeigt, wie Sie das Archiv herunterladen, entpacken und die einzelnen JSONL-Dateien Zeile für Zeile verarbeiten können.

import requests
import tarfile
import json
import io

# URL zum Datenset
DATASET_URL = "[https://s3.kpool.at/nightly/full_records.tar.gz](https://s3.kpool.at/nightly/full_records.tar.gz)"

print(f"Lade Datenset von {DATASET_URL} herunter...")
response = requests.get(DATASET_URL, stream=True)
response.raise_for_status()

# Erstelle ein file-like object aus dem heruntergeladenen Inhalt
file_like_object = io.BytesIO(response.content)

print("Entpacke Archiv im Speicher...")
with tarfile.open(fileobj=file_like_object, mode="r:gz") as tar:
    # Iteriere durch jede Datei im Archiv
    for member in tar.getmembers():
        if member.isfile() and member.name.endswith('.jsonl'):
            print(f"\n--- Verarbeite Datei: {member.name} ---")
            
            # Extrahiere die Datei in den Speicher
            file_content = tar.extractfile(member).read().decode('utf-8')
            
            # Verarbeite jede Zeile der JSONL-Datei
            for line in file_content.strip().split('\n'):
                try:
                    # Lade die Zeile als JSON-Objekt
                    record = json.loads(line)
                    
                    # Greife auf Daten zu (Beispiel: Titel extrahieren)
                    # Achtung: Die Struktur kann variieren
                    if 'aggregatedCHO' in record and 'dc:title' in record['aggregatedCHO']:
                        # Finde einen Titel, idealerweise auf Deutsch
                        title_de = next((t['value'] for t in record['aggregatedCHO']['dc:title'] if t.get('lang') == 'de'), None)
                        title_any = record['aggregatedCHO']['dc:title'][0]['value'] if record['aggregatedCHO']['dc:title'] else "Kein Titel"
                        
                        print(f"Gefundener Titel: {title_de or title_any}")

                except json.JSONDecodeError:
                    print(f"Fehler beim Parsen einer Zeile in {member.name}")
                except Exception as e:
                    print(f"Ein unerwarteter Fehler ist aufgetreten: {e}")

print("\nVerarbeitung abgeschlossen.")