# Rapportly API, van fictieve bron naar resultaat

De bestaande API-basis is op 4 oktober 2026 getest en op productie vrijgegeven. De CRM-mutaties met 375 zijn na gecontroleerde uitrol in productie vrijgegeven. De synthetische CRM-proef heeft zoekopdrachten, bezoekregistratie en trajecten gecontroleerd, inclusief herhaling, versieconflicten, rechtenweigering, opruiming van de eigen proefklant en intrekking van de tijdelijke sleutels. Kantoorsjablonen zijn in deze productieproef uitsluitend gelezen; hun schrijfcontract is lokaal en in CI getest. Workflowtaal met 376-v2 en vergelijking van opgeslagen uitvoerhistorie zijn lokaal en in CI getest. Hun volledige productiegedrag is hiermee niet bewezen; de CRM-proef bewijst die functies niet. De exacte contractbron staat per route in OpenAPI; de historische route-inventaris is 56179ec5. Gebruik uitsluitend acties die voor de concrete omgeving zijn vrijgegeven. Dit is geen volledige gelijkheid met alle websitefuncties. De betaalde taalvervolgstap per uitkomst uit 28d23f2e en bulk met tweede taal blijven uitgesloten. CRM-bron d964db8c en workflowtaalbron a2f438b8 blijven afhankelijk van actuele rechten, privacyvrijgave en volledige schema-readiness.

## Releasebewijs en afbakening

- Backendmerge: `d1369da2f17f32fa2bffbcc361951e379a62e218`; deployment: `c9ab886d-c92d-48b7-a182-a3e5f7ead4d4`.
- Publieke runtime/source-herlezing: `1016c3ab4030f19b719a0423e7db03ca2aa80e42` / `72c1e27dfc3eb3c90689840a8f8e7a8b6ab0688f` op `2026-10-05T14:41:33.902190+00:00`.
- CRM-proef: `https://github.com/ASKmimon/rapportly-app/actions/runs/37325544706`; inhoudsvrij bewijs: `fb6f357e0fd04d5ed94bf95a076d36ae9624eabc0aba1df93305a8f2a30bedb2`; afgerond op `2026-10-05T14:33:53Z`.
- Migraties 375 en 376-v2, exacte privacyvrijgave, readiness en CRM-activering: `375: 20261005121746; 376-v2: 20261005130842; 12 readiness / RLS / ACL checks passed; PostgreSQL 17 CI 37320873679; CRM concurrency CI 37320873720`.

De CRM-proef gebruikt tijdelijke sleutels met een creditbudget van nul en controleert opruiming en intrekking. Zij dekt drie CRM-writes; kantoorsjablonen zijn in productie niet gewijzigd. Workflowtaal en opgeslagen-historievergelijking hebben in deze releaserapportage uitsluitend lokaal/CI-bewijs. Bulk met tweede taal blijft gesloten. Dit bewijst geen volledige websitepariteit of externe klantacceptatie.

## Contracten kiezen en importeren

- `rapportly-productie.openapi.json`: routes voor echte verwerking, met schemas en een expliciete openlijst per gedeeltelijk contract.
- `rapportly-schema-inventaris.json`: alle statisch geïnventariseerde domeinacties, inclusief de acties waarvan het exacte schema nog open is.
- `rapportly-productie.postman_collection.json`: handmatige synthetische voorbeelden. Importeer als Postman Collection v2.1; kies verzoeken één voor één.
- `rapportly-testmodus.openapi.json` en de oefencollectie: afzonderlijke simulator, alleen vaste oefeninhoud.

De productiecollectie start met `https://api.rapportly.invalid/api/rapportly`, lege geheimen, lege object-ID’s en `allowMutations=false`. Importeren maakt geen sleutel, bestand of verwerking. Het voorbereidingsscript blokkeert een ongeldig domein en blokkeert POST/PUT/PATCH/DELETE zolang je niet bewust lokaal toestemming hebt ingesteld. De raming is ook geblokkeerd omdat de collectie alle POST-verzoeken conservatief behandelt, hoewel die route niets afboekt.

Gebruik een afzonderlijke vrijgegeven organisatie met uitsluitend fictieve gegevens. Stel `baseUrl` bewust lokaal in op de bevestigde server met `/api/rapportly`, bijvoorbeeld het beoogde adres `https://api.rapportly.io/api/rapportly`. De verzoeken voegen `/v1` zelf toe. Bewaar `apiKey` en eventueel `sessionJwt` uitsluitend lokaal als geheim. Exporteer geen ingevulde geheimen. Zet `allowMutations` alleen aan voor het beoordeelde verzoek en daarna weer uit. Draai de collectie niet als één ongecontroleerde reeks.

Dit checkpoint bevat geen resultaat van een collectie-import of API-proef. De onderstaande ketens zijn uitvoerbare voorbeelden voor een latere expliciet vrijgegeven proef. Productieacties met fictieve tekst kunnen echte credits, opslag en providerverkeer gebruiken.

## Sleutel en rechten

Een productiesleutel begint met `rply_`; een testsleutel met `rply_test_`. Stuur `Authorization: Bearer <sleutel>`. Een testsleutel past alleen bij de simulator. De gekoppelde gebruiker, diens organisatie, pakket, objectrechten en het actuele rechtenplafond blijven beslissend.

Vraag `GET /v1/acties` op met `gebruik:lezen` voor de aangesloten catalogus. `toegestaan_door_sleutel` is geen belofte dat ieder object toegankelijk is. `GET /v1/gebruik` geeft sleutelbudget en verzoekaantallen. Open reserveringen uit eerdere maanden tellen mee; werkelijk verbruik volgt de UTC-reserveringsmaand. Een onbeperkt sleutelbudget geeft geen extra accountcredits.

De beheerroutes `/koppelingen/sleutels/{id}/beleid`, `/gebruik`, `/verzoeken` en `/vervangen` staan buiten `/v1` en vereisen een gebruikerssessie. Een API-sleutel kan daar geen sessie vervangen. Lees bij beleidswijziging eerst de ETag en stuur die letterlijk als `If-Match`, inclusief aanhalingstekens. Een teamlid kan uitsluitend binnen toegekend wijzigrecht en beheerdersplafond aanscherpen. Een sleutel verandert nooit van test naar productie. Geheim vervangen werkt direct; verlies je het antwoord, lees dan eerst opnieuw en ga niet blind herhalen.

## Ketting A: bronbestand, rapport, status en download

1. Maak lokaal twee nieuwe UUID’s, bewaar ze als `dossierId` en `bestandId`. Stuur `PUT /v1/dossiers/{dossierId}` met `{"naam":"Synthetische werkplaats Atlas"}`. Verwacht 201; dezelfde naam/eigenaar geeft bij herhaling 200. Deze PUT heeft geen Idempotency-Key nodig.
2. Maak een tekstbestand met uitsluitend fictieve oefenfeiten. Kies het bestand in de collectie en stuur `PUT /v1/dossiers/{dossierId}/bestanden/{bestandId}` als multipart met één veld `bestand`. Maximaal 20 MiB; geen extra tekstvelden. PDF, DOCX, DOC, TXT, MD, PNG en JPEG zijn toegestane extensies, met controle van de inhoud. Bewaar id, naam en sha256. Een afwijkend bestand onder dezelfde UUID geeft 409.
3. Vraag desgewenst `POST /v1/generatieplan` met alleen aantallen/instellingen. Dit reserveert geen credits. Toon de bandbreedte én onzekerheden. Ontbrekende legacy-bedragen betekenen niet gratis verwerking.
4. Kies een nieuwe `idempotencyKey` van 16 tot 128 veilige tekens, bijvoorbeeld `synthetisch-rapport-20261004-0001`. Stuur `POST /v1/rapporten` met dossierId en fictieve notities. Bewaar de exacte body en opdrachtcode vóór verzending. Bewaar `versie_id` uit het antwoord als `versieId`. Een startantwoord betekent alleen ontvangst.
5. Lees `GET /v1/rapporten/{versieId}` met oplopende wachttijd. Alleen `status: klaar` heeft een resultaat. Bij `mislukt` registreer je de fout; begin niet automatisch opnieuw met een nieuwe opdrachtcode.
6. Lees `resultaat.export_url` voor PDF, `export_url_docx` voor Word en `export_url_pptx` indien beschikbaar. `null` betekent geen bestand voor dat formaat. Download de teruggegeven link binnen 15 minuten met een aparte aanvraag zonder Rapportly-Authorization-header. Vraag het resultaat opnieuw op als de link verlopen is. Het openen van de statuspagina is geen bewijs dat de download of inhoud correct is.
7. Lees gebruik en verzoekhistorie opnieuw. Leg voor de latere proef afzonderlijk vast: ontvangst, eindstatus, download, inhoud van de fictieve bron, heropenen en verbruik. Deze handleiding claimt die controles nog niet uitgevoerd.

Een offerte of presentatie gebruikt respectievelijk `/v1/offertes` of `/v1/presentaties` met een nieuwe opdrachtcode. Ook deze gebruiken `/v1/rapporten/{versie_id}` voor resultaat. Offertestart verstuurt niet automatisch een bericht. Geavanceerde document-, taal- en stijlopties staan nog als gedeeltelijk schema vermeld; gebruik voor deze keten de eenvoudige gedocumenteerde subset. De totale JSON-body is begrensd; een ruime veldlimiet verruimt die grens niet.

## Ketting B: audio bewaren, transcriberen en gespreksbundel

1. Kies een zelf gemaakte fictieve audio-opname. Stuur `POST /v1/opnames`, multipart `audio`, optioneel `titel`, `klant_id` en `duur_seconden`. Maximaal 100 MiB; M4A, MP3, WAV, OGG, WEBM en MP4 met inhoudscontrole. Dit bewaren vereist `bronnen:uploaden`; de audio-opslag en het quotum moeten dit toestaan.
2. Bewaar `opname.id` als `opnameId`. Start vervolgens `POST /v1/opnames/{opnameId}/transcriptie` met een nieuwe opdrachtcode en bijvoorbeeld `{"model_id":"melia-1","taal":"auto"}`. Hiervoor is `transcripties:starten` vereist. Bewaren en transcriberen zijn afzonderlijke acties.
3. Bewaar `transcriptie_id`, vraag `GET /v1/transcriptie/{id}` op en wacht op `klaar`. Bij een fout gebruik je het concrete foutantwoord; een HTTP 200 kan ook `mislukt` betekenen. De modelkeuze en daadwerkelijke kosten volgen de opdracht, geen vast documentatiebedrag.
4. Gebruik uitsluitend het gecontroleerde fictieve transcript voor `POST /v1/gesprekken`, eventueel met `opnameId`. Minimaal honderd tekens. Hiervoor is `verwerkingen:starten` nodig en weer een nieuwe opdrachtcode. Bewaar `gesprek_id` en volg `GET /v1/gesprekken/{id}`. Bewaar de verslag- en mailteksten pas bij `klaar`.

## Ketting C: native rapport aanpassen en teruglezen

Lees `GET /v1/uitvoer/rapport/{versieId}/rapport_markdown`. Bewaar `versie_nummer`. Stuur daarna PUT op hetzelfde pad met `inhoud` en het gehele getal `basis_versie`, plus een nieuwe Idempotency-Key van minimaal 16 tekens. Lege tekst wordt geweigerd. Deze native revisie is beperkt tot het ondersteunde Rapportly-rapporttype en vereist `documenten:wijzigen`.

Bewaar het nieuwe versienummer uit het ontvangstbewijs. Lees de huidige inhoud en status opnieuw en download verse bestanden. Historie staat onder `/versies` en `/versies/{nr}`. Bewust herstellen gebruikt POST `/herstel/{nr}` met de huidige `basis_versie` en `bevestigd:true`; het maakt een nieuwe revisie. Bij 409 lees je opnieuw en laat je de gebruiker over de nieuwe basis beslissen. Een oude herhaling mag geen latere revisie overschrijven. Betaald hergenereren is een afzonderlijke opdracht; het terminale herhaalantwoord daarvan is nog gedeeltelijk gedocumenteerd.

## Verbindingen, standaardmailbox en webhooks

De aparte verbindingsgids beschrijft menselijke Google-/Microsofttoestemming. Lees altijd eerst de huidige `basis`. Consent en ontkoppeling vereisen een opdrachtcode van minimaal 16 tekens. Een afgeronde toestemmingsaanvraag is een historisch bewijs; de actuele verbinding lees je apart. De API retourneert geen providertokens.

Voor mailboxvoorkeur lees je zowel de voorkeursbasis als `verbinding_basis` van een verzendbare mailbox. PUT vereist `verbindingen:beheren` én `berichten:verzenden`; het antwoord bevat historische `ontvangst` en actuele `huidig`. De keuze verstuurt niets. Gebruik voor de weergegeven keuze `huidig`, ook na herhaling.

Voor v1-webhooks registreer je een eigen publiek HTTPS-doel met `webhooks:beheren` en expliciete bevestiging. Bewaar `signing_secret` veilig, controleer de originele bytes en verwerk event-ID’s uniek. Een herhaalde bezorging mag geen tweede vervolgtaak starten. De webhookgids en het verificatievoorbeeld beschrijven dit. De oude Zapier-eventroutes zijn een afzonderlijk contract.

## Antwoordverlies, conflict en fouten

| Situatie | Vervolg |
|---|---|
| Startantwoord verloren | Dezelfde body, dezelfde object-ID’s en dezelfde Idempotency-Key herhalen. |
| 400 | Corrigeer invoer; maak geen automatische alternatieve opdracht. |
| 401/403 | Controleer sleutelomgeving, actuele gebruiker, pakket en rechten. Verbreed rechten nooit automatisch. |
| 402 | Controleer sleutelbudget, reserveringen en beschikbare credits. |
| 404 | Niet aanwezig of niet zichtbaar. Gebruik geen andere actor om de grens te omzeilen. |
| 409 op versie/basis | Opnieuw lezen; bewuste keuze vóór nieuwe opdrachtcode. |
| 429 | Wacht en respecteer Retry-After. |
| 503/onzeker | Geen fictief succes tonen. Exact herhalen of actuele status lezen. |

