diff --git a/.gitignore b/.gitignore
index 5af7728c..5d55bd25 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@ vendor
.DS_Store
.vscode/settings.json
**.DS_Store
+.fetch
diff --git a/docs/integratie/ai-metadata-api.md b/docs/integratie/ai-metadata-api.md
new file mode 100644
index 00000000..ab0abf3c
--- /dev/null
+++ b/docs/integratie/ai-metadata-api.md
@@ -0,0 +1,391 @@
+---
+layout: default
+title: AI metadata API
+parent: Een integratie ontwikkelen
+has_children: false
+has_toc: true
+nav_order: 8
+last_modified_date: 2026-04-21
+---
+
+
+
+ Inhoudstafel
+
+ {: .text-delta }
+1. TOC
+{:toc}
+
+
+## AI metadata API
+
+Status: `v1.1.0`
+Laatst bijgewerkt: `28/05/26`
+
+## 1. Inleiding
+
+Met verschillende AI-technieken zoals spraak- en gezichtsherkenning, wordt door
+meemoo voor geselecteerd audiovisueel materiaal specifieke, verrijkende metadata
+gegenereerd. Het genereren gebeurt in zogeheten pipelines. Het uitvoeren van een
+pipeline op een enkel object is een taak (of *task*), bijvoorbeeld: de
+transcriptie aanmaken van een audiobestand.
+
+De AI metadata API maakt de gegenereerde metadata
+beschikbaar voor contentpartners, onder meer:
+
+- taakresultaten van AI-verwerkingen op fragmenten
+- matches tussen gedetecteerde personen en de referentieset
+- metadata van personen in de referentieset
+- transcripties en speech-to-textresultaten
+- output van Named Entity Recognition (NER)
+
+De API is bedoeld voor (externe) ontwikkelaars van contentpartners die de
+AI-gegenereerde metadata in hun systemen willen integreren.
+
+## 2. Authenticatie & Autorisatie
+
+De API is alleen toegankelijk voor geautoriseerde gebruikers. Autorisatie
+verloopt via een OAuth2.0 flow met Bearer Token, aan te vragen via de volgende
+URL: .
+
+De authenticatieflow gebruikt `client_credentials` als
+`grant_type` met het e-mailadres en het wachtwoord van je meemoo-account als credentials
+([Client Credentials - OAuth 2.0 Simplified](https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/)).
+
+### REQUEST
+
+```shell
+curl -X POST "https://oas.hetarchief.be/token" \
+–u ":" \
+-d "grant_type=client_credentials" \
+-d "expires_in=3600
+```
+
+### RESPONSE
+
+```json
+{
+ "access_token": "",
+ "expires_in": 3600,
+ "token_type": "bearer"
+}
+```
+
+## 3. API architectuur
+
+Deze API is een GraphQL endpoint waarnaar je een query stuurt
+waarin je zelf bepaalt voor welke velden je data wil krijgen.
+
+De API biedt een *view* per metadatatype als resultaat van een
+pipeline. Elke view bevat op taakniveau het resultaat van de verwerking
+uitgevoerd op een mediafragment of een match met een referentieset.
+
+De beschikbare views en de metadatabeschrijving zijn:
+
+- `face_tasks:` detectie van gezichten/personen op videofragmenten
+- `image_tasks:` detectie van gezichten/personen op foto
+- `face_matches:` matches tussen gedetecteerde personen en de referentieset voor video
+- `image_matches:` matches tussen gedetecteerde personen en de referentieset voor foto
+- `refset_persons`: metadata van personen in de referentieset
+- `speech_tasks`: speech-to-text metadata en transcripties
+- `ner_tasks`: NER en textrazor metadata
+
+## 4. Endpoints
+
+De API wordt aangeboden via:
+. De endpoint is beveiligd en
+kan alleen bevraagd worden door een Bearer token mee te geven (zie boven: 2.
+Authenticatie & Autorisatie). Met typische GraphQL queries kan flexibel alle of
+een deel van de (meta)data van een of meer taken uit een pipeline opgevraagd
+worden.
+
+Het is mogelijk het aantal resultaten van de query te beperken met een `limit`
+en door een `offset` mee te geven om bijvoorbeeld de resultaten te pagineren.
+Je kan de resultaten ook filteren door een `where` clause mee te geven in de
+query. De velden waarop gefiltered kan worden kunnen met een standaard
+introspect query opgevraagd worden of worden ingevuld door een query builder te
+gebruiken.
+
+Bijvoorbeeld voor face_tasks:
+
+- cluster_uuid
+- cp
+- match_score
+- matched_time
+- refset_person_id
+- refset_person_name
+- refset_person_wiki_id
+- time_intervals
+
+Voor meer informatie over GraphQL queries, zie [Queries | GraphQL](https://graphql.org/learn/queries/).
+
+Het onderstaande voorbeeld van een typische query vraagt de `face_tasks` view op
+via het GraphQL endpoint, waarbij `<...>` de in de response gewenste datavelden
+van de view zijn. Zie verder bij hoofdstuk '5. Data views' voor een volledig
+overzicht van de beschikbare velden per view.
+
+## GRAPHQL QUERY
+
+```graphql
+query GetFaceTasks($limit: Int!, $offset: Int!, $status: [String!]) {
+ face_tasks(
+ limit: $limit
+ offset: $offset
+ where: { status: { _in: $status } }
+ ) {
+ <...>
+ }
+}
+```
+
+## cURL REQUEST
+
+```shell
+echo '{
+ "query": "query GetFaceTasks($limit: Int!, $offset: Int!, $status: [String!]) {
+ face_tasks(
+ limit: $limit
+ offset: $offset
+ where: {
+ status: {
+ _in: $status
+ }
+ }
+ )
+ {
+ task_id
+ processed_time
+ status
+ cp
+ title
+ }
+ }",
+ "variables": {
+ "limit": 1,
+ "offset": 1,
+ "status": "succeeded"
+ }
+}' | tr -d '\n' | curl --silent \
+ -X POST "https://services.viaa.be/ai-results/v1/graphql" \
+ -H "Authorization: Bearer " \
+ -H "Content-Type: application/json" \
+ -d @-
+```
+
+## RESPONSE
+
+```json
+{
+ "data": {
+ "face_tasks": [
+ {
+ "task_id": "",
+ "processed_time": "",
+ "status": "succeeded",
+ "cp": "OR-xxxxxxxx",
+ "title": "Example fragment"
+ }
+ ]
+ }
+}
+```
+
+## 5. Data views
+
+- Timestamps worden weergegeven in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) waar van toepassing.
+- De precieze velden die je opvraagt, bepaal je zelf in je GraphQL-query.
+- Ruwe outputvelden zoals `processed_json`, `textrazor_json`,
+ `transcript_json` en `audio_classification_json` zijn bedoeld voor
+ integraties die de volledige service-output willen verwerken.
+
+### 5.1 face_matches | image_matches
+
+Geeft matches terug tussen gedetecteerde personen en personen in de
+referentieset.
+
+#### Velden
+
+| **Veld** | **Beschrijving** |
+| :---------------------- | :----------------------------------------------------------- |
+| `cluster_uuid` | een unieke identifier voor de cluster waartoe de match behoort |
+| `cp` | de unieke identifier van de content partner |
+| `match_score` | de score van de match |
+| `matched_time` | het moment waarop de match gemaakt is in in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601)|
+| `refset_person_id` | de refset identifier van de gematchte persoon |
+| `refset_person_name` | de naam van de gematchte persoon |
+| `refset_person_wiki_id` | de wiki/Q-identifier van de gematchte persoon |
+| `time_intervals` | een lijst van start- en eindtijden (in seconden) waarin de gematchte persoon voorkomt |
+
+### 5.2 face_tasks | image_tasks
+
+Geeft resultaten terug van gezichts- en persoonsdetectie op fragmenten.
+
+| **Veld** | **Beschrijving** |
+| :----------------------- | :----------------------------------------------------------- |
+| `cluster_uuids` | een lijst van cluster uuids |
+| `cp` | de unieke identifier van de content partner |
+| `error` | de foutmelding indien de task status `failed` is |
+| `external_id` | de externe identifier van het fragment gelinkt aan de task |
+| `main_local_id` | de interne cp-id, indien ingevuld op main-fragmentniveau en alleen voor shared-AI CP's (niet GiVE) |
+| `media_object_id` | het mediaobject-id van het fragment gelinkt aan de task |
+| `n_faces` | het totaal aantal gezichten in de task |
+| `n_faces_per_frame` | het aantal gezichten per frame |
+| `n_persons` | het totaal aantal personen in de task |
+| `n_persons_per_frame` | het aantal personen per frame |
+| `n_scenes` | het totaal aantal scènes in de task |
+| `perc_frames_with_faces` | het precentage aan frames met een gezicht |
+| `pid` | de pid van het fragment gelinkt aan de task |
+| `processed_time` | het tijdstip waarop de task verwerkt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) |
+| `status` | de verwerkingsstatus van de task, bijvoorbeeld `succeeded` of `failed` |
+| `task_id` | een unieke identifier voor de task |
+| `title` | de titel van het fragment |
+
+### 5.3 ner_tasks
+
+Geeft NER-resultaten en gerelateerde ruwe output terug.
+
+| **Veld** | **Beschrijving** |
+| :--------------- | :----------------------------------------------------- |
+| `cp` | de unieke identifier van de content partner |
+| `fragment_id` | de unieke identifier van het fragment gelinkt aan de task |
+| `error` | de foutmelding indien de task status `failed` is |
+| `pid` | de pid van het fragment gelinkt aan de task |
+| `processed_json` | de onbewerkte output van de task in JSON-formaat |
+| `processed_time` | het tijdstip waarop de task verwerkt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) |
+| `status` | de verwerkingsstatus van de task, bijvoorbeeld `succeeded` of `failed` |
+| `task_id` | een unieke identifier voor de task |
+| `textrazor_json` | de onbewerkte output van textrazor |
+
+### 5.4 speech_tasks
+
+Geeft speech-to-textresultaten, transcripties en aanverwante metadata terug.
+
+| **Veld** | **Beschrijving** |
+| :-------------------------- | :----------------------------------------------------------- |
+| `cp` | de unieke identifier van de content partner |
+| `error` | de foutmelding indien de task status `failed` is |
+| `external_id` | de externe identifier van het fragment gelinkt aan de task |
+| `main_local_id` | de interne cp-id, indien ingevuld op main-fragmentniveau en alleen voor shared-AI CP's (niet GiVE) |
+| `fragment_id` | de unieke identifier van het fragment gelinkt aan de task |
+| `media_object_id` | het mediaobject-id van het fragment gelinkt aan de task |
+| `pid` | de pid van het fragment gelinkt aan de task |
+| `processed_time` | het tijdstip waarop de task verwerkt is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) |
+| `statistics` | een reeks van speechmatics stastieken |
+| `status` | de verwerkingsstatus van de task, bijvoorbeeld `succeeded` of `failed` |
+| `task_id` | een unieke identifier voor de task |
+| `title` | de titel van het fragment |
+| `transcript_json` | de onbewerkte output van textrazor in JSON-formaat |
+| `transcript_srt` | de transcriptie als .srt ondertitels |
+| `transcript_txt` | de transcriptie als platte tekst |
+| `transcript_vtt` | de transcriptie als .vtt ondertitels |
+| `audio_classification_json` | de resultaten van de audioclassificatie pipeline |
+
+### 5.5 refset_persons
+
+Geeft metadata terug over personen in de referentieset.
+
+| **Veld** | **Beschrijving** |
+| :------------- | :----------------------------------------------------------- |
+| `created_at` | het tijdstip waarop de refset-entry is aangemaakt, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) |
+| `id` | de unieke identifier van de refset-entry |
+| `label` | een label van de refset-entry, bijvoorbeeld een naam |
+| `description` | een omschrijving van de refset entry |
+| `modified_at` | het tijdstip waarop de refset-entry het laatst aangepast is, in [ISO-8601](https://developer.meemoo.be/docs/metadata/viaa/datatypes.html#iso8601) |
+| `public_links` | een lijst van publieke links van de refset-entry |
+| `status` | de status van de refset-entry |
+
+## 6. Voorbeelden van gebruik
+
+Het gebruik van de API wordt toegelicht met 2 concrete voorbeelden in:
+[give-graphql-query-examples](https://github.com/viaacode/give-graphql-query-examples).
+
+Deze repository bevat twee use cases die de AI metadata API gebruiken:
+- alle beschikbare metadata ophalen
+- ruwe data downloaden
+
+Zie ook de [README.md in de repository](https://github.com/viaacode/give-graphql-query-examples/blob/main/README.md) voor uitleg.
+
+### 6.1 Voorbereiding
+
+- Zorg dat Python 3.11+ geïnstalleerd is op je systeem: [Python installatie](https://www.python.org/downloads/)
+- git clone [de repository](https://github.com/viaacode/give-graphql-query-examples)
+- Kopieer het `.env-template` en hernoem het naar `.env`
+- Vul in het `.env` bestand de `USER_EMAIL` en `PASSWORD` velden in met de waarden van een account gelinkt aan jouw organisatie
+- Voer de volgende commando's uit in een terminal om de virtuele omgeving te activeren zodat de scripts kunnen gerund worden:
+
+**Linux/MacOS:**
+
+```shell
+python3.11 -m venv .venv
+source .venv/bin/activate
+python -m pip install -U pip wheel
+python -m pip install -r requirements.txt
+```
+
+**Windows:**
+
+```shell
+py -3.11 -m venv .venv
+.venv\Scripts\activate
+python -m pip install -U pip wheel
+python -m pip install -r requirements.txt
+```
+
+### 6.2 De scripts uitvoeren
+
+#### Metadata downloaden
+
+Gebruik `download_meemoo_ai_data.py` om alle beschikbare metadata voor je
+organisatie op te halen en lokaal als JSON op te slaan.
+
+Het script maakt in `output/` een submap per view aan:
+
+- `face_tasks`
+- `face_image_tasks`
+- `face_matches`
+- `face_image_matches`
+- `refset_persons`
+- `speech_tasks`
+- `ner_tasks`
+
+In elke submap wordt de data gepagineerd opgeslagen. Elk JSON-bestand bevat dus
+1 pagina met resultaten.
+
+Het script verwacht dat de uitvoermap nog niet bestaat. Wil je de export opnieuw
+uitvoeren, verwijder dan eerst de map `output/`.
+
+```shell-script
+# vergeet niet eerst je virtuele omgeving te activeren
+python download_meemoo_ai_data.py
+```
+
+### Ruwe AI output downloaden
+
+Gebruik daarna `download_meemoo_raw_ai_files.py` om per taak de ruwe bestanden
+op te halen.
+
+Voer dit script pas uit nadat `download_meemoo_ai_data.py` succesvol heeft
+gedraaid. Het script gebruikt namelijk de eerder geëxporteerde metadata in
+`output/` om te bepalen welke taken moeten worden opgehaald.
+
+In de huidige versie van het script worden ruwe bestanden voor `speech_tasks`
+gedownload naar `output/speech_tasks/tasks//`. Per taak kunnen daar
+onder meer volgende bestanden in terechtkomen:
+
+- `metadata.json`: metadata van de taak
+- `speechmatics_raw.json`: ruwe JSON-respons van Speechmatics
+- `subtitles.srt`: transcriptie in SRT-formaat
+- `subtitles.vtt`: transcriptie in VTT-formaat
+- `transcription.txt`: platte tekstversie van de transcriptie
+- `audio_classification.json`: output van de audio-classificatie
+
+De map `output/speech_tasks/tasks/` mag nog niet bestaan wanneer je het script
+start. Wil je de ruwe bestanden opnieuw downloaden, verwijder die map dan eerst.
+
+Afhankelijk van het aantal taken kan dit script enige tijd duren. Tijdens het
+uitvoeren toont het script een voortgangsbalk.
+
+```shell-script
+# vergeet niet eerst je virtuele omgeving te activeren
+python download_meemoo_raw_ai_files.py
+```