# Codevoorbeelden voor de Binadit API

- [Python](/developers/guides/code-examples-python?lang=nl) · [Markdown](/developers/guides/code-examples-python.md?lang=nl)
- [JavaScript / TypeScript](/developers/guides/code-examples-javascript?lang=nl) · [Markdown](/developers/guides/code-examples-javascript.md?lang=nl)
- [PHP](/developers/guides/code-examples-php?lang=nl) · [Markdown](/developers/guides/code-examples-php.md?lang=nl)
- [C#](/developers/guides/code-examples-csharp?lang=nl) · [Markdown](/developers/guides/code-examples-csharp.md?lang=nl)

## Starten

Kies één taal hierboven. Iedere taalgids bevat een volledige herbruikbare HTTP-client en dezelfde belangrijke taken. De bronbestanden staan in `docs/examples/`; het zijn controleerbare voorbeelden, geen afzonderlijk officieel SDK-pakket. Python en JavaScript gebruiken alleen de standaardbibliotheek; PHP vraagt cURL en C# gebruikt .NET 10. Gebruik JavaScript aan de serverkant, ook als je applicatie verder TypeScript gebruikt.

Maak in **Account → API en integraties** een eigen serviceverbinding met minimale scopes. Laat je secretmanager `BINADIT_CLIENT_ID` en `BINADIT_CLIENT_SECRET` beschikbaar maken. De client vraagt daarmee één kortdurend token aan via `POST /oauth/token` met `grant_type=client_credentials`. Hij bewaart of print het geheim en token niet. Een door je eigen OAuth-applicatie verkregen persoonlijk token kan via `BINADIT_ACCESS_TOKEN` worden gebruikt. Haal geen persoonlijke tokens uit de sleutelkluis van de CLI. Voor gewone interactieve bediening gebruik je `binadit login`.

Een servicesleutel kan geen recente menselijke verificatie vervangen. Teamuitnodigingen, webhookbeheer, Send As inschakelen en ruimtes verwijderen kunnen een bevoegde, recent sterk geverifieerde persoon vereisen. Gebruik daarvoor een eigen goedgekeurde persoonlijke OAuth-verbinding of de bestaande CLI. De snippets omzeilen geen bedrijfsbeleid of featureflags. Exchange en oude saldo-opwaarderingen blijven buiten de release.

De clients gebruiken uitsluitend `https://my.binadit.com`, normale TLS-controle, een timeout en geen redirects of automatische herhaling. Het vaste origin voorkomt dat een pagina- of betaal-URL onbedoeld een Bearer-token ontvangt. Voor een eigen testinstallatie pas je de constante origin bewust aan; zet certificaatcontrole niet uit. De voorbeelden lezen maximaal 8 MiB per response. Gebruik voor grotere bestanden een afzonderlijke begrensde streamingimplementatie.

## Waarden en versies invullen

Alle adressen op `example.test`, documentatie-IP's, IDs en UUID's zijn fictief. Vervang ze door resources die je via dezelfde bedrijfsverbinding hebt opgehaald. `123` is het bedrijf, `7` een Workspace, `23/24` mailboxen, `8` een DNS-zone en `12` een maildomein. Een ID van een ander bedrijf geeft geen bevoegdheid.

Volg bij pagineren `meta.next_cursor`, ook als een door rechten gefilterde `data`-lijst leeg is. De taalgidsen tonen een begrensde lus met controle op een herhaalde cursor. Volg geen willekeurige volgende URL met je token.

De client retourneert `etag` en `data`; `data` is de volledige JSON-envelope, dus bijvoorbeeld `result.data.data` in JavaScript. C# gebruikt `ETag`, `Data` en voor een PDF `Bytes`. Bewaar een ETag bij de exacte resource. Voor mutaties met versiecontrole geeft de taalgids aan welke GET je eerst moet doen. Zet de bekeken ETag of expliciete planversie in `BINADIT_RESOURCE_VERSION`. Gebruik geen verzonnen hash en geen versie van een ander object.

Voor iedere beoordeelde schrijfactie bewaar je **vóór verzending** de oorspronkelijke principal, methode, URL, exacte JSON, resourceversie en een willekeurige `Idempotency-Key` van 16–128 veilige tekens. Geef de oorspronkelijke sleutel door als `BINADIT_REQUEST_KEY`. Een UUID is geschikt; genereer hem één keer in je eigen duurzame aanvraagopslag, niet opnieuw bij iedere scriptstart. De voorbeeldclients eisen uit voorzorg ook bij leesgerichte POST-aanroepen een sleutel; die maakt zo'n endpoint niet alsnog een mutatie.

De schrijfvoorbeelden gebruiken waar relevant `dry_run: true`. Een dry-run bewaart geen uitvoerbare bestelling, machtiging of DNS-plan. Voor echte uitvoering beoordeel je eerst de preview, leest actuele versies en bewaart de uiteindelijke JSON zonder `dry_run` met zijn eigen sleutel. Plak niet alle voorbeelden achter elkaar: elke snippet is een afzonderlijke taak met zijn eigen invoer en sleutel. Een dry-run voor een gevoelige taak heft de menselijke verificatieregel niet op.

## Bestellen, betalen en opzeggen

1. Lees producten, de eigen houder en capabilities. Vraag de prijs aan de server; bereken geen eigen verkoopprijs.
2. Beoordeel een offerte-preview. Vraag daarna bewust een **bewaarde** offerte aan door `dry_run` weg te laten. Gebruik de echte `data.id` en controleer dezelfde offerte met GET. Een preview-ID mag niet als echte offerte worden behandeld.
3. Preview het bevestigen met `orders` en `dry_run: true`. Alleen na goedkeuring verstuur je diezelfde offerte-ID zonder `dry_run`, met een daarvoor duurzaam vastgelegde sleutel. Dit kan een factuur en bestelling aanmaken. `orders:commit` en de geldende bestel-/bestedingsrechten blijven vereist.
4. De bestelling kan `checkout_url` teruggeven. Open die afzonderlijk in de browser voor de betaalbevestiging. Stuur nooit het Binadit-token naar de betaalprovider en haal deze URL niet met de voorbeeldclient op.
5. Volg de **oorspronkelijke** operatie en lees het domein opnieuw. `queued` of `awaiting_payment` bewijst geen registratie. Controleer registrarstatus, DNS-publicatie en abonnement/automatisch verlengen afzonderlijk.

Een domein opzeggen stopt automatische verlenging; het is geen onmiddellijke verwijdering. Lees daarna opnieuw `domains/{id}/subscription` en controleer de vastgelegde einddatum en facturatiestatus. Hosting en andere diensten hebben eigen opzeggingsintenties; een domein en een hostingpakket zijn afzonderlijke overeenkomsten.

## DNS en Workspace

DNS verloopt altijd via de Binadit API en de bestaande portaalverwerking. Lees records, maak een plan, beoordeel records en versie en pas het oorspronkelijke plan afzonderlijk toe. Een template-plan is ook een voorstel. Gebruik nooit rechtstreeks PowerDNS-, NS1- of Cloudflare-sleutels in deze clients. De recordwaarde heet `value`; CNAME-doelen volgen de portaalnotatie zonder afsluitende punt. Werk bij verwijderen/bewerken met de werkelijk gelezen record-ID's, niet met de positie in een nieuw gesorteerde lijst.

Gewone en gedeelde mailboxen zijn betaalde producten. Bestel een normale mailbox via een offerte van het type `workspace_mailbox`; voor gedeelde mailboxen geldt het [eigen betaalde contract](/developers/guides/workspace-shared-mailboxes?lang=nl). De voorbeelden voor gemachtigden, agenda's, verzendlijsten en ruimtes zijn gratis en vragen geen product of factuur. `full` geeft ook versturen namens; `send_as` is een afzonderlijke gevoelige keuze. De ontvanger ziet na uitschakelen van Send As weer de gemachtigde zolang `full` blijft bestaan. Een lijstlid is een bestaand typed ID zoals `mailbox-24`, geen extern adres of geneste lijst. Ruimtes hebben geen inlogwachtwoord; bij herhaling wordt alleen het eerste voorkomen gecontroleerd. Zie het [volledige mailcontract](/developers/guides/workspace-mail-collaboration?lang=nl).

## Fouten, onzekerheid en voortgang

| Uitkomst | Actie |
| --- | --- |
| 401 | Stop. Controleer eerst of een mutatie al kan zijn verstuurd. Vraag voor volgende bewuste acties een nieuw token aan; herhaal geen POST automatisch. |
| 403/404 | Controleer bedrijf, scopes, resourcebeperkingen en eventuele menselijke verificatie; probeer geen ander bedrijf of beheertoken als omweg. |
| 409 | Onderzoek de bestaande aanvraag of blokkade. Geen nieuwe sleutel, offerte of leveranciersaanvraag om de oude te vervangen. |
| 412/428 | Lees de juiste resource opnieuw en beoordeel de gewijzigde situatie; forceer geen nieuwe ETag op een oude opdracht. |
| 422 | Controleer velden, typen en het OpenAPI-contract. |
| 429 | Respecteer `Retry-After`. De helpers herhalen zelf niets. Onderzoek een onzekere mutatie voordat je later opnieuw leest of iets aanvraagt. |
| Timeout/5xx | Uitkomst kan onbekend zijn. Bewaar de oorspronkelijke metadata en inspecteer de operatie. Een timeout bewijst niet dat de server niets heeft uitgevoerd. |

`operation.request_status: succeeded` bevestigt het HTTP-ontvangstbewijs, niet automatisch de leveranciersactie. Volg `operation.status`: onder meer `queued`, `running`, `awaiting_payment`, `requires_approval`, `requires_reconciliation`, `failed` en `succeeded`. Een vastgehouden gratis mailtaak is `requires_reconciliation`, geen betaalverzoek. Een fout in een medewerker-/DNS-taak is geen reden voor een tweede betaalde bestelling.

Bewaar ontvangen operation-, plan- en intent-ID's bij je oorspronkelijke aanvraag. Lees met `operations:read` dezelfde operatie met een begrensde pollfrequentie, bijvoorbeeld elke vijf seconden en maximaal twee minuten per scriptuitvoering. Stop bij een controle- of betaalstatus; druk die niet door. Na een nieuwe persoonlijke aanmelding kan de oorspronkelijke principal zijn veranderd: gebruik dan het [oorspronkelijke ontvangstbewijs](/developers/guides/original-operations?lang=nl), niet een automatische replay onder de nieuwe verbinding.

De clients geven fouten bewust zonder ongefilterde responsebody door. Log geen Bearer-token, clientgeheim, eenmalige claim, persoonsgegevens, mailinhoud of PDF. Eenmalige wachtwoord- en sleutelclaims hebben een afzonderlijk protocol en horen niet in een generieke retrylus.

## Webhooks ontvangen

De taalgidsen bevatten een HMAC-controle voor de **ongewijzigde raw body** en de drie headers `Binadit-Webhook-Id`, `Binadit-Webhook-Timestamp` en `Binadit-Webhook-Signature`. De verwachte sleutel-ID en het geheim komen uit je eigen secretmanager. Gebruik TLS, controleer het tijdvenster, vergelijk constant-time en voorkom daarna replay met een unieke delivery-ID in duurzame opslag. Een geldige handtekening alleen voorkomt geen dubbele uitvoering.

Na verificatie: leg de delivery-ID en een werkitem atomair vast in één databasetransactie met een unieke constraint. Beantwoord pas daarna 2xx. Een al duurzaam ontvangen, geldig ondertekende delivery krijgt opnieuw 2xx zonder het werk te herhalen. Verwerk bijvoorbeeld een factuurmelding nooit tweemaal. Houd bij sleutelrotatie uitsluitend bewust toegestane eigen sleutel-ID's bij; vertrouw geen onbekende key_id uit een header.

## Contract en controle

De voorbeelden worden gegenereerd uit de werkelijke operatiecatalogus en gedeelde recepten. Routes, scopes, methoden en JSON-bodies worden lokaal tegen [OpenAPI](/developers/openapi.json) gecontroleerd. De clientcode wordt apart uitgevoerd tegen een lokale testontvanger; hierbij worden geen klantgegevens of betaalde acties op productie gebruikt. De PHP-/Python-/Node-versies en .NET-buildcontrole staan in de ontwikkelnotities bij de broncode. Dit is geen claim dat iedere getoonde betaalde actie in alle vier talen op productie is besteld.

De voorbeelden volgen het actuele [releasebereik](/developers/guides/release-scope?lang=nl), de [API-referentie](/developers/api?lang=nl#reference) en de [agenthandleiding](/developers/agents?lang=nl). Technische standaardbibliotheken: [HttpClient redirects](https://learn.microsoft.com/dotnet/api/system.net.http.httpclienthandler.allowautoredirect), [Node fetch en timeouts](https://nodejs.org/api/globals.html).


## Onderwerpen in iedere taal

| Taak | Methode | Scope |
| --- | --- | --- |
| Identiteit controleren | `GET` | `account:read` |
| Bedrijven ophalen | `GET` | `account:read` |
| Beschikbaarheid en scopes controleren | `GET` | `account:read` |
| Bedrijfsgegevens en ETag lezen | `GET` | `account:read` |
| Bedrijfsgegevens wijzigen | `PATCH` | `account:write` |
| Producten en prijzen bekijken | `GET` | `products:read` |
| Bestaande domeinhouders ophalen | `GET` | `holders:read` |
| Standaardhouder uit bedrijfs- of particuliere gegevens voorbereiden | `POST` | `holders:read, holders:write` |
| Een eigen domeinhouder aanmaken | `POST` | `holders:write` |
| Beschikbaarheid van een domein opvragen | `POST` | `domains:read` |
| Domeinregistratie offreren | `POST` | `orders:write` |
| Een bewaarde offerte opnieuw lezen | `GET` | `orders:read` |
| Bestelling en betaling voorbereiden | `POST` | `orders:commit` |
| Registratie, verlenging en abonnementstatus lezen | `GET` | `domains:read` |
| Domein niet meer automatisch verlengen | `POST` | `domains:write` |
| DNS-zones ophalen | `GET` | `dns.zones:read` |
| Huidige DNS-records en versie ophalen | `GET` | `dns.records:read` |
| DNS-templates ophalen | `GET` | `dns.templates:read` |
| Een DNS-template voorbereiden | `POST` | `dns.templates:write` |
| Toepassen van een template voorstellen | `POST` | `dns.records:write` |
| Meerdere DNS-records in één plan voorbereiden | `POST` | `dns.records:write` |
| Een bekeken DNS-plan toepassen | `POST` | `dns.records:write` |
| Een oorspronkelijke operatie volgen | `GET` | `operations:read` |
| Facturen ophalen | `GET` | `billing.invoices:read` |
| Een factuur als PDF ophalen | `GET` | `billing.invoices:read` |
| Workspaces ophalen | `GET` | `workspace:read` |
| Mailboxen ophalen | `GET` | `workspace.mailboxes:read` |
| Gemachtigden en gebruikersdelingen lezen | `GET` | `workspace.mailboxes:read` |
| Volledige mailboxtoegang en agenda bewerken | `PUT` | `workspace.mailboxes:write` |
| Een gratis verzendlijst voorbereiden | `POST` | `workspace.mailboxes:write` |
| Eén lijstlid toevoegen | `PUT` | `workspace.mailboxes:write` |
| Eén lijstlid verwijderen | `DELETE` | `workspace.mailboxes:write` |
| Een gratis ruimte voorbereiden | `POST` | `workspace.mailboxes:write` |
| Een ruimtebeheerder toevoegen | `PUT` | `workspace.mailboxes:write` |
| Een ruimte opheffen met persoonlijke verificatie | `DELETE` | `workspace.mailboxes:write` |
| Hostingabonnementen ophalen | `GET` | `hosting:read` |
| Hostingopzegging voorbereiden | `POST` | `hosting:write` |
| Spamfilters ophalen | `GET` | `spam:read` |
| Een collega met beperkte rechten uitnodigen | `POST` | `team:write` |
| Een gepauzeerde webhook voorbereiden | `POST` | `webhooks:write` |
| Webhookafleveringen inspecteren | `GET` | `webhooks:read` |
| De actuele productversie lezen | `GET` | `products:read` |
| Een betaalde normale mailbox offreren | `POST` | `orders:write` |
| Een betaalde gedeelde mailbox voorbereiden | `POST` | `workspace.mailboxes:write, orders:commit` |
| Versturen als afzonderlijk inschakelen | `PUT` | `workspace.mailboxes:write` |
| Mail- en agendatoegang samen intrekken | `DELETE` | `workspace.mailboxes:write` |