De meeste generieke API-starts accepteren 8–128 veilige tekens voor Idempotency-Key; consent en native rapportrevisies vragen minimaal 16. De voorbeelden kiezen daarom overal minimaal 16. Iedere nieuwe logische opdracht krijgt een nieuwe code. Een herhaling krijgt de oude code én dezelfde invoer. Verwijderen, berichten verzenden, nieuwe sleutels uitgeven en bestaande klantobjecten wijzigen zijn geen automatische opruimstappen van deze collectie.

## Wat staat nog open?

De inventaris benoemt ieder open domeincontract. De uitgebreide bron bevat nu nested documentopties, taalvariantstatus, agenda, klantmapbeheer, opname-inhoud, transcriptcorrectie, bibliotheek, workflowvoorstellen en gespreksuitvoer. Native en duurzame herhaalantwoorden van documentstarts en rapporthergeneratie, complete sleuteluitgifte, stijlen/Excel en resterende actiepunt- en abonnementgroepen vragen verdere schema-uitwerking. Drie expliciete taalstatus-/inhoudGETs zijn later selectief toegevoegd. Directe taalstart, beleid en modelvrij herstel zijn verderop als begrensd broncontract beschreven. Workflowtaal is lokaal en in CI getest en vereist volledige 376-v2-readiness; afzonderlijk productiegedragsbewijs blijft nodig; tweede taal bij bulk blijft expliciet gesloten.

Daarna volgen pas schema- en importvalidatie, rechten-/retry-/foutproeven met fictieve bronnen, de volledige eindronde en een afzonderlijk vrijgegeven publicatie. NL/EN vormen eerst de afgeronde bron; de overige 23 actieve schermtalen volgen in een afzonderlijke opdracht.

## Klantmap en bron opnieuw openen

Maak een nieuwe UUID voor een fictieve klantmap. `PUT /v1/klanten/{id}` met `{"naam":"Synthetisch team Atlas","externe_referentie":"oefening-atlas"}` is create-only en vereist `klanten:beheren` plus Idempotency-Key. Lees daarna `GET /v1/klanten/{id}` en bewaar de exacte ETag. Een bewuste `PATCH` met bijvoorbeeld `{"plaats":"Oefenplaats"}` vereist die ETag in `If-Match` en een nieuwe opdrachtcode. Bij 412 opnieuw lezen en de wijziging opnieuw beoordelen. Een identieke ontvangstherhaling mag latere wijzigingen niet terugdraaien.

Gebruik de map-ID als `klantId` bij een documentstart of `klant_id` bij audio-opslag. Zoek de oefening later via `/v1/bibliotheek/zoek?q=Synthetisch&type=alles&limiet=20`. `begrensd:true` betekent dat de zoekset beperkt is; verfijn dan de zoekterm. Bibliotheekfragmenten zijn geen volledige bronkopie.

Lees `/v1/opnames/{id}/inhoud` voor de opgeslagen transcripttekst en sprekers. Een transcriptcorrectie is een aparte `PUT /v1/opnames/{id}/transcript` met vier velden: nieuwe `transcript`, exacte oude `basis_transcript`, nieuwe `sprekers` en exacte oude `basis_sprekers`. Lees na antwoordverlies opnieuw voordat je doorgaat. Bij 409 kan de basis gewijzigd zijn. Een correctie maakt geen nieuwe transcriptie en verandert bestaande gegenereerde documenten niet automatisch. Download de tekst via `/transcript.txt` of vraag de audio-URL via `/audio`; de audiolink is 300 seconden geldig.

## Documentopties, tweede taal en agenda

De productie-OpenAPI bevat afzonderlijke `RapportStart`, `OfferteStart` en `PresentatieStart` schemas. Kies alleen opties voor het betreffende documenttype. `documentformat` vereist een gereed stijlprofiel; een presentatie gebruikt haar eigen dia-opmaak. Offerteregels gebruiken gehele centen en duizendsten, plus expliciete menselijke bevestiging. Serverbevestigingen voor catalogus- of routeregels horen bij dezelfde gebruiker, organisatie en hetzelfde concept. Vul daarvoor geen zelfbedachte bevestigingstoken in.

Een gesprek kan bij de basisstart taalkeuzes bevatten. De oude betaalde gesprek-POSTtaalvarianten bestaat nog in de bron, maar heeft nog geen volledige nieuwe sleutel-/budget-/jobketen. Daarom staat die oude route niet als startvoorbeeld in deze collectie. De afzonderlijke nieuwe gebonden taalstarts, beleid en retry zijn verderop als broncontract beschreven en blijven afhankelijk van expliciete vrijgave en integrale verificatie. Dit document verwijdert geen runtime-route en bewijst geen livewijziging.

`GET /v1/agenda/afspraken?uren=24` leest beschikbare afspraken voor 1–72 uur, met `agenda:lezen`. `verlopen` noemt verlopen providerverbindingen. Een deels succesvol providerantwoord is geen bewijs dat alle agenda’s volledig konden worden gelezen.

## Workflowvoorstel tot indiening

1. Lees `/v1/keuzes/uitleg` en vraag desgewenst modelvrij advies via `POST /v1/keuzes/advies` met `{"documenttype":"rapport","complexiteit":"hoog"}`. Bewaar `advies_id` en `advies_hash`. Relatieve kosten zijn geen vaste creditprijs.
2. Start bewust een fictief voorstel via `POST /v1/workflowvoorstellen`, bijvoorbeeld met `{"naam":"Oefenproces Atlas","klantbeschrijving":"Fictief proces: bron verzamelen, concept schrijven, intern controleren en na akkoord bewaren.","gekoppelde_stijlprofiel_ids":[],"deling_scope":"persoonlijk"}`. Dit kan modelcredits verbruiken. Bewaar voorstel-ID en ETag.
3. Bij antwoordverlies lees je `/v1/workflowvoorstellen/status` met dezelfde Idempotency-Key. `veilig_opnieuw:false` betekent dat deze status geen veilige basis geeft voor een nieuwe betaalde start. Toon onzekerheid en herhaal dezelfde logische opdracht gecontroleerd.
4. Lees het voorstel. Beantwoord uitsluitend bekende vraag-ID’s via PATCH met actuele If-Match en een nieuwe opdrachtcode. Stuur `aangepast_procesvoorstel` alleen als je bewust de procesinstellingen wilt vervangen.
5. Alleen `klaar_voor_indienen` met ten minste één processtap kan via `/indienen` worden ingediend. Indiening bewijst geen menselijke goedkeuring of publicatie. Lees daarna de huidige status opnieuw.

Workflowlijsten geven momenteel hoogstens de eerste 100 items; de opslagadapter verwerkt geen vervolgcursor. Een aanwezige cursor is daarom geen belofte van volledige paginering.

## Menselijke vervolgactie

`POST /v1/zelfservice-aanvragen` met `{"doel":"abonnement","bevestigd":true}` maakt een vijftien minuten geldige bevestigingsingang. De gebruiker opent zelf de ontvangen Rapportly-URL en meldt zich aan met dezelfde identiteit. Hoogstens tien aanvragen blijven tegelijk open. `geopend` betekent alleen dat deze ingang is geopend; `uitvoering_bevestigd` blijft `false`. De API registreert hiermee geen aankoop, betaling, abonnementswijziging, sleuteluitgifte of MFA-wijziging.

## Account, team en sleutelbeheer

Lees de zes instellingen via `/v1/account/bedrijfsgegevens`, `/schermtaal`, `/uitvoertalen`, `/teamkwaliteit`, `/mijnkwaliteit` en `/teamrollen` onder dezelfde accountprefix. Bewaar `basis` letterlijk als string; ook `"0"` is geldig. Een PATCH bevat `basis`, `waarde` en `bevestigd:true`, plus een vaste Idempotency-Key van 8–128 tekens. Bijvoorbeeld: `{"basis":"0","waarde":{"taal":"nl"},"bevestigd":true}` voor schermtaal, uitsluitend als de vooraf gelezen basis echt `"0"` was.

De respons scheidt `ontvangst` (de historische bevestiging van deze opdracht) van `huidig` (de actuele instellingen). Een herhaling maakt een latere wijziging niet ongedaan. Bij een basisconflict lees en beoordeel je opnieuw. Teamkwaliteit, uitvoertalen en teamrollen vereisen de eigenaar; persoonlijke kwaliteit kan vast teambeleid niet omzeilen. `/v1/team` leest rollen en capaciteit, zonder een uitnodiging of extra seat te bestellen.

`/v1/koppelingen/sleutels` en de bijbehorende GET-routes lezen alleen metadata met `sleutels:lezen`. Uitgifte, activatie, beleidswijziging en intrekking gebruiken een gebruikerssessie op `/koppelingen`, buiten `/v1`. Een gedelegeerde sleutel wordt pas bruikbaar wanneer de toegewezen gebruiker die zelf activeert. Geheimen worden eenmalig getoond. Herhaal uitgifte of activatie niet blind na antwoordverlies. De oude `/rechten`-route weigert in de volledige API met 409; gebruik het actuele beleid en If-Match.

## Klantgebonden innameadres

1. Lees `/v1/klant-inname` voor de huidige organisatiebeschikbaarheid. Een leesfout is 503, geen bewijs dat inname uitstaat.
2. Lees `/v1/klanten/{id}/inname` met `klanten:delen`. Bewaar de UUID uit `basis`, ook wanneer `actief:false`.
3. Activeer bewust met POST op hetzelfde pad: `{"basis":"<gelezen UUID>","actief":true,"bevestigd":true}` en een unieke opdrachtcode van 16–128 tekens. Gebruik uitsluitend een fictieve klantmap in een vrijgegeven oefenomgeving.
4. Lees `ontvangst`, `herhaald` en `huidig` apart. Het adres in `huidig` is de actuele ingang. Een nieuwe activering roteert het oude adres; dezelfde exacte retry doet dat niet opnieuw. `actief:false` trekt de actuele ingang in. De cyclus inactief-actief-inactief wijzigt de basis; opnieuw uitzetten zonder actief adres doet dat niet.

Deze adresactie start geen modelverwerking en is geen portaaluitnodiging. Wijziging van organisatie-afzenderregels en verdere portaalhandelingen hebben afzonderlijke contracten; open schema’s blijven in de inventaris staan.

## Opnamewerkplek, transcriptievoorkeuren en CRM

Lees `/v1/opnamewerkplek/mogelijkheden` vóór het kiezen van transcriptieopties. `automatisch` kiest melia-1 voor eenvoudige transcriptie en enhanced bij woordenlijsten, stemprofielen of een stemproef. Expliciet melia-1 is niet te combineren met deze rijke opties. Alleen de eigenaar kan opnameopties wijzigen zolang de opname bewaard of mislukt is.

Werkplekindeling en persoonlijke transcriptievoorkeuren hebben ieder een eigen `versie`; historische transcriptie gebruikt `transcript_revisie`. Lees de juiste basis, wijzig bewust en lees na antwoordverlies eerst opnieuw. Het verwijderen van een opnamemap bewaart de opnames. Het hersteloverzicht geeft alleen ID en datum van eigen opnames waarvan klanttoegang vervallen is; inhoud blijft afgeschermd tot de toegestane ontkoppeling.

Een stemprofiel vereist expliciete toestemming voor de eigen stem met de huidige `toestemming_versie`. Aanmaken heeft een herhaalbare opdrachtcode; wijzigen/verwijderen vereist de exacte huidige `bijgewerkt_op` in If-Match. Aanmaken alleen betekent nog niet dat een profiel klaar is voor herkenning. Biometrische provideridentifiers worden niet teruggegeven. De voorbeeldcollectie registreert geen stemmen.

CRM gebruikt GET/PUT `/v1/klanten/{id}/crm`. PUT vervangt precies één volledig onderdeel (`opvolging`, `contactpersonen`, `notities`, `checklist`, `pins` of `definitief`) met de actuele `revisie`. Bewaar bestaande rij-ID’s bij aanpassen en laat niet bedoelde rijen niet weg uit een volledige vervanging. Er mag maximaal één hoofdcontact zijn; ontvangen/gecontroleerde checklistregels vereisen een echt toegankelijk bestand. Auteurschap en datum van notities worden door de server bewaakt. Na antwoordverlies lees je de CRM terug; een nieuwe revisie is geen bewijs dat blind herhalen veilig is.

Voor zoeken lees je eerst `/zoekbestanden`. Een bewuste POST `/zoekbestanden/{bestandId}` met `soort` bestand of versie maakt bestaande tekst doorzoekbaar, zonder modelgeneratie. HTTP 200 kan `wacht`, `bezig`, `mislukt` of `onleesbaar` bevatten. Er is geen OCR-belofte voor gescande documenten. Zoek vervolgens met `/zoeken?q=Atlas&offset=0`; gebruik maximaal dertig treffers per pagina en volg `meer`. Een intern resultaatpad is geen zelfstandige downloadautorisatie.

## Toegang, links en briefing

Lees `/v1/klanten/{id}/toegang` en gebruik alleen bij `kanWijzigen:true` de huidige revisie voor een bewuste keuze team, geselecteerd of privé. Geselecteerd vereist andere toegestane collega’s; bij team/privé is die lijst leeg. De revisie voorkomt dat een oude keuze nieuwere rechten overschrijft.

`POST /v1/klantmappen/koppel` accepteert één bronitem (opname, gesprek of dossier) en precies één bestaande klant-ID of klantnaam. Bronmateriaal blijft in dezelfde opslag en bibliotheek. Controleer na een onduidelijk antwoord de actuele koppeling; deze route heeft geen idempotent ontvangstcontract.

Een rapportvoorkeur hoort bij jouw gebruiker en het stijlprofiel van de rapportversie. Lees `/v1/rapporten/{versieId}/voorkeuren` en stuur de JSON-ETag letterlijk als If-Match bij PUT met `tekst` (maximaal 2000 tekens). Dit herschrijft geen bestaand rapport.

Deel- en aanleverlinks hebben een bewuste bevestiging, geldigheid van 7, 14 of 30 dagen en een vaste opdrachtcode. Een actieve ontvangst geeft toegangdragend token/URL; sla deze beschermd op. Een exacte oude aanvraag voor een verlopen of ingetrokken link geeft alleen metadata, verlengt niets en maakt geen nieuw token. De lijsten tonen geen tokens. Intrekken gebeurt afzonderlijk en een al ingetrokken link geeft 404. Linkaanmaak verstuurt geen bericht.

