Alle talen en veiligheidsafspraken · API-referentie
Node.js 22+. Een ES-module voor servers; ook vanuit TypeScript te importeren. Stop servicegeheimen nooit in browserbundels.
1. Herbruikbare client
Bewaar dit als binadit.mjs. De client volgt geen redirects en herhaalt geen aanvragen. Geef geheimen via je secretmanager aan de omgeving door; niets wordt automatisch opgeslagen of gelogd.
// Node.js 22+, server-side JavaScript. Never put service secrets in browser code.
import { createHmac, timingSafeEqual } from 'node:crypto';
const ORIGIN = 'https://my.binadit.com';
const LIMIT = 8 * 1024 * 1024;
async function send(method, path, headers, body) {
if (!(path.startsWith('/api/v1/') || path === '/oauth/token') || /[\\#]/.test(path)) {
throw new Error('Use a relative Binadit API path');
}
let response;
try {
response = await fetch(ORIGIN + path, {
method, headers, body, redirect: 'manual', signal: AbortSignal.timeout(30000),
});
} catch {
throw new Error('Transport outcome unknown; preserve the original request');
}
if (!response.ok) {
await response.body?.cancel();
throw new Error(`API HTTP ${response.status}; inspect the original operation`);
}
const chunks = [];
let size = 0;
for await (const chunk of response.body ?? []) {
size += chunk.length;
if (size > LIMIT) throw new Error("Response exceeds the example's 8 MiB limit");
chunks.push(Buffer.from(chunk));
}
return { headers: response.headers, bytes: Buffer.concat(chunks) };
}
export async function accessToken() {
if (process.env.BINADIT_ACCESS_TOKEN) return process.env.BINADIT_ACCESS_TOKEN;
const { BINADIT_CLIENT_ID: id, BINADIT_CLIENT_SECRET: secret } = process.env;
if (!id || !secret) throw new Error('Supply service credentials from your secret manager');
const result = await send('POST', '/oauth/token', {
Accept: 'application/json', 'Content-Type': 'application/x-www-form-urlencoded',
}, new URLSearchParams({ grant_type: 'client_credentials', client_id: id, client_secret: secret }));
const token = JSON.parse(result.bytes.toString('utf8')).access_token;
if (typeof token !== 'string' || !token) throw new Error('Token response is invalid');
return token;
}
export async function api(token, method, path, body = undefined, options = {}) {
if (!path.startsWith('/api/v1/') || !['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) {
throw new Error('Use a supported API method and path');
}
const headers = { Authorization: `Bearer ${token}`, Accept: options.binary ? 'application/pdf' : 'application/json' };
if (method !== 'GET') {
if (!/^[A-Za-z0-9_.:-]{16,128}$/.test(options.key ?? '')) throw new Error('Supply the persisted original Idempotency-Key');
headers['Idempotency-Key'] = options.key;
}
if (options.version) headers['If-Match'] = options.version;
if (body !== undefined) headers['Content-Type'] = 'application/json';
const result = await send(method, path, headers, body === undefined ? undefined : JSON.stringify(body));
if (options.binary && result.headers.get('content-type')?.split(';')[0] !== 'application/pdf') throw new Error('Expected an invoice PDF');
return { etag: result.headers.get('etag'), data: options.binary ? result.bytes : (result.bytes.length ? JSON.parse(result.bytes.toString('utf8')) : null) };
}
export function verifyWebhook(raw, deliveryId, timestamp, signature, expectedKeyId, secret, now = Date.now() / 1000) {
const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
if (raw.length > 1024 * 1024 || secret.length < 32 || !uuid.test(deliveryId) || !uuid.test(expectedKeyId)
|| !/^[1-9][0-9]{8,10}$/.test(timestamp) || Math.abs(now - Number(timestamp)) > 300) return false;
const digest = createHmac('sha256', secret).update(`${timestamp}.${deliveryId}.`).update(raw).digest('hex');
const expected = Buffer.from(`v1=${digest},key_id=${expectedKeyId}`);
const actual = Buffer.from(signature);
return actual.length === expected.length && timingSafeEqual(actual, expected);
}
2. Eenmalig voor deze workflow
import { accessToken, api } from './binadit.mjs';
const token = await accessToken();
De tokenaanvraag gebeurt één keer voor deze korte workflow. Een servicesleutel is geen menselijke step-up. Stop bij 401 en onderzoek eerst een mogelijk verzonden mutatie. Iedere onderstaande codeblok is een afzonderlijk voorbeeld: plak ze niet allemaal achter elkaar. Alle IDs en example.test-adressen zijn fictief. Schrijfvoorbeelden met mogelijke gevolgen gebruiken dry_run.
Identiteit controleren
GET /api/v1/me · scope account:read
const result = await api(token, "GET", "/api/v1/me");
Bedrijven ophalen
GET /api/v1/accounts · scope account:read
const result = await api(token, "GET", "/api/v1/accounts");
Beschikbaarheid en scopes controleren
GET /api/v1/accounts/123/capabilities · scope account:read
const result = await api(token, "GET", "/api/v1/accounts/123/capabilities");
Bedrijfsgegevens en ETag lezen
GET /api/v1/accounts/123/profile · scope account:read
const result = await api(token, "GET", "/api/v1/accounts/123/profile");
Bedrijfsgegevens wijzigen
PATCH /api/v1/accounts/123/profile · scope account:write
Lees eerst GET profile en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "PATCH", "/api/v1/accounts/123/profile", {"city": "Utrecht", "dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Producten en prijzen bekijken
GET /api/v1/accounts/123/products · scope products:read
const result = await api(token, "GET", "/api/v1/accounts/123/products");
Bestaande domeinhouders ophalen
GET /api/v1/accounts/123/holders · scope holders:read
const result = await api(token, "GET", "/api/v1/accounts/123/holders");
Standaardhouder uit bedrijfs- of particuliere gegevens voorbereiden
POST /api/v1/accounts/123/holders/default · scope holders:read, holders:write
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/holders/default", {"dry_run": true}, { key: process.env.BINADIT_REQUEST_KEY });
Een eigen domeinhouder aanmaken
POST /api/v1/accounts/123/holders · scope holders:write
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/holders", {"initials": "A", "firstname": "Ada", "lastname": "Example", "gender": "F", "street": "Voorbeeldstraat", "number": "1", "zipcode": "1234 AB", "city": "Utrecht", "country": "NL", "email": "ada@example.test", "tel1": "+31", "tel3": "612345678", "dry_run": true}, { key: process.env.BINADIT_REQUEST_KEY });
Beschikbaarheid van een domein opvragen
POST /api/v1/accounts/123/domains/check · scope domains:read
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/domains/check", {"domains": ["example.test"]}, { key: process.env.BINADIT_REQUEST_KEY });
Domeinregistratie offreren
POST /api/v1/accounts/123/order-quotes · scope orders:write
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/order-quotes", {"kind": "domain_register", "input": {"domain": "example.test", "product_id": 9, "holder_id": 17}, "dry_run": true}, { key: process.env.BINADIT_REQUEST_KEY });
Een bewaarde offerte opnieuw lezen
GET /api/v1/accounts/123/order-quotes/11111111-1111-4111-8111-111111111111 · scope orders:read
const result = await api(token, "GET", "/api/v1/accounts/123/order-quotes/11111111-1111-4111-8111-111111111111");
Bestelling en betaling voorbereiden
POST /api/v1/accounts/123/orders · scope orders:commit
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/orders", {"quote_id": "11111111-1111-4111-8111-111111111111", "dry_run": true}, { key: process.env.BINADIT_REQUEST_KEY });
Registratie, verlenging en abonnementstatus lezen
GET /api/v1/accounts/123/domains/31/subscription · scope domains:read
const result = await api(token, "GET", "/api/v1/accounts/123/domains/31/subscription");
Domein niet meer automatisch verlengen
POST /api/v1/accounts/123/domains/31/actions/cancel · scope domains:write
Lees eerst GET domains/31 en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/domains/31/actions/cancel", {"confirm_domain": "example.test", "dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
DNS-zones ophalen
GET /api/v1/accounts/123/dns/zones · scope dns.zones:read
const result = await api(token, "GET", "/api/v1/accounts/123/dns/zones");
Huidige DNS-records en versie ophalen
GET /api/v1/accounts/123/dns/zones/8/records · scope dns.records:read
const result = await api(token, "GET", "/api/v1/accounts/123/dns/zones/8/records");
DNS-templates ophalen
GET /api/v1/accounts/123/dns/templates · scope dns.templates:read
const result = await api(token, "GET", "/api/v1/accounts/123/dns/templates");
Een DNS-template voorbereiden
POST /api/v1/accounts/123/dns/templates · scope dns.templates:write
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/dns/templates", {"name": "Websitevoorbeeld", "replace": "none", "records": [{"name": "@", "type": "A", "value": "192.0.2.50", "ttl": 300}, {"name": "www", "type": "CNAME", "value": "example.test", "ttl": 300}], "dry_run": true}, { key: process.env.BINADIT_REQUEST_KEY });
Toepassen van een template voorstellen
POST /api/v1/accounts/123/dns/zones/8/template-plans · scope dns.records:write
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/dns/zones/8/template-plans", {"template_id": 11, "dry_run": true}, { key: process.env.BINADIT_REQUEST_KEY });
Meerdere DNS-records in één plan voorbereiden
POST /api/v1/accounts/123/dns/change-plans · scope dns.records:write
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/dns/change-plans", {"zone": "example.test", "changes": [{"action": "create", "name": "proef", "type": "A", "value": "192.0.2.50", "ttl": 300}, {"action": "create", "name": "_verify", "type": "TXT", "value": "binadit-example", "ttl": 300}], "dry_run": true}, { key: process.env.BINADIT_REQUEST_KEY });
Een bekeken DNS-plan toepassen
POST /api/v1/accounts/123/dns/change-plans/11111111-1111-4111-8111-111111111111/apply · scope dns.records:write
Lees eerst version van het oorspronkelijke bekeken DNS-plan en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/dns/change-plans/11111111-1111-4111-8111-111111111111/apply", {"dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Een oorspronkelijke operatie volgen
GET /api/v1/accounts/123/operations/22222222-2222-4222-8222-222222222222 · scope operations:read
const result = await api(token, "GET", "/api/v1/accounts/123/operations/22222222-2222-4222-8222-222222222222");
Facturen ophalen
GET /api/v1/accounts/123/billing/invoices · scope billing.invoices:read
const result = await api(token, "GET", "/api/v1/accounts/123/billing/invoices");
Een factuur als PDF ophalen
GET /api/v1/accounts/123/billing/invoices/45/pdf · scope billing.invoices:read
const result = await api(token, "GET", "/api/v1/accounts/123/billing/invoices/45/pdf", undefined, { binary: true });
result.data bevat uitsluitend PDF-bytes. Gebruik de aparte privé-bestandsvoorbeelden hieronder; print geen PDF- of persoonsgegevens.
Workspaces ophalen
GET /api/v1/accounts/123/workspaces · scope workspace:read
const result = await api(token, "GET", "/api/v1/accounts/123/workspaces");
Mailboxen ophalen
GET /api/v1/accounts/123/workspaces/7/mailboxes · scope workspace.mailboxes:read
const result = await api(token, "GET", "/api/v1/accounts/123/workspaces/7/mailboxes");
Gemachtigden en gebruikersdelingen lezen
GET /api/v1/accounts/123/workspaces/7/mailboxes/23/delegates · scope workspace.mailboxes:read
const result = await api(token, "GET", "/api/v1/accounts/123/workspaces/7/mailboxes/23/delegates");
Volledige mailboxtoegang en agenda bewerken
PUT /api/v1/accounts/123/workspaces/7/mailboxes/23/delegates/24 · scope workspace.mailboxes:write
Lees eerst GET workspaces/7/mailboxes/23 en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "PUT", "/api/v1/accounts/123/workspaces/7/mailboxes/23/delegates/24", {"level": "full", "send_as": false, "calendar_level": "write", "dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Een gratis verzendlijst voorbereiden
POST /api/v1/accounts/123/workspaces/7/mailing-lists · scope workspace.mailboxes:write
Lees eerst GET workspaces/7 en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/workspaces/7/mailing-lists", {"domain_id": 12, "local_part": "team", "display_name": "Team", "members": [{"kind": "mailbox", "id": 23}, {"kind": "mailbox", "id": 24}], "dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Eén lijstlid toevoegen
PUT /api/v1/accounts/123/workspaces/7/mailing-lists/10/members/mailbox-24 · scope workspace.mailboxes:write
Lees eerst GET workspaces/7/mailing-lists/10 en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "PUT", "/api/v1/accounts/123/workspaces/7/mailing-lists/10/members/mailbox-24", {"dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Eén lijstlid verwijderen
DELETE /api/v1/accounts/123/workspaces/7/mailing-lists/10/members/mailbox-24 · scope workspace.mailboxes:write
Lees eerst GET workspaces/7/mailing-lists/10 en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "DELETE", "/api/v1/accounts/123/workspaces/7/mailing-lists/10/members/mailbox-24", {"dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Een gratis ruimte voorbereiden
POST /api/v1/accounts/123/workspaces/7/rooms · scope workspace.mailboxes:write
Lees eerst GET workspaces/7 en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/workspaces/7/rooms", {"domain_id": 12, "local_part": "vergaderzaal", "display_name": "Vergaderzaal 1", "kind": "room", "capacity": 8, "location": "Eerste verdieping", "manager_ids": [23], "dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Een ruimtebeheerder toevoegen
PUT /api/v1/accounts/123/workspaces/7/rooms/11/managers/24 · scope workspace.mailboxes:write
Lees eerst GET workspaces/7/rooms/11 en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "PUT", "/api/v1/accounts/123/workspaces/7/rooms/11/managers/24", {"dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Een ruimte opheffen met persoonlijke verificatie
DELETE /api/v1/accounts/123/workspaces/7/rooms/11 · scope workspace.mailboxes:write
Lees eerst GET workspaces/7/rooms/11 en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
Vereist ook recente sterke menselijke verificatie, actuele bevoegdheden en ingeschakelde gevoelige acties. Een servicesleutel kan die verificatie niet leveren.
const result = await api(token, "DELETE", "/api/v1/accounts/123/workspaces/7/rooms/11", {"confirm_address": "vergaderzaal@example.test", "dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Hostingabonnementen ophalen
GET /api/v1/accounts/123/hosting/subscriptions · scope hosting:read
const result = await api(token, "GET", "/api/v1/accounts/123/hosting/subscriptions");
Hostingopzegging voorbereiden
POST /api/v1/accounts/123/hosting/subscriptions/41/actions/cancel · scope hosting:write
Lees eerst GET hosting/subscriptions/41 en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/hosting/subscriptions/41/actions/cancel", {"intent_id": "33333333-3333-4333-8333-333333333333", "dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Spamfilters ophalen
GET /api/v1/accounts/123/spam/filters · scope spam:read
const result = await api(token, "GET", "/api/v1/accounts/123/spam/filters");
Een collega met beperkte rechten uitnodigen
POST /api/v1/accounts/123/team/invitations · scope team:write
Lees eerst GET profile en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
Vereist ook recente sterke menselijke verificatie, actuele bevoegdheden en ingeschakelde gevoelige acties. Een servicesleutel kan die verificatie niet leveren.
const result = await api(token, "POST", "/api/v1/accounts/123/team/invitations", {"email": "collega@example.test", "role": "member", "permissions": [{"module": "module_dns", "level": "read"}], "dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Een gepauzeerde webhook voorbereiden
POST /api/v1/accounts/123/webhooks · scope webhooks:write
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
Vereist ook recente sterke menselijke verificatie, actuele bevoegdheden en ingeschakelde gevoelige acties. Een servicesleutel kan die verificatie niet leveren.
const result = await api(token, "POST", "/api/v1/accounts/123/webhooks", {"name": "Orderstatus", "url": "https://receiver.example.test/binadit", "integration_id": "44444444-4444-4444-8444-444444444444", "dry_run": true}, { key: process.env.BINADIT_REQUEST_KEY });
Webhookafleveringen inspecteren
GET /api/v1/accounts/123/webhooks/55555555-5555-4555-8555-555555555555/deliveries · scope webhooks:read
const result = await api(token, "GET", "/api/v1/accounts/123/webhooks/55555555-5555-4555-8555-555555555555/deliveries");
De actuele productversie lezen
GET /api/v1/accounts/123/products/9 · scope products:read
const result = await api(token, "GET", "/api/v1/accounts/123/products/9");
Een betaalde normale mailbox offreren
POST /api/v1/accounts/123/order-quotes · scope orders:write
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "POST", "/api/v1/accounts/123/order-quotes", {"kind": "workspace_mailbox", "input": {"workspace_id": 7, "product_id": 9, "domain_id": 12, "local_part": "ada", "display_name": "Ada", "drive": false}, "dry_run": true}, { key: process.env.BINADIT_REQUEST_KEY });
Een betaalde gedeelde mailbox voorbereiden
POST /api/v1/accounts/123/workspaces/7/shared-mailboxes · scope workspace.mailboxes:write, orders:commit
Lees eerst GET workspaces/7 en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
Lees ook GET products/9 en bewaar zijn ongequote data.version als BINADIT_PRODUCT_VERSION. Deze betaalde gedeelde mailbox vraagt naast mailrechten ook orders:commit en actuele bestel- en bestedingsrechten. Een productversie is geen Workspace-versie.
const payload = {"domain_id": 12, "product_id": 9, "local_part": "support", "display_name": "Support", "member_ids": [23, 24], "dry_run": true};
payload["product_version"] = process.env.BINADIT_PRODUCT_VERSION;
const result = await api(token, "POST", "/api/v1/accounts/123/workspaces/7/shared-mailboxes", payload, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Versturen als afzonderlijk inschakelen
PUT /api/v1/accounts/123/workspaces/7/mailboxes/23/delegates/24 · scope workspace.mailboxes:write
Lees eerst GET workspaces/7/mailboxes/23 en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
Send As aanzetten vereist recente sterke persoonlijke verificatie en volledige mailtoegang. Een servicesleutel met alleen de genoemde scope is niet voldoende.
const result = await api(token, "PUT", "/api/v1/accounts/123/workspaces/7/mailboxes/23/delegates/24", {"level": "full", "send_as": true, "calendar_level": "write", "dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Mail- en agendatoegang samen intrekken
DELETE /api/v1/accounts/123/workspaces/7/mailboxes/23/delegates/24 · scope workspace.mailboxes:write
Lees eerst GET workspaces/7/mailboxes/23 en bewaar de bijbehorende HTTP ETag (of expliciet beschreven planversie) als BINADIT_RESOURCE_VERSION. Versies van verschillende resources zijn niet uitwisselbaar.
Gebruik voor exact deze beoordeelde aanvraag een vooraf duurzaam bewaarde BINADIT_REQUEST_KEY van 16–128 veilige tekens. Hergebruik haar alleen voor dezelfde methode, URL en JSON; nooit voor een volgende stap.
const result = await api(token, "DELETE", "/api/v1/accounts/123/workspaces/7/mailboxes/23/delegates/24", {"dry_run": true}, { version: process.env.BINADIT_RESOURCE_VERSION, key: process.env.BINADIT_REQUEST_KEY });
Verder werken
Pagineren zonder resources over te slaan
Controleer meta.next_cursor ook als data leeg is. Volg geen externe next-URL met een token.
let cursor = null;
const seen = new Set();
for (let page = 0; page < 20; page++) {
const query = new URLSearchParams({ limit: '25' });
if (cursor !== null) query.set('cursor', String(cursor));
const result = await api(token, 'GET', `/api/v1/accounts/123/domains?${query}`);
for (const domain of result.data.data) console.log(domain.id);
cursor = result.data.meta?.next_cursor ?? null;
if (cursor === null) break;
if (seen.has(String(cursor))) throw new Error('Repeated pagination cursor');
seen.add(String(cursor));
if (page === 19) throw new Error('Page limit reached; explicitly continue from the saved cursor');
}
PDF opslaan zonder overschrijven
import { open } from 'node:fs/promises';
const result = await api(token, 'GET', '/api/v1/accounts/123/billing/invoices/45/pdf', undefined, { binary: true });
const file = await open('factuur-45.pdf', 'wx', 0o600);
try { await file.writeFile(result.data); } finally { await file.close(); }
Gebruik op Windows een privémap met passende ACL. Log geen PDF-bytes.
Webhookhandtekening controleren
import { verifyWebhook } from './binadit.mjs';
// rawBody must be the unmodified Buffer, before JSON parsing middleware.
const valid = verifyWebhook(rawBody, deliveryIdHeader, timestampHeader, signatureHeader,
process.env.BINADIT_WEBHOOK_KEY_ID, process.env.BINADIT_WEBHOOK_SECRET);
if (!valid) throw new Error('Reject this webhook');
// Next: atomically insert deliveryIdHeader (UNIQUE) and enqueue work in your DB.
Controleer dat headers en secrets aanwezig zijn voordat je de functie aanroept. Gebruik bodylimieten en weiger dubbele headers. De HMAC-controle vergelijkt constant-time en accepteert maximaal vijf minuten tijdverschil. Zij maakt geen werkitem en voorkomt zelf geen replay. Leg de unieke delivery-ID en het werkitem atomair vast voordat je 2xx antwoordt. Voor TypeScript kun je deze server-ES-module met allowJs in een bestaand Node-project opnemen; de voorbeelden zijn geen browser-SDK.