Alle talen en veiligheidsafspraken · API-referentie
.NET 10. Maak met dotnet new console een project en voeg Binadit.cs toe. Gebruik de aanroepen hieronder vanuit de async Program.cs.
1. Herbruikbare client
Bewaar dit als Binadit.cs. De client volgt geen redirects en herhaalt geen aanvragen. Geef geheimen via je secretmanager aan de omgeving door; niets wordt automatisch opgeslagen of gelogd.
// .NET 10, standard library only. Reuse one client; no automatic token refresh or retry.
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json.Nodes;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
public sealed record BinaditReply(string? ETag, JsonNode? Data, byte[] Bytes);
public sealed class BinaditExample : IDisposable
{
private readonly HttpClient http = new(new HttpClientHandler { AllowAutoRedirect = false, UseCookies = false })
{ Timeout = TimeSpan.FromSeconds(30), MaxResponseContentBufferSize = 8 * 1024 * 1024 };
private const string Origin = "https://my.binadit.com";
private async Task<(HttpResponseMessage Response, byte[] Bytes)> Send(string method, string path, string? body, string contentType, string? token = null, string? version = null, string? key = null, bool binary = false)
{
if ((!path.StartsWith("/api/v1/", StringComparison.Ordinal) && path != "/oauth/token") || path.Contains('\\') || path.Contains('#'))
throw new ArgumentException("Use a relative Binadit API path");
using var request = new HttpRequestMessage(new HttpMethod(method), Origin + path);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(binary ? "application/pdf" : "application/json"));
if (token is not null) request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
if (version is not null) request.Headers.Add("If-Match", version);
if (key is not null) request.Headers.Add("Idempotency-Key", key);
if (body is not null) request.Content = new StringContent(body, Encoding.UTF8, contentType);
HttpResponseMessage response;
try { response = await http.SendAsync(request); }
catch (HttpRequestException) { throw new InvalidOperationException("Transport outcome unknown; preserve the original request"); }
catch (TaskCanceledException) { throw new InvalidOperationException("Transport outcome unknown; preserve the original request"); }
if (!response.IsSuccessStatusCode) { int code = (int)response.StatusCode; response.Dispose(); throw new InvalidOperationException($"API HTTP {code}; inspect the original operation"); }
return (response, await response.Content.ReadAsByteArrayAsync());
}
public async Task<string> AccessToken()
{
if (Environment.GetEnvironmentVariable("BINADIT_ACCESS_TOKEN") is { Length: > 0 } token) return token;
string Required(string name) => Environment.GetEnvironmentVariable(name) ?? throw new InvalidOperationException("Supply service credentials from your secret manager");
using var form = new FormUrlEncodedContent(new Dictionary<string, string> {
["grant_type"] = "client_credentials", ["client_id"] = Required("BINADIT_CLIENT_ID"), ["client_secret"] = Required("BINADIT_CLIENT_SECRET") });
var (response, bytes) = await Send("POST", "/oauth/token", await form.ReadAsStringAsync(), "application/x-www-form-urlencoded");
using (response) return JsonNode.Parse(bytes)?["access_token"]?.GetValue<string>() is { Length: > 0 } value ? value : throw new InvalidOperationException("Token response is invalid");
}
public async Task<BinaditReply> Api(string token, string method, string path, JsonNode? body = null, string? version = null, string? key = null, bool binary = false)
{
if (!path.StartsWith("/api/v1/", StringComparison.Ordinal) || !new[] { "GET", "POST", "PUT", "PATCH", "DELETE" }.Contains(method)) throw new ArgumentException("Use a supported API method and path");
if (method != "GET" && !Regex.IsMatch(key ?? "", @"\A[A-Za-z0-9_.:-]{16,128}\z")) throw new ArgumentException("Supply the persisted original Idempotency-Key");
var (response, bytes) = await Send(method, path, body?.ToJsonString(), "application/json", token, version, key, binary);
using (response)
{
if (binary && response.Content.Headers.ContentType?.MediaType != "application/pdf") throw new InvalidOperationException("Expected an invoice PDF");
return new(response.Headers.ETag?.ToString(), binary || bytes.Length == 0 ? null : JsonNode.Parse(bytes), binary ? bytes : []);
}
}
public void Dispose() => http.Dispose();
public static bool VerifyWebhook(byte[] raw, string deliveryId, string timestamp, string signature, string expectedKeyId, string secret, long? now = null)
{
const string uuid = @"\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z";
if (raw.Length > 1024 * 1024 || secret.Length < 32 || !Regex.IsMatch(deliveryId, uuid) || !Regex.IsMatch(expectedKeyId, uuid)
|| !Regex.IsMatch(timestamp, @"\A[1-9][0-9]{8,10}\z") || Math.Abs((now ?? DateTimeOffset.UtcNow.ToUnixTimeSeconds()) - long.Parse(timestamp)) > 300) return false;
byte[] input = Encoding.UTF8.GetBytes(timestamp + "." + deliveryId + ".").Concat(raw).ToArray();
string digest = Convert.ToHexString(HMACSHA256.HashData(Encoding.UTF8.GetBytes(secret), input)).ToLowerInvariant();
return CryptographicOperations.FixedTimeEquals(Encoding.UTF8.GetBytes("v1=" + digest + ",key_id=" + expectedKeyId), Encoding.UTF8.GetBytes(signature));
}
}
2. Eenmalig voor deze workflow
using System.Text.Json.Nodes;
using var client = new BinaditExample();
var token = await client.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
var result = await client.Api(token, "GET", "/api/v1/me");
Bedrijven ophalen
GET /api/v1/accounts · scope account:read
var result = await client.Api(token, "GET", "/api/v1/accounts");
Beschikbaarheid en scopes controleren
GET /api/v1/accounts/123/capabilities · scope account:read
var result = await client.Api(token, "GET", "/api/v1/accounts/123/capabilities");
Bedrijfsgegevens en ETag lezen
GET /api/v1/accounts/123/profile · scope account:read
var result = await client.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.
var result = await client.Api(token, "PATCH", "/api/v1/accounts/123/profile", JsonNode.Parse("""{"city": "Utrecht", "dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("BINADIT_REQUEST_KEY"));
Producten en prijzen bekijken
GET /api/v1/accounts/123/products · scope products:read
var result = await client.Api(token, "GET", "/api/v1/accounts/123/products");
Bestaande domeinhouders ophalen
GET /api/v1/accounts/123/holders · scope holders:read
var result = await client.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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/holders/default", JsonNode.Parse("""{"dry_run": true}"""), key: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/holders", JsonNode.Parse("""{"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: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/domains/check", JsonNode.Parse("""{"domains": ["example.test"]}"""), key: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/order-quotes", JsonNode.Parse("""{"kind": "domain_register", "input": {"domain": "example.test", "product_id": 9, "holder_id": 17}, "dry_run": true}"""), key: Environment.GetEnvironmentVariable("BINADIT_REQUEST_KEY"));
Een bewaarde offerte opnieuw lezen
GET /api/v1/accounts/123/order-quotes/11111111-1111-4111-8111-111111111111 · scope orders:read
var result = await client.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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/orders", JsonNode.Parse("""{"quote_id": "11111111-1111-4111-8111-111111111111", "dry_run": true}"""), key: Environment.GetEnvironmentVariable("BINADIT_REQUEST_KEY"));
Registratie, verlenging en abonnementstatus lezen
GET /api/v1/accounts/123/domains/31/subscription · scope domains:read
var result = await client.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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/domains/31/actions/cancel", JsonNode.Parse("""{"confirm_domain": "example.test", "dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("BINADIT_REQUEST_KEY"));
DNS-zones ophalen
GET /api/v1/accounts/123/dns/zones · scope dns.zones:read
var result = await client.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
var result = await client.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
var result = await client.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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/dns/templates", JsonNode.Parse("""{"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: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/dns/zones/8/template-plans", JsonNode.Parse("""{"template_id": 11, "dry_run": true}"""), key: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/dns/change-plans", JsonNode.Parse("""{"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: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/dns/change-plans/11111111-1111-4111-8111-111111111111/apply", JsonNode.Parse("""{"dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("BINADIT_REQUEST_KEY"));
Een oorspronkelijke operatie volgen
GET /api/v1/accounts/123/operations/22222222-2222-4222-8222-222222222222 · scope operations:read
var result = await client.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
var result = await client.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
var result = await client.Api(token, "GET", "/api/v1/accounts/123/billing/invoices/45/pdf", binary: true);
result.Bytes 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
var result = await client.Api(token, "GET", "/api/v1/accounts/123/workspaces");
Mailboxen ophalen
GET /api/v1/accounts/123/workspaces/7/mailboxes · scope workspace.mailboxes:read
var result = await client.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
var result = await client.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.
var result = await client.Api(token, "PUT", "/api/v1/accounts/123/workspaces/7/mailboxes/23/delegates/24", JsonNode.Parse("""{"level": "full", "send_as": false, "calendar_level": "write", "dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/workspaces/7/mailing-lists", JsonNode.Parse("""{"domain_id": 12, "local_part": "team", "display_name": "Team", "members": [{"kind": "mailbox", "id": 23}, {"kind": "mailbox", "id": 24}], "dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "PUT", "/api/v1/accounts/123/workspaces/7/mailing-lists/10/members/mailbox-24", JsonNode.Parse("""{"dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "DELETE", "/api/v1/accounts/123/workspaces/7/mailing-lists/10/members/mailbox-24", JsonNode.Parse("""{"dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/workspaces/7/rooms", JsonNode.Parse("""{"domain_id": 12, "local_part": "vergaderzaal", "display_name": "Vergaderzaal 1", "kind": "room", "capacity": 8, "location": "Eerste verdieping", "manager_ids": [23], "dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "PUT", "/api/v1/accounts/123/workspaces/7/rooms/11/managers/24", JsonNode.Parse("""{"dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "DELETE", "/api/v1/accounts/123/workspaces/7/rooms/11", JsonNode.Parse("""{"confirm_address": "vergaderzaal@example.test", "dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("BINADIT_REQUEST_KEY"));
Hostingabonnementen ophalen
GET /api/v1/accounts/123/hosting/subscriptions · scope hosting:read
var result = await client.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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/hosting/subscriptions/41/actions/cancel", JsonNode.Parse("""{"intent_id": "33333333-3333-4333-8333-333333333333", "dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("BINADIT_REQUEST_KEY"));
Spamfilters ophalen
GET /api/v1/accounts/123/spam/filters · scope spam:read
var result = await client.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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/team/invitations", JsonNode.Parse("""{"email": "collega@example.test", "role": "member", "permissions": [{"module": "module_dns", "level": "read"}], "dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/webhooks", JsonNode.Parse("""{"name": "Orderstatus", "url": "https://receiver.example.test/binadit", "integration_id": "44444444-4444-4444-8444-444444444444", "dry_run": true}"""), key: Environment.GetEnvironmentVariable("BINADIT_REQUEST_KEY"));
Webhookafleveringen inspecteren
GET /api/v1/accounts/123/webhooks/55555555-5555-4555-8555-555555555555/deliveries · scope webhooks:read
var result = await client.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
var result = await client.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.
var result = await client.Api(token, "POST", "/api/v1/accounts/123/order-quotes", JsonNode.Parse("""{"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: Environment.GetEnvironmentVariable("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.
var payload = JsonNode.Parse("""{"domain_id": 12, "product_id": 9, "local_part": "support", "display_name": "Support", "member_ids": [23, 24], "dry_run": true}""")!;
payload["product_version"] = Environment.GetEnvironmentVariable("BINADIT_PRODUCT_VERSION") ?? throw new InvalidOperationException("Read the product version first");
var result = await client.Api(token, "POST", "/api/v1/accounts/123/workspaces/7/shared-mailboxes", payload, version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "PUT", "/api/v1/accounts/123/workspaces/7/mailboxes/23/delegates/24", JsonNode.Parse("""{"level": "full", "send_as": true, "calendar_level": "write", "dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("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.
var result = await client.Api(token, "DELETE", "/api/v1/accounts/123/workspaces/7/mailboxes/23/delegates/24", JsonNode.Parse("""{"dry_run": true}"""), version: Environment.GetEnvironmentVariable("BINADIT_RESOURCE_VERSION") ?? throw new InvalidOperationException("Read the current ETag first"), key: Environment.GetEnvironmentVariable("BINADIT_REQUEST_KEY"));
Verder werken
Pagineren zonder resources over te slaan
string? cursor = null;
var seen = new HashSet<string>();
for (int page = 0; page < 20; page++)
{
var path = "/api/v1/accounts/123/domains?limit=25";
if (cursor is not null) path += "&cursor=" + Uri.EscapeDataString(cursor);
var result = await client.Api(token, "GET", path);
foreach (var domain in result.Data!["data"]!.AsArray()) Console.WriteLine(domain!["id"]);
cursor = result.Data["meta"]?["next_cursor"]?.GetValue<string>();
if (cursor is null) break;
if (!seen.Add(cursor)) throw new InvalidOperationException("Repeated pagination cursor");
if (page == 19) throw new InvalidOperationException("Page limit reached; explicitly continue from the saved cursor");
}
Een lege lijst kan nog wel een volgende cursor hebben. Alleen de vertrouwde eigen resourcepath wordt gebruikt; geen externe next-URL.
PDF in een nieuw privébestand opslaan
var result = await client.Api(token, "GET", "/api/v1/accounts/123/billing/invoices/45/pdf", binary: true);
var options = new FileStreamOptions { Mode = FileMode.CreateNew, Access = FileAccess.Write, Share = FileShare.None };
if (!OperatingSystem.IsWindows()) options.UnixCreateMode = UnixFileMode.UserRead | UnixFileMode.UserWrite;
await using var output = new FileStream("factuur-45.pdf", options);
await output.WriteAsync(result.Bytes);
Op Windows erft het bestand de map-ACL: kies een map die uitsluitend voor de bedoelde gebruiker toegankelijk is. Log de PDF-bytes niet.
Webhookhandtekening controleren
// Obtain these raw bytes and headers from your server framework before JSON parsing.
bool valid = BinaditExample.VerifyWebhook(rawBody, deliveryIdHeader, timestampHeader, signatureHeader,
Environment.GetEnvironmentVariable("BINADIT_WEBHOOK_KEY_ID") ?? "",
Environment.GetEnvironmentVariable("BINADIT_WEBHOOK_SECRET") ?? "");
if (!valid) throw new InvalidOperationException("Reject this webhook");
// Next: atomically insert the delivery ID (UNIQUE) and enqueue work in your DB.
De volledige helper hierboven gebruikt HMACSHA256 en CryptographicOperations.FixedTimeEquals. Configureer een bodylimiet en valideer ontbrekende en dubbele headers in je framework. Sla de delivery-ID en het werkitem in één transactie op vóór het 2xx-antwoord. Een geldig al opgeslagen bericht krijgt opnieuw 2xx zonder dubbele uitvoering. Deze helper is geen kant-en-klare webhookserver en maakt geen duurzame replayopslag.