Een briefingstart vereist de huidige Amsterdamse datum als `dag`, bijvoorbeeld `{"dag":"<huidige dag>","taal":"nl","vernieuwen":false}`. De API gebruikt de duurzame betaalde verwerking; een oude datum geeft 409. Een klaar dagresultaat kan direct uit cache komen; 202 bewijst geen gereed resultaat. Lees GET op hetzelfde klantpad. Vernieuwen is een bewuste nieuwe generatie en mag niet dienen als automatische reactie op een onzeker antwoord.

Volledige klantverwijdering heeft een afzonderlijke beheerderscontrole met aantallen, blokkades en fingerprint. De schrijfroute vereist de exacte huidige naam, fingerprint en bevestiging; 202 betekent dat opslagopruiming nog loopt. Dit verschilt van alleen de klantmap verwijderen. De collectie bevat geen uitvoerbaar voorbeeld voor definitieve verwijdering.

## Klassieke stijlbron, OCR en herstel

Lees `/v1/stijlprofielen/{id}/bronstatus` met `stijlen:bronnen_lezen`. Bewaar de huidige `basis`; de lijst geeft bronmetadata zonder inhoud of opslagpaden. Alleen de huidige maker én eigenaar kan een herstel- of OCR-opdracht starten. Een teamrol geeft geen toestemming om als een andere maker te werken.

Bij `ocr_keuze_nodig:true` kan POST `/ocr-schattingen` met `basis`, `bevestigd:true` en een vaste opdrachtcode een raming maken. Daarvoor is ook `stijlen:uitgebreid_lezen` nodig. De raming gebruikt expliciet providercontact om PDF-gebruik te tellen en blijft aan de privacytoestemming gebonden. De ontvangst is vijftien minuten geldig; een onzekere claim mag niet automatisch opnieuw naar de provider worden gestuurd. `verwerking_gestart:false` betekent dat betaalde OCR nog niet is gestart.

Na bewuste beoordeling start `/uitgebreid-lezen` met dezelfde actuele basis, `schatting_id`, bevestiging en een nieuwe logische opdrachtcode. Algemeen `/herstellen` gebruikt `stijlen:herstellen`, dezelfde bronleesrechten en een passende terminale native fout. Lees vervolgens `/herstelopdrachten/{aanvraagId}`. Een ontvangen job of geslaagde worker is niet vanzelf een actieve documentstijl: de bestaande controle en goedkeuring kunnen nog volgen. Herhaling plant geen tweede job; de oorspronkelijke en actuele bronbasis blijven verschillende begrippen.

## Mailvoorbeeld, akkoord en onzeker verzenden

1. Vraag POST `/v1/gesprekken/{id}/mail/voorbeeld` aan met `mailsoort` klantmail of followup, de bewuste ontvanger en eventueel een bestaande taalvariant. Dit plant of verstuurt niets.
2. Beoordeel onderwerp, tekst, bijlagen, afzender, ontvanger en verzendbeleid. Followup geeft ook `basis`. Een optionele tekstbewerking hoort bij die basis en kan niet tegelijk een vertaalde variant vervangen. Bewaar de exacte voorbeeldinvoer en `review_hash`.
3. Alleen na akkoord gebruik je `/mail/goedkeuren` met `bevestigd:true`, de hash en voor beide mailsoorten de actuele basis. De route gebruikt het review-/snapshotcontract, niet een vrije Idempotency-Key. Verouderde inhoud of verzendgegevens vragen een nieuw voorbeeld en nieuw akkoord.
4. Lees `/v1/mail-outbox`. `queued` kan een toekomstig verzendvenster betekenen. Geaccepteerde MIME bij Gmail/Microsoft, `sent` en `handmatig_bevestigd` zijn geen bewijs van bezorging. Bezorg/open/klikvelden kunnen ontbreken; een bronleesfout geeft 503.
5. Bij `directe_status:onzeker` blijft automatische herverzending uit. Na minimaal vijf minuten kan de eigenaar met de huidige `poging_id` bewust `stoppen`, `als_verzonden` of `opnieuw` kiezen op `/mail-outbox/{outboxId}/herstel`. Opnieuw vereist bovendien `dubbelrisico:true`; de oorspronkelijke poging kan al zijn aangekomen. Dezelfde herstelkeuze herhaalt zonder een tweede actie.

## Verlopen proefperiode

Na afloop blijft lezen beschikbaar voor een geldige gebruiker/sleutel en blijven expliciete leesacties zoals het mailvoorbeeld mogelijk. Nieuw werk vereist een geldige betaalde voortzetting: anders 402 `rapportly_proefperiode_verlopen`; een onleesbare controlebron geeft 503. De afgebakende uitzonderingen zijn een menselijke zelfservice-ingang, verbinding ontkoppelen, webhook intrekken en mailherstel stoppen/als_verzonden. Opnieuw verzenden valt niet onder die uitzondering. Alle overige rechten- en objectgrenzen blijven gelden; verwijderen is geen algemene vrijstelling.

## Stijlintake, metadata en controle

Een klassieke stijl upload je als 1–3 bestanden met naam, soort, deling_scope, tekstwaarde bevestigd=true en een vaste opdrachtcode. Behoud exact dezelfde bytes, namen, volgorde en metadata bij herhaling. Een incomplete ontvangst kan dertig dagen worden hervat; een complete ontvangst krijgt een opdracht-id. Lees de sleutelgebonden `/v1/stijlprofiel-uploads/{id}` om de ontvangst te volgen. De oudere `/stijlprofielen/aanvragen/{aanvraagId}` is voor native UUIDv4-aanvragen; nieuwe API-uploads gebruiken een eigen UUIDv5. Ontvangst en verwerking betekenen nog geen goedgekeurde publicatie.

GET `/v1/stijlprofielen/{id}` geeft metadata met ETag. PATCH en deactivering gebruiken de exacte huidige ETag en de toepasselijke eigenaars-/teamrechten. Na antwoordverlies lees je eerst de huidige toestand. GET `/template-navigatie` geeft uitsluitend relatieve controlevakken en paginanummers, geen tekst. Controleweergave, vaste teksten, formulierkeuzes en publicatie zijn hieronder afzonderlijk beschreven.

## Saldo, opslag en eigen verbruik

GET `/v1/saldo` geeft het huidige persoonlijke of organisatorische saldo. GET `/v1/opslag` geeft bytes en de actuele uitbreidingstarieven zonder iets te bestellen. Bij onvolledige persoonlijke toerekening zijn gebruikt en beschikbaar `null`; behandel dat als onbekend. Een bestaande organisatie-uitbreiding kan verdere afstemming nodig maken.

GET `/v1/credits/verbruik?maand=2026-10` geeft een gekozen UTC-maand; zonder maand gebruikt de route de huidige UTC-maand. Het overzicht telt exacte definitief afgeschreven ledgercredits en benoemt eventuele voorschotten. Het totale openstaande voorschot is actueel, terwijl aflossingen bij de geselecteerde maand horen. Te veel of onvolledige bronregels geven 503 en geen onvolledig totaal.

GET `/v1/credits/runs/{runRef}` is een afzonderlijk historisch runoverzicht. De afronding kan afwijken van de som in het maandledger. `afgerond:true` betekent dat er geen open creditreservering resteert; het zegt niet dat een document geslaagd of mail bezorgd is. Afmaakmeldingen zijn inhoudsvrije signalen over eigen geslaagde jobs met bewezen interne kostendekking.

De oudere `/instellingen/taal`-leesroute valt bij een leesfout terug op Nederlands. Gebruik het expliciete accountcontract met revisiebasis voor wijzigingen. Het abonnementsleesmodel en documentenbankread staan hieronder; dynamische pakketfeatures blijven semantisch open.

## Documentcontrole en presentatiecorrecties

GET `/v1/stijlprofielen/{id}/template-controle` geeft de actuele controle. Een Word- of PDF-document heeft een `sha256`, documentvoorbeeld en merkassets. Afhankelijk van de bron bevat het antwoord ook lettertypevervangingen, behouden opmaak, vaste PDF-tekst of formulieraanpassingen. Lees en beoordeel het volledige voorbeeld; de tijdelijke links zijn geen blijvende openbare bestanden.

Vaste PDF-tekst kies je alleen uit bestaande kandidaten met `/template-vaste-teksten`. Formulierkeuzes gaan naar `/template-formulier-aanpassingen`: bestaande keuze-id’s krijgen true of false. Beide routes vervangen de controle en hash, zonder publicatie. Voor documentgoedkeuring stuur je naar `/template-goedkeuren` de actuele `controleSha256`, de volledige `goedgekeurdeMerkassetSha256`-lijst en `bevestigd:true`. Een formulier vereist ook `formulierInhoudGecontroleerd:true`. Een ontbrekende of verouderde beoordeling vraagt een nieuwe controle.

Presentatie-inzage hoort bij een reeds gepubliceerde stijl. Het antwoord heeft `sha256:null`, de actieve `profielversie_id`, dia’s, layouts, lettertypen, assets en getrouwheidsmetingen. De publicatieroute gebruikt hier `basis_versie_id`. Je kunt de huidige versie herbevestigen of met `correcties.assets_uit` en `correcties.layoutrol` een nieuwe versie maken. Bevestiging van de actieve versie voorkomt dat een oude keuze nieuw werk overschrijft. Bij antwoordverlies eerst de huidige versie opnieuw lezen.

## Abonnement en documentenbank lezen

GET `/v1/abonnement` accepteert geen queryparameters en gebruikt `abonnement:lezen`. De weergave benoemt pakket, saldo, betaal-/inrichtingsstatus, wijzigbevoegdheid, privacybasis, proefperiode en White Label afzonderlijk. Betaalgegevens aanwezig betekent geen succesvolle betaling. Een proefperiodebanner is geen toegangspoort. Ontbrekende ondersteunende status kan null of niet_beschikbaar zijn. Pakketfeatures komen als dynamische database-JSON terug: dat veld staat expliciet als open semantisch schema genoteerd.

De API voert geen abonnementswijziging uit via deze leesroute. Gebruik de eerder beschreven zelfservice-aanvraag voor een bewuste menselijke vervolgstap. Het openen daarvan bewijst geen betaling of afgeronde wijziging.

GET `/v1/documenten` geeft actieve documenten uit de documentenbank van de eigen organisatie. Deze route verzamelt alle interne pagina’s en heeft geen externe cursor. `/v1/documenten/{id}/download` geeft een URL die vijf minuten geldig is; ook een eerder gedeactiveerd document kan nog beschikbaar zijn voor een oude gespreksbundel. Bewaar of log de tijdelijke URL niet als vaste downloadlink. Uploaden/deactiveren van documentenbankmateriaal is hiermee niet als externe API-route ontsloten.

## Stijlonderzoek en gerichte verfijning

GET `/v1/stijlprofielen/{id}/onderzoek` toont de laatste honderd eigen onderzoeksmeldingen. Een gevonden technisch recept is nog geen actief stijlprofiel. Maak een concreet voorstel met `/onderzoek/{meldingId}/voorstel`, beoordeel het en pas het bewust toe met de juiste `basisVersieId` en `bevestigd:true`. Voor presentatieonderzoek moet dezelfde actor eerst de exacte PDF-preview openen; die GET legt de bekeken hash vast. Bij een gewijzigde basis lees je opnieuw.

Een melding uitstellen of de bestaande stijl behouden gebruikt `/keuze` met `later` of `behouden` en exact de ontvangen `bijgewerktOp`. De tijdtekst niet zelf herformatteren. Voorstel, toepassen en keuze delen een limiet van twaalf mutaties per minuut. `klantCredits:0` geldt voor deze onderzoeksherstelroute. Excel heeft overeenkomstige lees-, keuze- en toepasroutes, maar het geneste Excel-onderzoeksvoorstel staat nog open in de schema-inventaris.

Een eigen betaalde vormgevingswijziging gebruikt `/v1/stijlprofielen/{id}/verfijnen/jobs`. Dit is alleen voor de bestaande legacy-engine `profiel_v1`. Stuur de huidige `verwachte_profielversie_id`, een korte opmerking over opmaak, `bevestigd:true` en een vaste opdrachtcode. Bijvoorbeeld: “Maak de tussenruimte groter.” Gebruik geen klantinhoud, contactgegevens of bedragen in de opmerking.

Het API-contract accepteert een opdrachtcode van 8–128 veilige tekens; de adapter zet die om voordat de native verfijnhandler hem ziet. Bewaar `aanvraagId` en lees `statusUrl` met dezelfde API-sleutel. Ook een herhaalde terminale ontvangst kan 202 teruggeven. De ontvangst vervalt na 48 uur. Bij `controle_nodig` is de verwerking onzeker en moet de huidige stijl worden beoordeeld; start niet automatisch een nieuwe betaalde opdracht. De collectie bevat een geblokkeerde synthetische start en losse statusread, zonder automatische keten.


## Stijlwerkplaats: voorstel, bekijken en bewust toepassen

De werkplaatsroutes zijn nu als broncontract uitgewerkt: mogelijkheden en actieve basis lezen, een duurzaam voorstel starten, de ontvangst terugvinden, indeling en afbeeldingen lezen, een voorbeeld openen, een voorstel activeren of verwijderen en een eerdere versie herstellen. Dit is een bouwcheckpoint vanaf `66d3dcaf`; beschikbaarheid en juiste werking zijn nog niet getest.

