Skip to documentation

Exchange will be rebuilt separately and is unavailable through the API or CLI. Availability in this release

Workflow guides

Markdown

Exchange is excluded from this API/CLI release. Any historical Exchange API or CLI example in this guide is unavailable; native portal behavior is outside this exclusion. See current release scope.

One checkout for multiple new purchases

The API can check out 1 through 25 new purchases for the same company together. Each request is priced beforehand using existing portal business rules. A batch does not execute a sequence of separate quote commits: all items are prepared together and pass through one shared company checkout.

Protocol

Method and path under /api/v1/accounts/{account} Use
POST /order-batches/quotes Validate { "items": [{ "kind": "...", "input": { ... } }] } and review server prices
GET /order-batches/quotes/{quote} View approved items, payment method and monthly invoice agreement
POST /order-batches Submit { "quote_id": "..." } once with a durable Idempotency-Key

Both POST requests support dry_run: true or X-Binadit-Dry-Run: true. A quote preview stores no quotes or secrets. A commit preview creates no order, reservation, invoice, payment or delivery task.

Supported new purchases are workspace_mailbox, workspace_service, domain_register, domain_transfer, hosting_subscription, exchange_mailbox and spam_filter. input uses the same fields as a separate /order-quotes request. Renewals, package changes and cancellations continue through their existing specific actions or a separate quote.

The server returns a parent quote and child items. Child quotes have status batched and cannot be purchased separately through /orders. The parent and all child quotes expire after at most ten minutes or at the end of the day. Company, principal, prices, existing identities and the displayed payment/monthly agreement remain bound to this approval.

Billing and boundaries

The existing portal agreement remains effective. Workspace items go on the monthly invoice if the company pays on account or has a valid monthly payment agreement. Without that agreement, the remaining days of this month are charged together with the other purchases. There is at most one immediate invoice and one immediate payment for the batch. The future monthly invoice remains a separate existing company agreement.

pricing.first_period_price_excl is the amount charged immediately by this checkout. pricing.spending_liability_excl counts the higher of the first and full recurring period for each item. A small prorated contribution or deferred monthly invoice therefore cannot conceal an automation limit. One combined limit reservation is made; an uncertain failure does not release it automatically.

Multiple Hosting purchases with the same package are projected in the approved list order. A free first website and paid subsequent website each therefore receive their actual price beforehand. The server also checks combined server capacity. Native preparation must then realize exactly that order, identities and prices.

Each identity may occur only once. A new mailbox with Drive can reference a new pool in the same Workspace through drive_pool_ref. Hosting and Exchange can reference a domain registration or transfer in the same batch through domain_ref. These are typed references to items in this one company order; arbitrary task IDs, conflicting existing domain selections, duplicate identities and cyclic or invalid references are rejected before billing. Parents and children together count toward the maximum of 25 items. Submitted domain, server or account IDs are never silently replaced.

A new Drive pool and mailbox together

Give the pool item a unique ref of at most 64 characters. It starts with a letter and otherwise contains only letters, digits, _ or -. The mailbox refers to it using input.drive_pool_ref and drive: true; both items must use the same workspace_id. A reference may point to a later item in the list.

{
  "items": [
    {"kind": "workspace_mailbox", "input": {"workspace_id": 12, "domain_id": 34, "product_id": 56, "local_part": "alice", "drive": true, "drive_pool_ref": "company_pool"}},
    {"ref": "company_pool", "kind": "workspace_service", "input": {"workspace_id": 12, "product_id": 78, "service": "drive_pool"}}
  ]
}

Use this protected JSON input file with binadit orders batch quote --from-file basket.json --account 1, read the combined quote and then approve only that parent quote with binadit orders batch commit QUOTE_UUID --confirm-quote QUOTE_UUID --account 1 --yes. One company checkout follows; the existing agreement determines whether Workspace lines are invoiced immediately or on the combined monthly invoice.

The native portal service prepares the pool and mailbox together, with separate permissions per task. A durable dependency blocks the mailbox in all normal tasks and manual restarts until the original pool task is complete and the correct pool, capacity, organization and server configuration are proven. A task status of completed alone is insufficient. A missing, cancelled, failed or changed prerequisite appears as requires_reconciliation; investigate the original operation and do not order again. Prepayment must remain confirmed for every item. Reviewing/recovering the same operation creates no new invoice.

Domain registration or transfer with Hosting and Exchange

Give the domain_register or domain_transfer item a unique ref. For Hosting and Exchange, use input.domain_ref instead of domain_id or domain. The domain may appear later in the list. Other fields follow the existing schemas; the contact and packages must already be available.

{
  "items": [
    {"kind": "hosting_subscription", "input": {"product_id": 10, "domain_ref": "company_domain", "manage_dns": true}},
    {"kind": "exchange_mailbox", "input": {"product_id": 20, "domain_ref": "company_domain", "alias": "alice", "local_part": "alice", "display_name": "Alice"}},
    {"ref": "company_domain", "kind": "domain_register", "input": {"domain": "voorbeeld.nl", "product_id": 30, "holder_id": 40}}
  ]
}

The quote shows the final domain name and prices. The new domain's database identity remains null in the quote. On commit, the server first reserves the real domain identity through the same native portal service used for existing registrations. It then binds the children to exactly that reservation. Only this identity and its corresponding versions may change; package, company, server, other approved choices and costs remain unchanged. Immediately before billing, the new reservation is checked again under a lock.

All lines pass through the same combined company checkout. Prepayment also holds the domain request until the original invoice is paid. Hosting and Exchange may then contact their suppliers only after the original domain task completes and registrar activation is confirmed with the same company and supplier identity. A transfer may wait for days; child tasks remain the same and cause no new checkout. A successful purchase commit therefore does not mean supplier delivery is complete: follow the original operation with binadit operations watch OPERATION_UUID --account 1.

