Getting started
Choose a language above. Each language guide includes a complete reusable HTTP client and the same important tasks. Source files are in docs/examples/; these are inspectable examples, not a separate official SDK package. Python and JavaScript use only their standard libraries; PHP requires cURL and C# uses .NET 10. Run JavaScript on the server, even when the rest of your application uses TypeScript.
Under Account → API and integrations, create a dedicated service connection with minimal scopes. Have your secret manager provide BINADIT_CLIENT_ID and BINADIT_CLIENT_SECRET. The client uses them to request one short-lived token through POST /oauth/token with grant_type=client_credentials. It does not save or print the secret or token. You can supply a personal token obtained by your own OAuth application through BINADIT_ACCESS_TOKEN. Do not extract personal tokens from the CLI's system keychain. For normal interactive use, run binadit login.
A service credential cannot replace recent human verification. Team invitations, webhook administration, enabling Send As and deleting rooms may require an authorised person with recent strong verification. Use your own approved personal OAuth connection or the existing CLI for those actions. The snippets do not bypass company policy or feature flags. Exchange and legacy balance top-ups remain outside this release.
The clients use only https://my.binadit.com, normal TLS verification, a timeout and no redirects or automatic retries. The fixed origin prevents a pagination or payment URL from unintentionally receiving a Bearer token. For your own test installation, deliberately change the origin constant; do not disable certificate verification. The examples read at most 8 MiB per response. Use a separate bounded streaming implementation for larger files.
Supplying values and versions
All example.test addresses, documentation IP addresses, IDs and UUIDs are fictional. Replace them with resources read through the same company connection. 123 is the company, 7 a Workspace, 23/24 mailboxes, 8 a DNS zone and 12 a mail domain. An ID from another company grants no authority.
For pagination, follow meta.next_cursor even when permission filtering leaves the data array empty. The language guides show a bounded loop that also rejects repeated cursors. Do not follow an arbitrary next-page URL with your token.
The client returns etag and data; data is the complete JSON envelope, for example result.data.data in JavaScript. C# uses ETag, Data and, for a PDF, Bytes. Associate each ETag with its exact resource. For version-controlled mutations, the language guide identifies the GET to perform first. Put that reviewed ETag or explicit plan version in BINADIT_RESOURCE_VERSION. Do not invent a hash or use a version belonging to another object.
Before sending each reviewed write, durably preserve the original principal, method, URL, exact JSON, resource version and a random Idempotency-Key containing 16–128 safe characters. Supply that original key through BINADIT_REQUEST_KEY. A UUID is suitable: generate it once in your own durable request store, not again on every script launch. As a precaution, the example clients also require a key for read-oriented POST requests; that does not turn those endpoints into mutations.
Write examples use dry_run: true where relevant. A dry run does not save an executable order, grant or DNS plan. For real execution, review the preview first, read current versions and preserve the final JSON without dry_run together with its own key. Do not paste all examples into one sequence: each snippet is a separate task with its own input and key. A dry run of a sensitive action does not remove its human-verification requirement.
Ordering, paying and cancelling
- Read products, your company holder and capabilities. Ask the server for pricing; do not calculate your own selling price.
- Review a quote preview. Then deliberately request a saved quote by omitting
dry_run. Use the actualdata.idand inspect that same quote with GET. A preview ID must not be treated as a real quote. - Preview confirmation through
orderswithdry_run: true. Only after approval, submit that same quote ID withoutdry_run, with a durably recorded key for that action. This can create an invoice and order.orders:commitand current ordering/spending privileges remain required. - The order may return
checkout_url. Open it separately in a browser to confirm payment. Never send the Binadit token to the payment provider or fetch that URL with the example client. - Follow the original operation and read the domain again.
queuedorawaiting_paymentdoes not prove registration. Check registrar status, DNS publication and subscription/automatic renewal separately.
Cancelling a domain disables automatic renewal; it does not immediately delete the registration. Afterwards, read domains/{id}/subscription again and check the recorded end date and billing status. Hosting and other services have their own cancellation intents; a domain and a hosting package are separate agreements.
DNS and Workspace
DNS always goes through the Binadit API and the existing portal processing. Read records, create a plan, review the records and version, then apply the original plan separately. A template plan is also a proposal. Never use PowerDNS, NS1 or Cloudflare credentials directly in these clients. The record value field is value; CNAME targets follow the portal notation without a trailing dot. When updating or deleting, use record IDs actually returned by the read, not their positions in a newly sorted list.
Personal and shared mailboxes are paid products. Order a personal mailbox through a quote of kind workspace_mailbox; shared mailboxes follow their own paid contract. The delegate, calendar, mailing-list and room examples are free and require no product or invoice. full also grants Send on Behalf; send_as is a separate sensitive choice. When Send As is disabled while full remains, recipients see the delegate again. A list member is an existing typed ID such as mailbox-24, not an external address or nested list. Rooms have no login password; recurring meetings are checked only for their first occurrence. See the complete mail contract.
Errors, uncertain outcomes and progress
| Outcome | Action |
|---|---|
| 401 | Stop. First check whether a mutation could already have been sent. Request a new token for subsequent deliberate actions; do not automatically repeat a POST. |
| 403/404 | Check the company, scopes, resource restrictions and any human-verification requirement; do not work around the refusal with another company or administrator token. |
| 409 | Inspect the existing request or blocker. Do not replace it with a new key, quote or supplier request. |
| 412/428 | Read the correct resource again and review the changed situation; do not force a fresh ETag onto an old command. |
| 422 | Check fields, types and the OpenAPI contract. |
| 429 | Respect Retry-After. The helpers do not retry. Inspect an uncertain mutation before later reading again or requesting another action. |
| Timeout/5xx | The outcome may be unknown. Keep the original metadata and inspect the operation. A timeout does not prove that the server performed no action. |
operation.request_status: succeeded confirms the HTTP receipt, not necessarily the supplier action. Follow operation.status, including queued, running, awaiting_payment, requires_approval, requires_reconciliation, failed and succeeded. A held free mail task is requires_reconciliation, not a payment request. A failed colleague/DNS task is no reason to submit a second paid order.
Keep returned operation, plan and intent IDs with your original request. With operations:read, poll the same operation at a bounded rate, for example once every five seconds for at most two minutes per script execution. Stop at a review or payment status; do not force it through. After a new personal login, the original principal may have changed: use the original receipt rather than automatically replaying under the new connection.
The clients deliberately report errors without the unfiltered response body. Do not log Bearer tokens, client secrets, one-time claims, personal details, mail content or PDFs. One-time password and key claims have a separate protocol and do not belong in a generic retry loop.
Receiving webhooks
The language guides include an HMAC check for the unmodified raw body and the three headers Binadit-Webhook-Id, Binadit-Webhook-Timestamp and Binadit-Webhook-Signature. Obtain the expected key ID and secret from your own secret manager. Use TLS, check the time window, compare in constant time, then prevent replay with a unique delivery ID in durable storage. A valid signature alone does not prevent duplicate execution.
After verification, atomically record the delivery ID and a work item in one database transaction with a unique constraint. Return 2xx only after that commits. An already durably received, validly signed delivery gets 2xx again without repeating its work. Never process an invoice notification twice. When rotating keys, retain only deliberately approved key IDs belonging to your integration; never trust an unknown key_id from a header.
Contract and verification
Examples are generated from the actual operation catalog and shared recipes. Routes, scopes, methods and JSON bodies are checked locally against OpenAPI. The client code is separately executed against a local test receiver; this does not modify customer data or submit paid production actions. Development notes alongside the source record the PHP/Python/Node versions and .NET build check. This is not a claim that every illustrated paid action was ordered on production in all four languages.
The examples follow the current release scope, API reference and agent guide. Standard-library references: HttpClient redirects, Node fetch and timeouts.
Tasks available in every language
| Task | Method | Scope |
|---|---|---|
| Check the authenticated identity | GET |
account:read |
| List accessible companies | GET |
account:read |
| Check capabilities and scopes | GET |
account:read |
| Read company details and their ETag | GET |
account:read |
| Update company details | PATCH |
account:write |
| Read products and prices | GET |
products:read |
| List existing domain holders | GET |
holders:read |
| Preview a default holder from company or personal details | POST |
holders:read, holders:write |
| Create a company domain holder | POST |
holders:write |
| Check domain availability | POST |
domains:read |
| Quote a domain registration | POST |
orders:write |
| Read a saved quote again | GET |
orders:read |
| Preview an order and payment | POST |
orders:commit |
| Read registration renewal and subscription status | GET |
domains:read |
| Disable automatic domain renewal | POST |
domains:write |
| List DNS zones | GET |
dns.zones:read |
| Read current DNS records and version | GET |
dns.records:read |
| List DNS templates | GET |
dns.templates:read |
| Preview a DNS template | POST |
dns.templates:write |
| Propose applying a template | POST |
dns.records:write |
| Preview multiple DNS records in one plan | POST |
dns.records:write |
| Apply a reviewed DNS plan | POST |
dns.records:write |
| Follow the original operation | GET |
operations:read |
| List invoices | GET |
billing.invoices:read |
| Download an invoice PDF | GET |
billing.invoices:read |
| List Workspaces | GET |
workspace:read |
| List mailboxes | GET |
workspace.mailboxes:read |
| Read delegates and user-configured shares | GET |
workspace.mailboxes:read |
| Grant full mail access and calendar editing | PUT |
workspace.mailboxes:write |
| Preview a free mailing list | POST |
workspace.mailboxes:write |
| Add one mailing-list member | PUT |
workspace.mailboxes:write |
| Remove one mailing-list member | DELETE |
workspace.mailboxes:write |
| Preview a free room | POST |
workspace.mailboxes:write |
| Add a room manager | PUT |
workspace.mailboxes:write |
| Delete a room with personal verification | DELETE |
workspace.mailboxes:write |
| List hosting subscriptions | GET |
hosting:read |
| Preview hosting cancellation | POST |
hosting:write |
| List spam filters | GET |
spam:read |
| Invite a colleague with limited permissions | POST |
team:write |
| Preview a paused webhook | POST |
webhooks:write |
| Inspect webhook deliveries | GET |
webhooks:read |
| Read the current product version | GET |
products:read |
| Quote a paid personal mailbox | POST |
orders:write |
| Preview a paid shared mailbox | POST |
workspace.mailboxes:write, orders:commit |
| Enable Send As separately | PUT |
workspace.mailboxes:write |
| Revoke mail and calendar access together | DELETE |
workspace.mailboxes:write |