1. Lees `/v1/stijlprofielen/{id}/werkplaats`. Gebruik de huidige `basisVersieId`, aangeboden lettertypen en mogelijkheden; ondersteuning hangt af van de engine en je rechten.
2. Start `/voorstellen/jobs` met een nieuwe idempotentiesleutel, `basis_versie_id` en één operatie: `opmerking`, `instellingen`, `afbeeldingen` of `indeling`. Alleen opmerking kan AI/klantcredits gebruiken. De importcollectie bevat een standaard geblokkeerde lokale instelling met lettergrootte11; kies bewust een echte wijziging ten opzichte van de fictieve basis. Een202 is een ontvangst, geen geslaagd voorstel.
3. Lees de status op aanvraagId. Deze status is actor-/organisatie-/profielgebonden; terugzoeken met idempotentiesleutel is bovendien aan de oorspronkelijke API-sleutel gebonden. Ontvangsten verlopen na7dagen. Bij `controle_nodig` geen nieuwe betaalde poging automatiseren.
4. Open de concrete preview bewust. Deze GET kan een achtergrondrender starten en eerst202 met `Retry-After:2` geven. De uiteindelijke PDF bevat `X-Rapportly-Preview-Hash`. Daarom bevat de collectie geen automatisch uitgevoerde preview-, activatie- of herstelketen.
5. Activeer met de huidige basis, `bevestigd:true` en die exacte hash. Na een verloren antwoord lees je eerst de huidige versie. Herstel van een oudere versie vereist een preview die dezelfde API-sleutel in de huidige UTC-dag heeft geopend. Na dagwisseling is opnieuw openen nodig.

Een indelingsvoorstel behoudt alle zichtbare secties. Een afgeleide bronkopie wordt bij toepassen een legacyprofiel en bewaart geen exacte tabellen, bronafbeeldingen of vaste bronopmaak. Afbeeldingsvervanging gebruikt een sleutel uit de actuele inventaris en een eigen beeldbank-ID; geen aangeleverde opslagpaden. Geen van deze beschrijvingen bewijst een livevrijgave.


## Organisatie-inname: beleid en ontvangst

De selectieve aanvulling uit `354bfa39` beschrijft GET en POST `/v1/klant-inname`. Lezen geeft nu ook de blijvende `basis`, `is_beheerder` en `versiecontrole:true`. Bewaar die basis precies. Beheren vereist de werkelijke organisatie-eigenaar, het recht `teaminstellingen:wijzigen`, actuele pakkettoegang en een idempotentiesleutel van16–128tekens.

De body bevat `actief`, `basis`, `bevestigd:true` en optioneel `allowlist`. Weglaten bewaart de bestaande lijst; een lege lijst verwijdert aanvullende afzenders. Het eigen klant-e-mailadres blijft via de bestaande klantregel toegelaten. Maximaal20invoerregels worden getrimd, naar kleine letters omgezet en ontdubbeld. Een ongeldige regel weigert de hele wijziging.

Het antwoord splitst `ontvangst` (historische id, basis en actief), `herhaald` en `huidig` (de actuele policy). Een oude exacte replay voert de wijziging niet opnieuw uit. Een gewijzigde body bij dezelfde sleutel geeft409. Alleen een recente wijzigingstijd maakt geen nieuwe basis. Deze route maakt geen organisatieadres en start geen AI- of creditverwerking; klantadressen blijven afzonderlijk. De standaard geblokkeerde importvoorbeelden gebruiken uitsluitend een fictieve afzender en beginnen met `actief:false`. Ook dat is bij bewust verzenden een echte beleidswijziging.

De bronaanvulling heeft eigen commitverwijzingen en bestandhashes. Andere nog niet overgedragen contracten zijn niet stilzwijgend opgenomen; alle eindcontroles en publicatie blijven open.

De selectieve proefperiodepoort uit `b7742838` laat ook portaalintrekking, intrekking van een portaalvrijgave en het pauzeren/annuleren van een workflowrun toe na proefverloop. Andere actor-, object- en sleutelrechten blijven verplicht. Deze uitzondering staat geen nieuwe workflow, nieuwe publicatie of herstart toe; de concrete runnercontracten en actuele releasegrenzen staan verderop.


## Modelvrije stijlmaker

De zes externe stijlmakerroutes gebruiken een duurzame opdracht: voorstellen starten, voorbeeld starten, ontvangst terugvinden, status lezen, resultaat ophalen en een onvolledige upload afbreken. De starts gebruiken multipart. De voorbeeldstart stuurt `ontwerp` als JSONstring in één tekstveld en accepteert geen bestanden. Een PNGlogo kan in de ontwerpdata staan. Dit werk publiceert geen actieve stijl.

Gebruik voor starts een nieuwe sleutel van8–128tekens die met een letter/cijfer begint; daarna zijn letters, cijfers, punt, underscore en streepje toegestaan. De algemene dubbelepuntoptie geldt hier niet. Hergebruik exact dezelfde body bij een verloren antwoord en zoek de oorspronkelijke ontvangst op. Ontvangsten en resultaten verlopen na48uur. Status op aanvraagId is actorgebonden; ontvangstlookup met oorspronkelijke sleutel is ook API-sleutelgebonden.

Een gereed voorstelresultaat bevat drie ontwerpen. Een documentvoorbeeldresultaat is altijd JSON met `bestand` in base64, `mime` en `ext`: DOCX, PPTX, XLSX of bij huisstijl PNG. Bewaar alleen het bestandstype uit dat gecontroleerde antwoord; resultaatmetadata kan de ruwe ontwerpinput tonen terwijl de renderer kleuren/afbeeldingen normaliseert. De resultaatroute geeft503 zolang de opdracht nog niet klaar is.

De maker gebruikt geen betaald model, maar een opgegeven website kan wel een afgeschermde netwerkleesactie starten. De collectie laat website en bestanden weg en blokkeert de start standaard. Afbreken geldt uitsluitend voor een onvolledige upload zonder ingeplande job; een ontvangen/bezig/klaaropdracht wordt hiermee niet geannuleerd. Er zijn geen imports of API-aanroepen uitgevoerd.


## Bronprofielen en brondocumenten

Een bronprofiel legt vast welke gegevens uit terugkerende documenten worden gelezen. De broncontracten beschrijven lijst, detail, aanmaak, wijzigen, deactiveren, bestandslink, extractiestart en menselijke controle. De canonieke profiel-PATCHbody is bruikbaar, maar de ruimere historische invoercoercie is nog expliciet als open compatibiliteit gemarkeerd.

Bij aanmaak is `velden` een JSONstring in multipart. Met bruikbare eigen velden volgt201 zonder modelafleiding; zonder velden is instructietekst of een instructiebestand nodig en volgt202. Een exacte herhaling geeft200 met huidige status. Bij PATCH is `velden` juist een JSONarray. Gebruik `If-Match` met de quoted integer `versie` uit het gelezen profiel; de GET zet zelf geen ETag. Deactiveren verwijdert geen historische bestanden.

Een extractiestart verwijst naar een bestaand `dossier_bestand_id` van de klant, met optioneel `bronprofiel_id`. Er is geen nieuwe externe brondocumentuploadroute. Hetzelfde bestand kan niet via een andere start opnieuw worden overgenomen of afgerekend. Volg het resultaat via de klantbrondocumentenlijst. AIafleiding en extractie kunnen klantcredits verbruiken.

Goed- of afkeuren kan alleen bij `te_controleren` met de exacte `bijgewerkt_op` tussen dubbele quotes in `If-Match`. Weggelaten `resultaat` bewaart alle oorspronkelijke gegevens. Meegestuurd `resultaat` vervangt de complete lijst; de API bewaakt de vijf toegestane keys, maar confidence/pagina/sleutel hebben geen verdere typevalidatie in deze handler. Geef daarom bewust de bestaande sleutel, tekst of null en confidence tussen0en1 op. Een ontvangst bewijst geen inhoudelijk juist extractieresultaat.

De importcollectie bevat alleen leesverzoeken en een standaard geblokkeerd fictief profiel met handmatig veld. Geen betaalde extractie of goedkeuring wordt automatisch gestart.


## Huisstijlsjabloon per documentsoort

Acht broncontracten beschrijven offerte, rapport, email en gespreksverslag: lezen, uploaden, ontvangst, previewlink, goedkeuren, merkfont, kleur/fontaanpassing en cover. Uploaden kan betaalde vision gebruiken. Font, aanpassing en cover maken een nieuw concept met lokale rendering. Een202startantwoord zegt altijd `bezig`, ook bij herhaling; lees de ontvangst voor werkelijke voortgang.

De oorspronkelijke idempotentiesleutel gebruikt8–128tekens zonder dubbelepunt. Tijdelijke input en basissnapshot hebben7dagenretentie; een startreplay daarna geeft409. De inhoudsvrije ontvangst kan daarna nog beschikbaar zijn. Het nieuwste concept is niet noodzakelijk de actieve stijl. De selectief overgedragen leesfix61b786b3 geeft bij sjabloon- of versiequeryfouten503 sjabloon_onbeschikbaar. Alleen een werkelijk ontbrekend sjabloon geeft200 met null.

De previewroute geeft een signedURL van300seconden met `preview_hash` en registreert meteen de huidige actor als laatste kijker. Dat bewijst de linkaanvraag, geen daadwerkelijke PDFdownload of menselijke beoordeling. Goedkeuren vereist dezelfde actor, exacte hash en `bevestigd:true`; de opgeslagen actieve basis wordt opnieuw vergeleken. Na verloren antwoord eerst status lezen. De collectie voert geen preview/goedkeuring automatisch uit.

Een merkfont vereist expliciete licentiebevestiging en maximaal2MiB WOFF2/WOFF/TTF/OTF. Insluiting geldt alleen voor PDF. CoverHTML is maximaal32000tekens en wordt gesaneerd; leeg wist de cover. De canonieke kleur/fontbody is beschreven, historische tolerante inputvormen blijven als gedeeltelijk schema gemarkeerd. Geen publicatie of runtimecontrole uitgevoerd.

## Bestaande taalvarianten lezen

De selectieve bron `99c1da9a` voegt drie GETcontracten toe: gesprekstatus, rapportstatus en concrete taaluitkomst. De status bevat gevraagde taalkeuzes, opgeloste talen, actieve selectie en historie; bij de beschreven native fallback kunnen beleidsvelden ontbreken. Historie bevat geen oud creditsveld. Gebruik eigen verbruik voor actuele kosten.

Lees per uitkomst `contentAvailable`. De inhoudsroute levert alleen `language`, `outcome`, tekst/null en `artifactId`. Geen opslagpaden of `artifactRefs`; documenten gaan via bestaande geauthenticeerde resultaatdownloads en actuele objectrechten. Bron- en actorrechten worden vóór en na het lezen gecontroleerd. Niet gereed409, onzichtbaar404 en onbetrouwbare bron503. Geen queryparameters toegestaan.

De collectie voegt uitsluitend drie leesverzoeken toe. Betaalde taalstart, beleid en retry zijn niet als voltooid onderdeel van de volledige nieuwe API beschreven. De oude route blijft een bestaande bronroute, maar publicatie wacht op veilige vervanging en tests.

## Stijlen v2: regels, versies en betaalde proeftekst

Lees `/v1/stijlen-v2` en `/v1/stijlen-v2/context?document_type=rapport`. Persoonlijke stijlen zijn alleen zichtbaar voor de eigenaar. Organisatie- en documentstijlen wijzigen vraagt daarnaast actuele teampublicatierechten. De context kiest regels in deze voorrang: beschermd, vakstijl, organisatie, document, persoonlijk, opdracht. Een hogere laag wint bij dezelfde sleutel.

Maak voor een fictieve oefening met een nieuwe idempotentiesleutel een persoonlijke stijl:

```json
{"naam":"Oefenstijl Atlas","laag":"persoonlijk","bron":"begeleid","antwoorden":{"toon":"zakelijk","aanspreekvorm":"je"},"regels":[]}
```

Aanmaak en versiepublicatie zijn modelvrij. `201` betekent nieuw, `200` een herhaalde ontvangst. Bewaar `ontvangst.stijl_id` en `ontvangst.versie_id`; de teruggegeven `stijl` beschrijft steeds de huidige actieve versie. Publicatie via `/{id}/versies` vereist de gelezen `basis_versie_id`, naam en regels en maakt de nieuwe versie direct actief. Een herhaling levert de oorspronkelijke versie naast de huidige stijl; overschrijf daardoor niet onbedoeld nieuwere keuzes. Gebruik voor een volgende operatie een nieuwe opdrachtcode. Bestaande versies terugzetten vraagt afzonderlijk `versie_id`, actuele basis en `bevestigd:true`.

Een stijltest via `/{id}/test-aanvragen` is een betaalde productieactie met credits, budget en actuele rechten. Geef een fictieve voorbeeldtekst van20–3000tekens of één bestaand zichtbaar gereed gesprek op. Geef geen eigen `aanvraag_id` mee: de API bepaalt die uit de sleutel. Lees na202 de eigen `/test-aanvragen/{jobId}`; start niet opnieuw bij wachten. De worker bewaakt tien pogingen per actor en UTC-dag. Het resultaat bevat tekst, toegepaste regels, versie-IDs en eventuele broninkortingswaarschuwingen. Na30dagen vanaf jobaanmaak geeft een geslaagd resultaat410. Onzeker providercontact geeft geen automatische toestemming voor een nieuwe poging.

Feedback is eenmalig per eigen test, met score1–5 en maximaal500tekens opmerking. De server bewaart alleen de hash van die opmerking. Een herhaling na beoordeling geeft 404; behandel dit niet als toestemming om een nieuwe test te maken. `POST /{id}/analyse` leest bestaande analyse en start geen AI, maar heeft geen afzonderlijke proefperiodevrijstelling in de actiecatalogus.

De contextquery voor geneste opdrachtregels en historische tolerante normalisatie blijven expliciet gedeeltelijk beschreven. De native beheer- en synchrone testroutes staan niet in deze externe API-catalogus. Alle beschreven antwoorden zijn broncontracten; import en uitvoering zijn nog niet getest.

Bij deze drie taalGETs controleert de server vlak vóór antwoord opnieuw de sleutel, activatie, pauze, verval, recht/plafond, actorrol, organisatie en pakket. Een intrekking tijdens het lezen geeft403 api_leesdelegatie_geweigerd; een onleesbare controlebron geeft503.

## Mailmeldingen volgen