For automatic Hosting DNS, the approved domain template is first compared with the confirmed portal zone. Only an executing background task records a receipt with the current zone version; inspection and dry run do not. The canonical portal writer then adds Hosting records using that version while preserving other records and history. Conflicting customer changes before or after the receipt are not silently adopted as a new baseline: the existing task requires reconciliation. An unclear registrar response, changed owner, withdrawn payment or failed parent task can never be bypassed by a manual restart.

These references are available in the same CLI quote/get/commit flow as the pool example. Passwords are not supplied in the examples; the existing secure credential workflow delivers new credentials. An existing external DNS setup retains normal portal configuration; choose existing manage_dns options suitable for that setup. The CLI communicates exclusively with the portal API.

Permissions, secrets and recovery

The connection needs orders:write to quote, orders:read to read quotes and orders:commit to check out. The server also rechecks current module and resource permissions for each item. Every delivery task retains only the permissions required by its own item. Explicit administration choices remain internal administration with separate scopes and recent strong human verification. An internal administrator also follows the customer company's payment method for API purchases.

Passwords and transfer codes remain encrypted. Quotes, replayable operation results and standard CLI output do not contain them. New Workspace credentials follow the secure portal workflow.

All local resources and real held tasks are recorded before the first accounting/bank request. The financial attempt receives a durable reference beforehand. Only after confirmed checkout are all local delivery parts released or linked to payment in one transaction. A failure in one confirmation leaves all still-unconfirmed tasks held.

On batch_requires_reconciliation, billing_phase=requires_reconciliation or held_before_billing, investigate the existing operation. Do not create a new batch to bypass an unclear bank/accounting response. Repeating the same idempotency key returns the existing outcome without another debit. Check the original API-BASKET-{quote} reference, existing invoice/payment and prepared resources. Money paid while blocked does not automatically authorize new delivery or a new invoice; recovery requires checking that same intent.

See also payment recovery, the API/CLI user guide and the release boundary for sensitive API actions. This implementation has been tested locally; it is not evidence of production deployment or completed general security acceptance.

Rust CLI and original intents

The Rust implementation checks the quote, company, individual prices and total spending liability before approving the purchase. Merely creating a quote needs no purchase confirmation; checking out a basket remains a separate action with exactly the same quote UUID and explicit approval. An incorrect or incomplete response retains the original local request intent. Passwords, transfer codes, future private fields and full input do not appear in price review.

No public Rust CLI release has been activated yet. The Rust CLI permanently stores the original principal with every write key and does not send that action under a new connection. After signing in again, recovery remains linked exclusively to the proven original operation; read the original operations guide. A new connection or the same local key grants no permission to repeat an uncertain purchase. Do not create a replacement basket or commit children separately.

Hosting DNS as part of the same delivery

For hosting_subscription with manage_dns: true, the background task uses the portal's DNS connection and approved hosting template. This applies to a separate hosting order and Hosting in a basket. The API and CLI do not write directly to the DNS server. The original task rechecks company, hosting subscription, server, template version, domain and existing payment before DNS preparation starts.

The DNS intent and its reference in the same original hosting task are stored together. The canonical portal writer then executes every supplier step outside a database transaction, with a previously recorded attempt and verification of the actual outcome. A missing managed zone is created only as part of this explicitly approved Hosting DNS configuration. An unknown response is never resolved by resending the same supplier step.

For a managed DNS zone, portal records, DNS history, hosting binding, original task and original order complete together only after the supplier confirms the full outcome. For an external DNS provider, only proposed portal records and their history are stored; no supplier connection is used and this confirms no live DNS change. Configure those records yourself at that external provider. If local storage is refused, supplier evidence is retained and local changes roll back. An explicit restart of this same task can finish that local completion without resending the confirmed supplier change. After a lost response, recovery may only read to confirm the original attempt; any subsequent step may start only if it has never been attempted.

For an API order, follow the original operation with binadit operations watch OPERATION_UUID --account 123. An accepted purchase does not mean completed delivery. On revoked authorization or a reconciliation hold, the system retains the original tasks. A current company owner with a personal, recently strongly verified connection and the original required scopes can use binadit operations reapprove OPERATION_UUID --account 123 --dry-run to review recovery. Actual explicit approval of that same operation uses binadit operations reapprove OPERATION_UUID --account 123 --yes. This creates no new order or invoice. If a verifiable supplier ID is missing or the original source/template/ownership changes, let support investigate the original intent; do not create a new order.

For other AI agents: HostingDnsProvisioning connects hosting.create to DnsRecordWriter::prepareMutation, executeMutation, reconcileMutation and completeMutation. The stable hosting-task-dns:<task-id> reference and encrypted, signed journal protect the same original intent. Only explicit existing task reapproval can renew its current grant; business payload, financial source and DNS intent remain unchanged. The completion callback performs only local storage and verifies the actual stored hosting flag, task status and order. Do not remove attempt markers, clear reconciliation holds to force a new intent, or put these phases back inside LegacyResourceWrite or another outer SQL transaction.

After local commit, the original task reference, DNS binding and order completion are also read back through the write connection. A removed reference stops every subsequent supplier request. If an observer changes a completion field after commit, the portal does not report successful delivery. The already confirmed DNS receipt remains; repeating the same task does not resend these supplier steps. Local data may already have been stored at that point. Have the original task and its journal reviewed and do not create a replacement order.

Before every Hosting DNS request, original supplier permissions are also fetched again after current dependency and payment checks. Immediately afterward, the remaining validity of exactly that approval is checked without a new database query or commit. A connection revoked or expired during the last payment check therefore cannot send the DNS step anyway.