De webhookhandleiding beschrijft nu ook `mail.geaccepteerd`, `mail.onzeker`, `mail.mislukt` en `mail.afgeleverd`, met een eigen outbox-/pogingverwijzing. Provideracceptatie is geen bezorgbewijs. Alleen een ondertekend Resendbewijs bij de juiste eigen mail kan `mail.afgeleverd` geven; handmatig bevestigen en Gmail/M365 doen dat niet. Gebruik de bijbehorende Node.js-ontvangerbouwsteen en bewaar event-IDs duurzaam. Bron3897cbd9; niet uitgevoerd of gepubliceerd.

## Documentformat kiezen zonder generatie

Lees `GET /v1/documentarchetypen` voor de vier universele documentformats en hun relatieve voorbeeldbestanden. Presentaties hebben een eigen register via `GET /v1/presentatie-archetypen`. Het veld `vrijgegeven` is een featurevlag; de uiteindelijke generatie blijft afhankelijk van alle actuele rechten en vrijgaven.

Lees `GET /v1/documentarchetypen/voorkeur` voor de organisatievoorkeur en bewaar de volledige quoted ETag. Binnen deze externe API kan alleen de organisatie-eigenaar die voorkeur wijzigen via PUT, met `If-Match`, `registryVersie: rapportly-archetypen-v1` en een `archetypeKey` uit het register. `null` herstelt automatisch kiezen. Bij409 opnieuw lezen; na een verloren antwoord ook eerst lezen. Deze route heeft geen apart Idempotency-Keycontract.

`POST /v1/documentarchetypen/selecties/controleren` leest welke keuze zal gelden. Expliciet universeel geeft het gekozen format terug. Automatisch gebruikt eerst de organisatievoorkeur, anders een stijlsignaal en ten slotte het documenttype. Dit bewaart niets en genereert geen document. De collectie bevat een fictief voorbeeld en houdt ook deze POST standaard tegen totdat je verzoeken bewust inschakelt.

## Excel veilig voorbereiden en invullen

De basisroutes beschrijven beschikbaarheid, bronlijst, upload, download, pagina-afbeelding, beeldkeuzes, controle, voorbeeld, akkoord, invullen, hervatten en verwijderen. Het objectleesmodel met historische analyses en de afzonderlijke betaalde bronvoorstellen staan in de volgende hoofdstukken. Uitvoering en importvalidatie blijven open.

Elke Excelmutatie vereist `X-Rapportly-Client-Version`; ontbrekend of ongeldig geeft426. Gebruik de vrijgegeven versie-identificatie van je client. Upload één lokaal fictief xlsx/xlsm/xls-bestand van maximaal25MiB met naam en modus `sjabloon` of `aanvullen`. Bewaar de ontvangst-ID.201bewijst opslag; een bron met een onderzoeksprobleem kan nog niet invulbaar zijn.

Controle en invullen accepteren maximaal16MiB ongecomprimeerde JSON. Bevestig per cel vast, invoer, berekening of leeg; formules blijven beschermd. Vaste en eventueel passieve onderdelen vereisen akkoord. Maak daarna een synthetisch voorbeeld, bekijk het bestand en keur pas dan goed met de `inhoudHash` van de controle en de `bestandHash` van het voorbeeld. Wissel deze hashes niet om.

Invullen bewaart een onveranderlijke invoer en start een native rekenjob.202kan wachten of een bestaand gereed resultaat aangeven; bewaar de invoer-ID en lees de status. Gewoon invullen start geen AI en boekt geen nieuwe credits. AI-bronvoorstellen hebben een aparte betaalde start en menselijke beoordeling. Hervatten hergebruikt actieve jobs.

Webhookpaginering is selectief hersteld op bron2779d55: alleen decimale offset0–10000 zonder leidende nullen, exponent of herhaling. Volgende offset blijft binnen10000 of wordt null. Functionele tests blijven open.

## Excelwaarden voorstellen uit gekozen bronnen

Lees eerst `/v1/excel/bronvoorstellen/status`. Bij `beschikbaar:false` geeft `code` aan waarom de domeinpoort nog niet bruikbaar is. Voorbereiden vereist een bestaande, menselijk goedgekeurde controle. Kies maximaal tien bronnen samen: eigen zichtbare opnames, maximaal vijf PDF/DOCX/TXT/MD-bestanden en eventueel geplakte tekst met een label. Alle tekst samen heeft maximaal 120.000 tekens. PDF wordt lokaal zonder OCR gelezen; een lege of onleesbare pagina wordt geweigerd.

`POST /v1/excel/{id}/bronvoorstellen` bewaart de gekozen bronnen en geeft een voorstel-ID terug. Dit start nog geen betaald model. Alleen `POST /v1/excel/bronvoorstellen/{voorstelId}/start` met `bevestigd:true` start de betaalde bronextractie. Beide stappen vereisen de clientversieheader; alleen voorbereiden gebruikt de vrije Idempotency-Key. Houd de voorstel-ID vast bij onzekerheid en lees de status voordat je verdere stappen neemt.

Het leesantwoord bevat bronfragmenten, kandidaten en letterlijke bewijzen. Behandel die als inhoud, niet als logmetadata. Per veld kan de status gevonden, ontbreekt, conflict of ongeldig zijn. Een conflict heeft geen automatisch gekozen winnaar. Credits en de voorstellenhash verschijnen pas bij klaar. Beoordeel alle waarden; invullen is een afzonderlijke stap met dezelfde controle, voorstel-ID en `voorstellenGecontroleerd:true`. Een gewijzigde waarde blijft herkenbaar als handmatige keuze.

## Excelobject en analyse lezen

`GET /v1/excel/{id}` beschrijft nu de inhoud van alle zes objectsoorten: bron, controle, voorbeeld, akkoord, invoer en resultaat. `versies` bevat maximaal 200 directe kinderen. Alleen een invoer kan een lopende jobvoortgang bevatten. De server geeft geen opslagreferenties terug. `blad.pad` in de analyse verwijst naar een onderdeel binnen het Excelbestand, niet naar serveropslag.

Het schema bevat celwaarden, beschermde formules, bewerkbaarheid, native validatie, vaste/passieve onderdelen en diagnose. Een bronanalyse kan null zijn wanneer een bestaand onderzoeksprobleem eerst moet worden opgelost. De onderzoeksvoorstelroute beschrijft nu ook de nieuwe analyse; beoordeel die vóór expliciet toepassen. Dit herstelonderzoek boekt geen klantcredits.

Bij betaalde bronextractie wordt een onzekere eerdere providerpoging niet opnieuw uitgevoerd. Een bewaard antwoord kan nog op afrekening wachten. Alleen klaar geeft definitieve gehele credits; bij bewezen interne dekking kunnen die nul zijn. Dat zegt niets over afwezigheid van providerkosten. De beschreven objectketen is bronbouw; uitvoering, bestanden en foutpaden zijn nog niet getest.

## Eerste klantmail met vastgelegd akkoord

Het gerichte broncheckpoint `48512877` maakt dezelfde gecontroleerde keten beschikbaar voor de eerste klantmail. Vraag eerst `/mail/voorbeeld` met `mailsoort: klantmail`. Een vrije `mail` is hier niet toegestaan: het voorbeeld gebruikt de opgeslagen klantmail of een bestaande customerEmail-taalvariant. Het antwoord bevat `versiecontrole:true`, `mailsoort`, `basis`, `review_hash`, `afzender` en de bestaande `outbox` of null. Ontbreekt een benodigde afzender of bijlage, dan volgt een fout. Bestaand herstel lees je dan via de afzonderlijke outboxroute.

Beoordeel de exacte ontvanger, afzender, tekst en bijlagen. Goedkeuren vereist voor beide mailsoorten `basis`, `review_hash` en `bevestigd:true`. Kopieer die waarden uit hetzelfde voorbeeld en behoud de overige aanvraagvelden. De collectie gebruikt lege basis/hashvelden, een ongeldig oefenadres en geblokkeerde mutaties; er is niets verstuurd. Een echte verzendproef vereist later een bewust gekozen eigen testadres in een vrijgegeven omgeving.

Een exacte retry geeft de oorspronkelijke outbox-ID met de huidige status terug. Dat ontvangstbewijs kan `wacht_tot` weglaten. Eerste klantmail en followup hebben elk een eigen ontvangst. Een oude verzonden, lopende of onzekere mail wordt hiermee niet opnieuw aangeboden. `kan_goedkeuren` beschrijft alleen een nog nooit aangeboden rij; `herstel_mogelijk` hoort bij de huidige actor en dezelfde mailsoort. Een legacy onzekere rij zonder snapshot geeft `mail_legacy_herstel_verplicht`. Dit is geen toestemming om blind opnieuw te verzenden.

Akkoord bindt maximaal 100 unieke bijlagen en in totaal 15 MiB aan exacte bytes, plus de afzender en inhoud. De verzendpoging hercontroleert rechten en diezelfde gegevens. Provideracceptatie, handmatig bevestigd en daadwerkelijk afgeleverd blijven verschillende statussen. Alleen het beschreven ondertekende afleverbericht kan een Resend-aflevering bewijzen. Bouwstatus: geschreven, geen uitgevoerde verzendproef of liveclaim.

## Workflowrun: ontvangst, menselijk akkoord en werkelijke productie

De acht uitgewerkte runneracties gebruiken bron `cd6dcaf4`. Een uitvoeringversie en een productierun zijn verschillende objecten. POST `/v1/uitvoeringen/{id}/productieruns` bewaart een run op de actuele reviewbasis. Een nieuwe run wacht op menselijke bronbevestiging. `bevestigd:true` in de API-aanvraag vervangt die inhoudelijke beoordeling niet. Daarvoor moet een bevoegde ingelogde gebruiker de native bediening gebruiken. De API heeft geen bevestigen-route.

GET `/v1/workflowruns/{runId}` geeft de huidige runstatus, basis, versie en gebonden hoofd-/opmaakjob. Gebruik voor een bewuste mutatie die exacte basis plus versie en een stabiele Idempotency-Key van 16–128 veilige tekens. Een historische herhaalontvangst is geen actuele voortgang; lees de run daarna opnieuw. Het startantwoord is HTTP200, zonder belofte dat de provider heeft gedraaid. Een nieuwe opdrachtcode maakt geen tweede run voor dezelfde uitvoeringversie.

Uitvoeren, pauzeren, hervatten, herstellen en annuleren hebben elk hun eigen toestandseisen. Pauze voorkomt verdere nieuwe stappen bij de volgende controlepoort; een reeds lopende provider kan nog kosten maken. Hervatten bewaart dezelfde job en pogingteller. `herstel_zonder_provider` gebruikt alleen bewezen opgeslagen inhoud en weigert nieuwe providerkosten; ontbrekende cache blijft een fout. `offerte_afmaken_mogelijk` herstelt alleen de bestaande offertemetadata en nummerontvangst. Een onzekere provideruitkomst is geen toestemming om automatisch opnieuw te starten. Na verlopen proefperiode blijven pauzeren en annuleren toegestaan, met overige rechtencontroles.

Download alleen wanneer de run canoniek klaar is. `/download/pdf`, `/download/docx` en voor een gebonden presentatie `/download/pptx` geven een link voor 60 seconden. Download apart zonder API-sleutel. PDF/Word volgen latere native revisies; een bijgewerkte tekst betekent geen nieuwe PowerPoint. Zowel de runtimevrijgave als de volledige-APIvrijgave moeten afzonderlijk aanstaan. Dit checkpoint activeert niets. Productiecontext met volledige snapshot, uitvoeringsversies en import van offertregelbewijzen krijgen hun eigen volgende schemas; de inventaris houdt ze open.

## Offertregelbewijzen vóór productie

POST `/v1/uitvoeringen/{id}/offerte-regelbewijzen` importeert een echte, nog geldige native catalogus- of routebevestiging. De body bevat uitsluitend `offerte_invoer` in schema2, met concept-ID, onderwerp, voorwaarden en maximaal 50 regels. Minstens één regel moet een bevestigde catalogus-/routeregel zijn; volledig geprijsde handmatige regels mogen erbij. Een uitsluitend handmatige offerte gebruikt de rechtstreekse productiekeuze. De import berekent geen nieuwe route, start geen provider en claimt geen offertenummer.

Gebruik de huidige uitvoering-ETag als `If-Match` en een vaste Idempotency-Key van 16–128 veilige tekens. Het expliciete recht `offertes:regelbewijzen` is vereist naast lezen, workflowbeheer en verwerkingsstart, in actuele rechten én plafond. Maximaal 100 imports per uitvoering zijn mogelijk, uitsluitend vóór een productierun bestaat. De aanvraag is begrensd op 200.000 geserialiseerde JSONtekens. De bestaande native validator controleert prijs, hoeveelheid, BTW, geldigheid en actuele catalogus-/workflow-/routeversies.

Het antwoord geeft de bewijs-ID, bewijs-hash, uitvoering, basisversie, gevalideerde regels en native totalen. Bedragen zijn gehele centen, aantallen duizendsten. Dit zijn offertebedragen, geen klantcredits of providerkosten. Ondertekende bevestigingstokens en hun ruwe inhoud worden niet teruggegeven. De collectie laat token, concept, uitvoering en ETag leeg; vul later uitsluitend een eigen actuele testbevestiging in en log die niet.

Na antwoordverlies herhaal je dezelfde body, ETag en opdrachtcode. Een bewezen ontvangst kan ook na tokenverval worden herhaald; een nieuwe import van een verlopen token weigert. Dezelfde actor, oorspronkelijke sleutel, uitvoering, concept en actuele toegangsrechten blijven vereist. Gebruik daarna de bewijs-ID als `productiekeuze.offerte_regelbewijs_id`, zonder daarnaast `offerte_invoer`. De volgende uitvoeringversie en de menselijke productiebeoordeling moeten die exacte berekening vasthouden. Volledig geneste uitvoerings-/productiecontext wordt nog afzonderlijk beschreven; deze nieuwe import is geschreven en niet uitgevoerd.

## Uitvoeringversies en huidige productiecontext

Bron `579b18e8` voegt de actuele uitvoeringlijst, versiehistorie, leesmodellen, contextstart, opdrachtwijziging, broncontrole, bronbevestiging en faseovergang toe. GET `/v1/uitvoeringen` geeft maximaal 50 metadataregels per pagina; gebruik de teruggegeven cursor. GET `/v1/uitvoeringen/{id}/versies` gebruikt een eigen positief versienummer als cursor en geeft maximaal 50 eerdere versies. Een uitvoeringfase is geen bewijs dat de documentproducer heeft gedraaid.

Een contextstart gebruikt een bestaand klaar Rapportly-rapport en krijgt HTTP201. Bewaar uitvoering-ID en ETag. Opdrachtwijziging en bronhandelingen vereisen de exacte huidige `If-Match` en een vaste opdrachtcode. Bij antwoordverlies herhaal je exact dezelfde body en ETag; na een echt conflict lees je eerst opnieuw. De context bewaart de opdracht, bronmanifest, bronhashes, stijl-/workflowversies, eventuele organisatie-instructie en productiekeuze. Historische ontvangst en huidige versie blijven afzonderlijk.

De broncontrole gebruikt alleen huidige opgeslagen bronnen, antwoorden en gekozen bronversies. Per antwoorden-/bronkeuzesobject gelden maximaal 100 sleutels en 20.000 UTF8bytes. Een gewijzigde bronbasis voorkomt opslag onder de oude beoordeling. Een afzonderlijke bronbevestiging registreert één exact gecontroleerd punt; dit vervangt geen menselijke bevestiging van de productierun. Fases mogen uitsluitend via de beschreven overgangen veranderen. Een overgang naar definitief vereist een geverifieerde rapportversie en produceert of verstuurt zelf niets.

GET `/v1/uitvoeringen/{id}/productie` toont de huidige snapshot, generatiekeuze, eventuele bronblokkade en eigen run. Een blokkade maakt de startbasis null. De historische `prijsgevolg` is een rapportcontextschatting en geen actuele offerte-/presentatieprijs of boeking. Offertebedragen komen uit `offerte_snapshot.calculation`; werkelijke credits en providerkosten blijven in hun eigen kostenketen.

Alleen een rapport accepteert `productiekeuze:{documenttype:'rapport',begeleidende_brief:true}`. Een formulierbron weigert die briefkeuze. De brief is een gebonden deelstap van dezelfde native rapportproductie en geen mailverzending; `generatiekeuze.begeleidendeBrief` toont de keuze. Presentatie en offerte hebben hun eigen expliciete stijl/inhoud. `taalvervolg` blijft in de oorspronkelijke productiecontext false; een latere vertaling gebruikt de afzonderlijke taalproductieroutes hieronder. Neutrale stijl en canonieke offertregelbewijzen zijn beschreven; enginegebonden doelidentiteiten en historische retentie-/goedkeuringsvarianten houden de desbetreffende routes nog gedeeltelijk. Geen eindcontrole of uitvoering is gedaan.

## Opgeslagen rapportrevisies vergelijken

GET `/v1/uitvoeringen/{id}/verschillen` gebruikt de aangesloten bron `af35221c` plus `9bab4bc9`. Stuur geen queryparameters; ook een onbekende parameter geeft HTTP 400. Dit vervangt de eerdere documentatie waarin de adapter nog ontbrak. Het is geschreven bron, geen geteste of gepubliceerde functionaliteit.

De nieuwste eigen run voor deze uitvoering moet klaar zijn en een rapport opleveren. Als een nieuwere run nog loopt, gebruikt de route niet een oudere klare run. Zowel het vastgelegde workflowprofiel als de huidige actieve, goedgekeurde en beschikbare profielversie moeten volledige interne vergelijking expliciet toestaan. Huidige sleutel-, actor-, organisatie-, bron- en rapportrechten blijven vereist.

Het antwoord is óf `beschikbaar:false` met een concrete `reden_code`, óf `beschikbaar:true` met `verschil`. Dat object bindt `uitvoering_id`, `run_id` en `rapport_versie_id` aan twee opeenvolgende opgeslagen rapportinhoudsrevisies: `van_versie` en `naar_versie`. Het vergelijkt uitsluitend huidige rapportmarkdown en de directe voorganger, maximaal 2 MiB geldige bronbytes per revisie. De huidige inhoud moet overeenkomen met de actieve pointerhash.

Bij gelijke teksten is `gewijzigd:false` en `blok:null`. Anders bevat één blok `oud` en `nieuw`, elk met regelnummers, tekst en `ingekort`. Het blok loopt van de eerste tot de laatste afwijking en kan ongewijzigde tussenregels bevatten; het is geen telling van afzonderlijke wijzigingen. Elk fragment heeft maximaal 8.000 Unicodecodepunten. Een zuivere invoeging of verwijdering kan aan één kant lege tekst en een eindregel vóór de beginregel geven. Open de bewaarde versie voor de volledige inhoud als een fragment is ingekort.

De zes niet-beschikbaarredenen onderscheiden uitgeschakeld beleid, nog niet klaar resultaat, niet aangesloten documentsoort, geen vorige inhoudsrevisie, ontbrekende/te grote historie en intussen gewijzigde historie. Leesfouten of onbetrouwbaar hashbewijs geven 503; gewijzigde basis tijdens lezen kan 409 geven. Rechten, beleid, run, actieve pointer en historie worden opnieuw gelezen vóór antwoord. Brief, bronnenlijst, opmaak, andere documentsoorten en uitvoeringssnapshots vallen buiten deze vergelijking. Er start geen model, render of mutatie.

## Eerste klantmail als mailboxconcept

Bron `c141e025` beschrijft vier afzonderlijke routes. Lees eerst GET `/v1/gesprekken/{id}/mail/concepten` met `berichten:verzenden`. Bewaar de actuele `basis`. Het antwoord bevat maximaal 100 eigen ontvangsten, gebonden aan de oorspronkelijke sleutel en actor. De native legacyfallback is geen API-antwoord.

Kies bewust Outlook of Gmail en gebruik POST op dezelfde route met `/outlook` of `/gmail`: `{aanvraag_id,basis,bevestigd:true}`. Maak één aanvraag-UUID en bewaar die bij deze exacte invoer; optioneel kiest `language` een bestaande variant. Er is geen Idempotency-Keyheadercontract. De opgeslagen eerste klantmail en alle bijlagen worden gebruikt; je kunt geen ontvanger, vrije inhoud of URL meesturen. Grenzen zijn 100 bijlagen samen 15 MiB, MIME 24 MiB en voor Outlook een aanvullende applicatiegrens van 4 MiB op de base64-body. Een te groot verzoek wordt vóór providerstart geweigerd, zonder bijlagen stil over te slaan.

HTTP 200 met `aangemaakt` bewijst alleen dat een concept is opgeslagen. HTTP 202 met `onzeker` of `gestopt` blijft herstelplichtig. Gebruik na antwoordverlies dezelfde aanvraag-ID, provider, basis en taal. Maak bij onzekerheid geen tweede aanvraag: ook een nieuw ID omzeilt de blokkade niet. Open zo nodig de vaste conceptenmaplink om zelf te controleren. Ontvanger invullen en verzenden zijn latere bewuste handelingen in de mailbox. `verzending` blijft `niet_aangevraagd`; dit is geen aflevermelding.

POST `/v1/gesprekken/{id}/mail/concepten/stoppen` gebruikt alleen `{aanvraag_id,bevestigd:true}` en geeft HTTP 200 met de actuele ontvangst. Stoppen is na een verlopen proefperiode toegestaan, maar nieuwe conceptaanmaak niet. Het stopt nieuwe providerstart bij de laatste controle, verwijdert geen concept en annuleert geen reeds lopend providerverzoek. Een later bewezen providerantwoord kan alsnog `aangemaakt` opleveren. De importvoorbeelden houden aanvraag-ID, basis en sleutels leeg en mutaties geblokkeerd. Ze zijn niet uitgevoerd.

## Taalvoorkeur bewaren en bestaande brief lezen

GET `/v1/rapporten/{id}/taalbeleid` of `/v1/gesprekken/{id}/taalbeleid` geeft de huidige `basis`, `policyVersion` en `requestedSecondary`. Rapporten hebben `report` en `coverLetter`; gesprekken hebben `conversationReport`, `customerEmail` en `followUpEmail`. Een ontbrekende opgeslagen keuze staat expliciet op `off`. Kies per uitkomst `off`, bewust `inherit`, of `specific` met een concrete kleine taalcode van twee of drie letters.

PATCH op dezelfde route bewaart `{secondary,basis,policyVersion,bevestigd:true}` met `voorkeuren:wijzigen` én `resultaten:lezen`, een geldige proefperiode/pakket en Idempotency-Key van 8–128 veilige tekens. Stuur alleen de te wijzigen uitkomsten; de overige keuzes blijven behouden. Neem basis en versienummer uit het zojuist gelezen antwoord over; het collectievoorbeeld met versie 0 is alleen passend als de read die waarde geeft. Dit start geen provider: `productie_gestart:false` en `start_productie_afzonderlijk:true` blijven expliciet. Het verandert de primaire brontaal niet.

Bij exact herhalen geeft `ontvangenPolicyVersion` de versie van de oorspronkelijke ontvangst. De andere beleidsvelden tonen de huidige toestand en kunnen inmiddels gewijzigd zijn. `changed` staat alleen in een nieuwe ontvangst, niet in een replay. Een echte versieconflict vereist opnieuw lezen. Betaalde taalstart/retry en workflowbediening staan in de volgende hoofdstukken; deze voorkeurroute biedt daarvoor geen impliciete start.

De bestaande GET `/v1/taalvarianten/{opdrachtId}/coverLetter` levert nu echte brieftekst via de vaste native referentie. Maximaal 1 MiB geldige UTF8, met actuele bron- en doelrapportrechten en herlezing van variant, opdracht en sleutel. De doelversie moet klaar zijn, in dezelfde dossier/organisatie vallen en van de juiste bron in de opdrachttaal zijn vertaald. Een onveilige referentie, te grote, lege of onleesbare brief geeft geen gedeeltelijke inhoud. Interne opslagpaden blijven verborgen. Alleen documentbestanden gebouwd; geen aanvragen uitgevoerd.

## Bewust betaalde vertalingen starten en volgen

Bron `cfe078af` beschrijft de nieuwe gebonden keten boven de bestaande native taalproducer. De oude betaalde route was al aanwezig; deze documentatie vervangt geen historische route met een fictieve afwezigheidsclaim. Er is geen test- of publicatiebewijs.

Lees GET `/v1/gesprekken/{id}/taalproductie` of `/v1/rapporten/{id}/taalproductie`. Kies uitsluitend beschikbare uitkomsten en een concrete andere taal. POST `/taalvarianten` onder dezelfde bron gebruikt `{language,outcomes,basis,bevestigd:true}`, huidige basis en een vaste Idempotency-Key van 8–128 veilige tekens. De aanvraag vereist actuele verwerking-/leesrechten, tweede-taalbeleid, proefperiode/pakket en persoonlijke werkelijke-kostenmodus. Rapportvertaling kan rapport én brief verwerken, ook als je één uitkomst kiest; lees `verwerkt_uitkomsten` voor die reikwijdte. Providerkosten en klantcredits zijn geen offertebedragen en worden niet als nul of vast tarief gepresenteerd.

Start geeft HTTP 202 met `opdracht_id`, `versie`, `basis`, `status`, `herhaald` en `statusUrl`. Lees daarna die statusroute. Een herhaling gebruikt exact dezelfde body en sleutel; een andere sleutel mag een bestaande native opdracht of doelvertaling niet overnemen. De status heeft aparte verwerking (`status`) en besturing (`besturing`), huidige afwijkingen en herstelvlaggen. Inhoud volgt via de bestaande taalvariantGET. Bron lezen, voorkeur bewaren, vertaling starten en inhoud lezen zijn afzonderlijke handelingen.

POST `/v1/taalvarianten/{opdrachtId}/retry` gebruikt huidige opdrachtbasis, opdrachtversie, `bevestigd:true` en een eigen stabiele sleutel. Alleen veilig vóór providerstart zonder doelrapport, of met volledig bewaarde en afgerekende resultaten, kan herstel doorgaan. In het tweede geval blijft iedere nieuwe providerpoging geblokkeerd. Gedeeltelijke of onzekere uitvoer wordt geen automatische nieuwe betaalde poging. Een eerder opgeslagen providerpogingmarker kan ook na budgetweigering herstel nodig maken.

## Workflowtaal onder 376-v2: lokaal en in CI getest

Bron `a2f438b8` vervangt de oude onvoorwaardelijke workflowblokkade door volledig `taalouder-v2`-schemabewijs. Start, herstart en hervatten blijven409 `taalproductie_ouderretentie_niet_vrijgegeven` geven bij ontbrekend, oud, deels gesloten of onleesbaar bewijs, vóór receipt/queue/provider. Volledige activering, huidige oorspronkelijke key/actor/run/bronrechten, pakket/trial en werkelijke kosten blijven vereist. De CRM-proef bewijst het productiegedrag van deze taalverwerking niet. Bulksecondary blijft gesloten.

GET `/v1/workflowruns/{runId}/taalproductie` geeft voor een ondersteund canoniek klaar rapport `mogelijk:true`, `blokkade:null`, gecombineerde `basis`, `bron` en `opdrachten_meer`; de niet-klare/ongeschikte vorm houdt `basis:null` zonder bron. Context is geen starttoestemming. Start gebruikt context.basis en run.versie, opdrachtbesturing gebruikt opdrachtbasis en opdrachtversie. De drie synthetische voorbeelden staan in de collectie en blijven standaard geblokkeerd.

`startblokkade` is null bij directe of actieve workflowbinding, de ouderretentiecode bij bulk en `taalproductie_ouder_vervallen` bij gearchiveerde workflowherkomst. De bestaande202-expiry draagt alleen een complete terminale, financieel afgeronde ouderketen over naar brongebonden bewijs. Oude replay maakt geen verdwenen run opnieuw aan. Bestaande260/261-klantbevestiging, holds, platformjobretentie en afzonderlijke opslagafronding blijven vereist; geen algemene accountpurgerclaim. Zie [de concrete routes, invoer en bewaarbeperkingen](rapportly-crm-workflowtaal-kandidaat.md).

## Mailboxschema nog niet beschikbaar

Selectieve bron `25aa00db` hercontroleert vóór iedere conceptstatus, stopkeuze en nieuwe conceptaanvraag of het vereiste schema beschikbaar is. Er is geen positieve cache. Onvolledige of afwijkende schemaonderdelen, een leesfout of deadline geven HTTP 503 `mail_concept_schema_onbeschikbaar`, ook bij alleen status lezen of stoppen. Er volgt dan geen nieuwe domein- of providerstart. Een reeds ontvangen providerantwoord kan nog via de bestaande afronding worden vastgelegd. De interne schemacontrole heeft geen publieke API-route en bewijst geen werkende tenantpurge, vrijgave of productieactivatie.

## Actiepunten en followup bewaren

Lees GET `/v1/gesprekken/{id}/followup`. Het antwoord bevat de actuele followupbasis, zichtbare actiepunten met ieder hun eigen `basis`, mailconcept, klant en afzonderlijke followup-outbox. Punten staan op schermvolgorde. Een nog niet klaar gesprek geeft HTTP 200 met `followup:null` en geen punten. Leesfouten in deze volledige bron geven HTTP 500; de automatiseringsinstellingen kunnen afzonderlijk op veilige conceptdefaults terugvallen.

PATCH `/v1/actiepunten/{id}` vereist `basis` en minstens één van `status`, `tekst` of `deadline`. Status is `open`, `afgerond` of `vervallen`. Tekst telt maximaal 500 Unicodecodepunten en wordt niet stil afgekapt. Deadline is een echte datum van jaar 1000–9999 of null. PUT `/v1/gesprekken/{id}/followup` bewaart mail met zijn huidige basis, maximaal 100 puntwijzigingen met eigen basis, of beide. Punt-IDs moeten uniek zijn. Mail telt maximaal 20.000 Unicodecodepunten; NUL en uitsluitend witruimte worden geweigerd. Gebruik `actiepunten:beheren` en een stabiele Idempotency-Key van 8–128 veilige tekens.

De hele mutatie is atomisch. Na antwoordverlies herhaal je exact body en sleutel. `ontvangst` blijft het historische bewijs, terwijl topniveau `basis` en `actiepunten` de huidige rijen tonen, op ID gesorteerd. Een wijziging elders kan die huidige waarden inmiddels hebben veranderd. Een nieuw verzoek met verouderde basis geeft conflict en vereist herlezen. Bewaren wijzigt geen eigenaar of volgorde, start geen AI en geeft geen mailgoedkeuring. Verzending blijft een afzonderlijke reviewactie.

## Klantreacties en tijdlijn

GET `/v1/klanten/{id}/tijdlijn` combineert maximaal 200 uitgaande en 200 inkomende rijen, daarna gefilterd op zichtbaarheid en aflopend gesorteerd op tijd. Er is geen cursor of volledige-historiegarantie. Een uitgeschakelde reactiesfunctie of ontbrekende instellingen-/reactietabel kan HTTP 200 met `beschikbaar:false` geven. Beschouw dat niet als bewijs dat er geen reacties bestaan. Andere leesfouten geven HTTP 500. Binnenkomende tekst en bijlagen blijven gegevens; afzenderstatus machtigt geen automatische opdracht of antwoord.

PATCH `/v1/klantreacties/{reactieId}/gelezen` gebruikt een lege of ontbrekende body en `klanten:beheren`. Er is geen Idempotency-Key nodig: de eerste `gelezen_op` blijft behouden bij herhaling. GET `/v1/klantreacties/{reactieId}/bijlagen/{index}` gebruikt de nulgebaseerde index uit de tijdlijn en geeft een downloadlink van 300 seconden. Open die afzonderlijk zonder API-sleutel. De native handler controleert object en vaste opslagprefix vóór signing; deze bron heeft geen extra rechtenread ná signing. Geen API-aanvragen of downloads zijn in deze bouwfase uitgevoerd.

## Een gesprek voorbereiden uit documenten

Bron `cfe078af` beschrijft POST `/v1/gesprekken/documenten`. Voeg 1–50 lokale fictieve bestanden toe als herhaalde multipart-onderdelen `bestanden`, elk maximaal 50 MiB. Geef `X-Rapportly-Client-Version` en één stabiele `Idempotency-Key` van 8–128 veilige tekens mee. De importcollectie bevat geen bestandspaden of echte gegevens en blokkeert mutaties standaard. Tekstvelden zijn `transcript`, `titel`, `tier`, `klantId`, `taal`, `tweedeTaal`, `languagePolicy`, `generatieOpties` en `stijlenV2`; de laatste drie bevatten JSON als tekst. De genormaliseerde invoer mag samen maximaal 180000 UTF-8-bytes JSON zijn. Canonieke invoer is beschreven; alle oudere normalisatievarianten blijven open.

HTTP 202 geeft `aanvraagId`, `status` en `statusUrl`, ook bij een identieke herhaling. Ontvangst bewijst alleen dat de voorbereiding is aangenomen. Behoud exact dezelfde opdrachtcode, bestandsvolgorde, namen, MIME en bytes bij herhaling. Andere invoer onder dezelfde code geeft een conflict. Na een verloren antwoord lees je GET `/v1/gesprekken/documenten/jobs` met dezelfde oorspronkelijke opdrachtcode, API-sleutel en clientversie. Dit is één ontvangst, geen lijst. Met de ontvangen UUID lees je GET `/v1/gesprekken/documenten/jobs/{aanvraagId}`. Deze route vereist dezelfde oorspronkelijke gebruiker en organisatie plus actuele rechten; de handler voegt daar geen oorspronkelijke-sleutelvergelijking aan toe. Beide leesroutes hercontroleren eventueel klantleesrecht. Na zeven dagen is de ontvangst niet meer beschikbaar.

De statussen zijn `uploaden`, `ontvangen`, `start_bezig`, `klaar`, `mislukt` en `opruimen`. Bij `mislukt` staat er een foutcode. **`klaar` betekent hier dat de gespreksbundel is gestart.** Gebruik daarna `gesprek_id` om de bestaande gesprekstatus te lezen; upload niet opnieuw om op het eindresultaat te wachten. De worker controleert iedere bron en weigert de voorbereiding als één bestand geen leesbare tekst heeft. Een geaccepteerde presentatie- of afbeeldingsextensie bewijst dus geen geslaagde extractie. De gecombineerde tekst moet minimaal 100 JavaScript-tekeneenheden bevatten. Actuele rechten, trial/pakket, credits, persoonlijke werkelijke kostenmodus en duurzame verwerking blijven vereist. Geen vaste prijs, uitgevoerde opruiming, geteste keten of livebeschikbaarheid afgeleid.

## Bestaande documentconcepten lezen en bewerken

Bron `cfe078af` beschrijft vijf routes onder `/v1/rapporten/{versieId}/documentconcept`. Lees eerst de metadata. `beschikbaar:false` is een geldig antwoord als er nog geen concept is; een fout bij opslag wordt geen lege succesmelding. GET `/inhoud` geeft de eigen bewaarde Markdown, leesbare tekst, eventueel gevalideerde structuur en de aangeboden bewerkvelden. Bewaar de exacte `etag`, inclusief dubbele aanhalingstekens. Een concept is een afgeleide revisie; het oorspronkelijke rapport en eerdere inhoud blijven behouden.

PUT `/inhoud` accepteert uitsluitend `{markdown}` of `{wijzigingen:[{sleutel,waarde}]}`. Bij een structuurwijziging gebruik je 1–2000 unieke sleutels uit de laatst gelezen velden, met hetzelfde waardetype. Vaste labels, tabelrelaties, bronverwijzingen en functievereisten kun je hiermee niet verwijderen. `bewerkwijze:structuur` vereist deze aangeboden velden; een losse Markdownvervanging kan dan HTTP 422 geven. De totale publieke JSON-aanvraag is maximaal 100 KiB. De interne inhoudsvalidator van 2 MiB geeft geen grotere uploadruimte. Stuur clientversie, een nieuwe stabiele opdrachtcode van 8–128 veilige tekens en de huidige `If-Match` mee. Wijzigen keurt ontbrekende broncontrole niet goed en start geen opmaak.

Na een verloren antwoord kun je dezelfde aanvraag herhalen. De snelle herhaling geldt alleen als de huidige rij nog dezelfde opdrachtcode en exact dezelfde inhoud heeft; dit is geen algemene belofte voor oude opdrachten na latere wijzigingen. Bij een echt versieconflict lees je opnieuw en beoordeel je de actuele inhoud.

POST `/opmaak` met een lege body vraagt expliciet opmaak of ondersteund inhoudsherstel aan. Ook dit vereist de huidige rechten, geldige trial/pakketstatus, clientversie, opdrachtcode en `If-Match`. HTTP 202 is alleen een aangenomen opmaakactie. Lees de metadata verder; `inhoud_beschikbaar`, `opmaak_bezig`, `gedeeltelijk` en `concept_klaar` blijven verschillende toestanden. `ontbrekendeVereisten` kan bijvoorbeeld een ontbrekende oorspronkelijke vorm of bewerkbare tekst aangeven. Dat een tekst te lezen is, bewijst geen volledige uitvoer.

GET `/download/pdf` of `/download/docx` geeft een tijdelijke privélink van 120 seconden met de huidige inhoud-ID, revisie en bestandsnaam. Word vereist daarnaast de actuele Word-downloadfunctie van het pakket. De dienst controleert de opgeslagen inhoudsbinding en het exacte privépad. Een optionele `bestandsnaam` is alleen een gesaneerd label. De handler herleest rechten niet nogmaals na het aanmaken van de link. Voorbeelden zijn fictief, mutaties staan standaard uit en er is geen ketentest of publicatie uitgevoerd.

## Hersteloverzicht en beeldbank

GET `/v1/documentherstel/overzicht` vereist `gebruik:lezen` en de huidige organisatiebeheerdersrol. Het geeft uitsluitend technische aantallen over de vaste afgelopen 30 dagen, per rapportversie de hoogste in die periode bijgewerkte conceptrevisie. De zes statustellingen tellen op tot `totaal`; meerdere oorzaken kunnen bij hetzelfde rapport horen. Er staan geen namen, rapport-ID's of inhoud in. Een onleesbaar of ongeldig bronresultaat geeft HTTP 503 en wordt geen nuloverzicht. Dit overzicht start geen herstelactie.

GET `/v1/beeldbank` toont maximaal 500 zichtbare beelden, nieuwste eerst: teambeelden en je eigen persoonlijke beelden. De lijst bevat huidig verwijderbeleid, mogelijke acties en gebruik in actieve stijlen. Miniatuurlinks zijn 120 seconden geldig; een mislukte ondertekening kan `preview_url:null` geven. Dit is geen volledige historische gebruiksinventaris.

POST `/v1/beeldbank` accepteert één lokale PNG of JPEG als `bestand`, optioneel `naam` en `deling_scope`. Nieuwe uploads zijn maximaal 5 MiB en 25 miljoen pixels, met maximaal 20000 pixels per zijde. De dienst bewaart een genormaliseerde PNG en miniatuur zonder originele metadata. Kies `persoonlijk` bewust; weglaten betekent `team`. HTTP 201 betekent een nieuwe rij en 200 hergebruik van zichtbare bestaande inhoud. Een bestaand teambeeld met dezelfde hash kan ook een persoonlijk verzoek beantwoorden; beoordeel daarom de teruggegeven `deling_scope`. De upload haalt geen gebruiksinventaris op, zodat `gebruikt_in` in dat antwoord leeg is. Lees de lijst voor huidig gebruik.

PATCH `/v1/beeldbank/{id}` wijzigt naam en/of deling. Alleen de eigenaar kan de deling daadwerkelijk veranderen; een zichtbaar teambeeld kan ook door een ander bevoegd lid worden hernoemd. PUT `/instellingen` met `team_verwijderen_alleen_beheer` vereist een beheerder en bepaalt wie teambeelden mag verwijderen. DELETE `/v1/beeldbank/{id}` geeft HTTP 204 zonder inhoud, ook bij een geldige al ontbrekende of onzichtbare rij. De verwijdermarkering is leidend; opruimen van bytes en quotum gebeurt daarna op best effort. Dit bewijst geen fysieke purge en bestaande bevroren stijlversies behouden eigen kopieën.

Deze beeldbankmutaties gebruiken `stijlen:beheren`, huidige trial-/pakketrechten en een gedeelde limiet van 30 per minuut per IP. Er is voor deze routes geen Idempotency-Key-, ETag- of clientversiecontract. Het importvoorbeeld bevat een lege bestandskeuze en vraagt expliciet een persoonlijk fictief beeld; mutaties blijven standaard geblokkeerd. Bronstatus: geschreven, geen tests of publicatie.

## Herhaalantwoorden van betaalde bijsturing

Bron `cfe078af` beschrijft POST `/v1/uitvoer/rapport/{ankerId}/rapport_markdown/hergenereer` en dezelfde vorm voor de gespreksvelden `verslag`, `interne_mail`, `klantmail` en `followup_mail`. Geef de actuele positieve `basis_versie`, een getrimde instructie van 10–2000 JavaScript-tekeneenheden en een stabiele opdrachtcode van 8–128 veilige tekens mee. Voor een echte nieuwe opdracht gebruik je een nieuwe code na inhoudelijke beoordeling. De collectie gebruikt basisversie 1 alleen als invulvoorbeeld; vervang die door de werkelijk gelezen versie. Alle betaalde opdrachten blijven standaard geblokkeerd in de importcollectie.

Bij een rapport geeft HTTP 202 `mutatie_id`, `taak_id`, `status:bezig` en `creditmodus:persoonlijke_api_kosten`. Bewaar de mutatie-ID. Bij een herhaling die inmiddels is afgerond kan HTTP 200 volgen met alleen `ok`, `versie_nummer`, `tier` en `creditmodus`; de IDs komen dan niet nogmaals mee. Een opgeslagen terminale fout geeft de oorspronkelijke foutstatus, bijvoorbeeld 402, 409, 429 of 502. Deze antwoorden bevatten geen rapporttekst en geen actueel saldo.

Een gespreksveld blijft ook bij een afgeronde herhaling HTTP 202 geven. Lees daarom `status`: `bezig`, `klaar`, `mislukt` of `controle_nodig`, naast `fase:ontvangen|schrijven|opslaan`. Bij `klaar` kan het opgeslagen versienummer volgen; bij een fout kan `code` volgen. Het bijsturen van mailtekst verstuurt geen bericht.

GET `/v1/uitvoermutaties/{id}` vereist de oorspronkelijke API-sleutel, gebruiker en organisatie en actuele objectrechten. Deze route gebruikt de technische statussen `queued`, `processing`, `succeeded`, `failed` en `reconcile_required`. Dit onderscheid is vooral bij een rapport nodig: zijn startantwoord kan nog `bezig` zeggen terwijl herstelcontrole nodig is. Omzeil een onzeker resultaat nooit met een nieuwe betaalde opdrachtcode. Na succes lees je de actuele uitvoertekst en historie. Opgeslagen creditvelden uit oudere interne afrekening zijn geen prijsbelofte; daadwerkelijke kosten lees je via gebruik. Geen test of publicatie uitgevoerd.

## Wat een eerste generatieontvangst bewijst

De huidige bron `cfe078af` geeft voor POST `/v1/rapporten`, `/v1/offertes`, `/v1/presentaties` en `/v1/gesprekken` **HTTP 200 met een duurzame ontvangstbevestiging**. Dit zegt niet dat de inhoud al klaar is. Documenten geven `versie_id` en `versie_nummer`; gesprekken geven `gesprek_id`. De huidige startvorm geeft geen `job_id` en geen terminale `status`. Gebruik de bestaande bronstatus- en downloadroutes om de verwerking te volgen.

De ontvangst bevat de primaire taal, aangevraagd taalbeleid, opgeloste uitkomsttalen, beleidsversie, tier en lengteband. Nieuwe volledige API-starts gebruiken `creditmodus:persoonlijke_api_kosten` en `credits_schatting:null`; dit is geen nulprijs. Een neutraal document kan `voorbeeldprofiel:{id:null,versie_id:null}` geven. De twee variantlijsten zijn in deze startontvangst altijd leeg, ook bij herhaling. Lees de afzonderlijke taalstatus voor daadwerkelijk aanwezige vertalingen. Een eventuele `taalbeleidWaarschuwing` betekent dat het document kan doorgaan terwijl een tweede-taalvoorkeur niet veilig is vastgelegd.

Bij een verloren antwoord behoud je dezelfde opdrachtcode en invoer. Een herhaalde aanvraag kan hetzelfde doel hergebruiken; gewijzigde bron-, stijl- of taalcontext kan alsnog tot een conflict leiden. Een herhaalde start is geen opdracht om een mislukte terminale worker opnieuw te starten. Documentstarts kunnen `Idempotency-Replayed:true` teruggeven. Voor gesprekken belooft deze bron die header niet.

Een gestructureerde offerte kan daarnaast `offerte_snapshot:{id,sha256}` teruggeven. Een exact voltooide offerteclaim kan zijn eerdere opgeslagen antwoord al teruggeven vóór nieuwe profiel-/catalogus-/tokencontrole; algemene publieke toegangscontroles blijven ervoor staan. Is de offerte gestart maar het snapshot of herhaalantwoord nog niet veilig vastgelegd, dan kan HTTP 503 toch een `versie_id` bevatten. Maak dan geen tweede offerte met een nieuwe code. Historische offerteclaims bewaren een 2xx-status en JSON-object zonder volledige huidige DTO-normalisatie; alle oudere antwoordvarianten blijven daarom expliciet open. De nieuwe schemas beschrijven de huidige producent en zijn nog niet getest of gepubliceerd.

### Wat een vastgezette documentstijl bevat

Een workflow kan de gekozen profielversie met haar renderidentiteit bewaren. De vorm verschilt per engine: een klassiek profiel, een Word-template, een PDF-bronstijl of een PowerPoint-template. De concrete hash- en versievelden en de Word-/PowerPoint-capaciteiten staan nu in OpenAPI. Bij Word zijn onder meer kopniveaus, tabellen, lijsten en de eventuele formulierprojectie vastgezet. Bij PowerPoint gaat het om beschikbare layouts, tekstvakken en tabel-/grafiekgrenzen. Deze grenzen beschrijven wat de vastgezette renderer kan verwerken; ze bevestigen geen voltooide documentproductie.

De actuele PowerPoint-producent gebruikt maximaal 200 dia’s en maximaal vier grafiekreeksen met twaalf punten. De bron accepteert daarnaast een specifieke oudere dia-limiet wanneer de rest van de bevroren identiteit exact gelijk is. De Word-manifestfallback kan ontbrekende Markdown-capaciteiten als null teruggeven; leid daar geen werkende renderroute uit af. Historische geneste voorbeeldmanifesten en herkenningsgegevens blijven uitdrukkelijk gedeeltelijk beschreven. Huidige profielrechten, actieve versie, keuzehash en de eigen rendercontroles blijven van toepassing.

### CRM-instellingen, bezoekstatus en mutaties

GET `/v1/klanten/crm-instellingen/{soort}` leest actuele revisie en maximaal30 opgeslagen JSONwaarden. GET `/v1/klanten/{id}/crm-bezoek` houdt met schrijfmodus uit de bestaande sinds/tot-vorm; met CRM-schrijfmodus aan bevat het antwoord ook revisie. Deze read markeert niets als gelezen of goedgekeurd.

De vier schrijfcontracten voor sjablonen, zoekopdrachten, bezoek en traject zijn afkomstig uit `d964db8c` en zijn onder de beschreven releasevoorwaarden beschikbaar. De productieproef omvat drie schrijfroutes; sjablonen zijn uitsluitend gelezen. Ze vereisen de CRM-vlag, volledige privacy375-readiness, huidige rechten, bevestigd:true en Idempotency-Key16–128. Instellingen vervangen de volledige lijst; bezoek gebruikt de herlezen servergrens/revisie. Replay geeft huidige toestand plus oorspronkelijke ontvangst, zonder oude instellingen terug te zetten. Stale basis en andere invoer onder dezelfde code geven409. Offboarding blokkeert schrijven; de365dagen-keuze bewijst geen aangesloten algemene accountpurger. Zie [contracten en veilige synthetische voorbeelden](rapportly-crm-workflowtaal-kandidaat.md). De importcollectie houdt mutaties standaard uit.

### CRM-pagina’s vervolgen zonder resultaten over te slaan

`GET /v1/klanten/crm-werk` toont maximaal tien klanten met elk maximaal 25 open actiepunten. Gebruik `pagina.volgende` voor de volgende klantenpagina. Meer punten van één klant lees je met `klantId` en `actiepuntNa`, zonder klantcursor `na`. De volgorde is UUID, niet deadline. Opgeslagen CRM-gegevens blijven JSON binnen een vaste envelop.

`GET /v1/klanten/{id}/crm-reacties` selecteert maximaal vijftig kandidaten en past daarna de huidige bronrechten toe. Een lege lijst kan daarom nog `pagina.meer:true` hebben. Gebruik altijd de servercursor, ook wanneer die niet bij een zichtbaar item hoort. De pagina’s vormen geen vaste momentopname en bieden geen totaaltelling. Historische kantoorreacties kunnen bij ingetrokken vrijgaven blijven staan zolang het onderliggende stuk nu nog leesbaar en deelbaar is; ze openen het klantportaal niet opnieuw.

De bestaande `GET /v1/uitvoermutaties/{id}` weigert nu alle queryparameters. De oorspronkelijke sleutelbinding en actuele delegatie worden vóór en na de lezing gecontroleerd; een inmiddels onzichtbaar rapport of gesprek geeft 404. Lees de concrete foutcode, en behandel een leesfout niet als bewijs dat een eerdere mutatie niet is uitgevoerd.

### Een vaste bulkimport ontvangen en vervolgen

`POST /v1/bulkimports` ontvangt één volledige set van 1–400 rijen met unieke rijnummers, een eigen `bulkImportId` en een actief rapportprofiel. De algemene JSON-grens blijft 100 KiB, ook als individuele rijvelden grotere maxima toelaten. Maximaal veertig numeriek gesorteerde rijen worden per groep ingepland, met tien minuten tussen de vroegste startmomenten. Dit is geen voltooiingsgarantie of vaste creditprijs.

Bewaar de volledige oorspronkelijke body en opdrachtcode. Bij een verloren antwoord of gedeeltelijke planning herhaal je precies die aanvraag, inclusief de rijvolgorde; stuur geen kleinere restlijst en maak geen nieuwe importcode. Bestaande mislukte of onzekere jobs worden daardoor niet opnieuw gestart. Huidige rechten, profielbronnen, pakket, kostenmodus en schema moeten nog steeds beschikbaar zijn.

Lees `GET /v1/bulkimports/{id}` met je oorspronkelijke `bulkImportId`. Het antwoordveld `opdracht_id` is een andere, door de server gebonden identiteit. `hoofdrapport_klaar:true` bewijst alleen het hoofdrapport; `klaar:true` op importniveau vereist alle gevraagde uitvoer van alle rijen. Een ontbrekende gekoppelde job kan in de huidige bron een null-hoofdrapportmarkering geven. De rijstatus onderscheidt ontbrekende taaluitvoer, verwerking en verplicht herstel. Historische taalstatus blijft zichtbaar, maar in deze release is iedere nieuwe of herhaalde import met effectief ingeschakelde tweede taal gesloten. Ontbrekende taaluitvoer kan dus niet via een ontvangstherhaling worden aangevuld.

De bestaande daglimiet voor Gratis is twee topniveau-rapportstarts per organisatie per UTC-dag. Een bulkrij en haar rapportkind worden niet dubbel geteld. `429 gratis_daglimiet` verschilt van een onzekere input-/queuefout met 503. Alleen een expliciete databaseweigering bewijst dat de betreffende enqueue is teruggedraaid. Omzeil onzekerheid niet met een nieuwe opdrachtcode. Een reeds geweigerde versie wordt niet vanzelf herstart na middernacht. Er is geen nieuw publiek dagcap-statusendpoint beschreven.

### Kantoorportaal: uitnodiging, stukken en intrekken

Lees eerst `GET /v1/klanten/{id}/portaal` met `klanten:delen`. Bewaar de actuele `basis` en de opaque `adres_basis`. Een uitnodiging gebruikt het adres dat al in de klantmap staat; de API neemt geen ontvangstadres, inloglink, OTP of redirect aan. Nodig uitsluitend een fictieve testklant uit op een daarvoor gecontroleerd adres. De importvoorbeelden hebben lege identificaties en voeren niets vanzelf uit.

`POST /v1/klanten/{id}/portaal` vereist beide basiswaarden, `bevestigd:true` en een vaste opdrachtcode. Een onzeker auth-/mailantwoord geeft 202. Een herhaling kan 200 geven terwijl de ontvangst nog onzeker is: lees altijd `ontvangst.status` en `herstel_nodig`. `mail_aangeboden` bewijst geen aflevering. Herhaal nooit met een nieuwe code om onzekerheid te omzeilen. Stoppen is een afzonderlijke bewuste actie op de oorspronkelijke aanvraag; het wist geen authaccount en maakt een reeds aangeboden externe poging niet ongedaan. Een gestopte poging kan daarom nog herstel vereisen.

Vrijgeven en intrekken staan los van uitnodigen. Vrijgeven vereist huidige rechten op een klaar rapport met PDF of een toegestaan bestaand dossierbestand. Opnames, audio en transcripties worden niet via deze actie gedeeld. `DELETE /v1/klanten/{id}/portaal` zet toegang uit; een DELETE op de specifieke vrijgave trekt alleen dat stuk in. Geen van beide verwijdert het oorspronkelijke document. Gebruik na iedere nieuwe wijziging de opnieuw gelezen basis; bij antwoordverlies herhaal je de exacte oorspronkelijke aanvraag. `huidig` is actueel, `ontvangst.basis` kan historisch zijn.

Het overzicht toont maximaal vijftig recente aanleveringen en de huidige zichtbare vrijgaven; het bevat geen paginering voor oudere aanleveringen. Een gekoppelde identiteit (`heeft_toegang`) is iets anders dan actieve toegang (`actief`). De zes kantooracties geven geen toegang tot de klant-JWT-router. De afzonderlijke portaalvrijgave en alle huidige rechten blijven vereist.

### Herstel na volledige vertaling, vóór publicatie

De geselecteerde bron `5edf9824` bewaart een complete gevalideerde rapport-/briefvertaling met bewezen werkelijke afrekening privé vóór renderen. De bestaande bewuste retry of hervatting kan diezelfde inhoud verder renderen, opslaan en publiceren zonder nieuwe provideraanroep of reservering. Hiervoor moeten de oorspronkelijke opdracht, doelversie, bronbasis, sleutel, actor, bovenliggende opdracht en kosten nog aantoonbaar kloppen. Een al actieve canonieke rapportrevisie wordt niet via dit pad overschreven. Lees eerst de huidige status en gebruik de huidige opdrachtbasis/versie.

`herstel_zonder_provider` beschrijft bewezen opgeslagen resultaat of volledige herstelinhoud; het is geen algemene starttoestemming. Bij ontbrekende brief, gedeeltelijke inhoud, onbekend providerantwoord of onzekere afrekening blijft betaalde retry gesloten. De nieuwe betaalde uitkomstselectie uit `28d23f2e` is uitgesloten van deze releasegids en importcollectie. Ook gesprek-, presentatie-, formulier-/offerte- en ongebonden legacyherstel krijgen daarmee geen nieuwe bevoegdheid. Er is geen nieuwe publieke herstelreceipt-route.


### Bulkimport zonder tweede taal

Bron `56179ec5` weigert een effectief ingeschakelde tweede taal met HTTP 409 `api_bulkimport_taalretentie_niet_vrijgegeven`, vóór ontvangst, private opslag en planning. Ontbrekend beleid of `inherit` kan een kantoorvoorkeur activeren. Kies bij een nieuwe import daarom beide secundaire uitkomsten expliciet `off`, zoals in de collectie. Bij een herhaling blijft het oorspronkelijk bevroren beleid gelden; verander de body niet om de grens te omzeilen. Nieuwe primaire bulk zonder tweede taal blijft onder het bestaande contract mogelijk. De grens annuleert geen al ingeplande primaire rapportjobs.
