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.

Order spam filters and restore the original delivery

Portal, API, and Rust CLI use the same order, invoice, recurring agreement, and delivery task. Save original_purchase_id from the answer. This is an existing order, not a key that allows someone without current rights to order.

Ordering

In the portal, under Spam filters → Order, choose the company, your own domain, the services, target servers and your own aliases. Automatically adjusting MX records is an explicit choice. The server calculates the price and period. Check the shopping cart and verify yourself with a current passkey or TOTP. The approval is valid for 24 hours for exactly this order. At each supplier step, the portal rechecks the person, security settings, company rights, payment agreement and original supplier.

You can create a quotation via the API with POST /api/v1/accounts/{account}/order-quotes, kind: "spam_filter" and input:

{
  "kind": "spam_filter",
  "input": {
    "domain_id": 123,
    "products": {"incoming": true, "outgoing": false, "archiving": false},
    "destinations": [{"hostname": "mail.example.nl", "port": 25}],
    "aliases": [],
    "manage_dns": true
  }
}

Review and confirm the quote using the existing orders endpoint and one persistent idempotency key. Use the published API guide for OAuth, price checking, and normal order steps. Multiple filters in one business order use one joint checkout and separate original delivery tasks. A service connection is not given an invented human identity.

queued means the original checkout has been confirmed locally. It does not prove a completed delivery. awaiting_payment means delivery is pending on the existing invoice. A late payment notification does not automatically extend an expired approval and may not create a second invoice or agreement.

View the same order

In the portal, open /module_spam/purchases/ORIGINAL_UUID. The screen shows the original choices and price. Refresh Status only reads local, controlled metadata. The original person uses the original active business context; another tab cannot silently replace this context.

The API uses:

GET /api/v1/accounts/{account}/spam/purchases/{original_uuid}

This requires spam:read and orders:read. A personal connection must represent the same original person and identity generation. A service connection can read its own original service command; that assignment is not transferred to any random person. The customer endpoint does not accept platform authority for another company.

The answer contains id, account_id, filter_id, order_id, task_id, version, filter_version, company_version, checkout_state, invoice_id, supplier_state, completion_verified, requires_reconciliation and the public original choices under review. A native assignment also shows the end time of its native approval. The private supplier and financial proofs, authentication data and signatures remain on the server.

Only completion_verified: true confirms both the original service and the local order. A vendor response without confirmed local storage does not count as completion.

Refresh, check and follow up

The portal shows three explicit actions. Always check the domain, services, target servers, price and company first and verify again when prompted.

Action Behavior
Renew consent 24 hours The same native portal user reapproves the same original assignment; no invoice, payment, task or supplier request is created.
Check existing result Only read at supplier/accounting and proven local completion. No new supplier change.
Continue this original order Only original steps that have never been attempted may be sent. An uncertain sent request is first read and never recreated.

The corresponding customer API paths are POST .../spam/purchases/{original_uuid}/actions/renew, /actions/reconcile, and /actions/continue. Use a current personal connection from the same person, recent strong authentication, and the original current order/module permissions. Renewal and continuation require enabled writes. If new writes are disabled, only reconciliation with a new strongly authenticated read connection can continue: current native order/write permissions and the saved original scope boundary remain required, but only reads and proven local completion occur. Renewing through the API binds the real current personal connection to the same original request and scope boundary. The initial HTTP request, original principal, and quote are not replaced. A revoked old connection will therefore not receive any new rights.

Send the exact current versions from GET and the appropriate confirmation:

{
  "confirm_original_id": "11111111-1111-4111-8111-111111111111",
  "confirm_filter_id": 456,
  "version": "64-hex-characters-from-GET",
  "filter_version": "64-hex-characters-from-GET",
  "company_version": "64-hex-characters-from-GET",
  "confirm_no_supplier_mutation": true
}

For /renew, replace only the last field name with confirm_renew_original; for /continue by confirm_continue_original. 412 means re-read and check. These restores take no new Idempotency-Key, dry-run or automatic retry. The existing UUID is retained even after a network error.

A known financial receipt can restore the original local checkout without checking out again. If a paid original has no agreement yet and has never dispatched an agreement request, explicit continuation can create the first original agreement. A previously uncertain subscription.add will not be resent. An uncertain invoice or filter creation response without trusted original evidence remains blocked: provide support with the original reference and do not create a new order. A missing or incomplete initial API receipt can also block recovery; a current connection is not proof that that original application was successful.

Rust CLI

binadit spam purchases get ORIGINAL_UUID
binadit spam purchases renew ORIGINAL_UUID --confirm-original ORIGINAL_UUID --input review.json --yes
binadit spam purchases reconcile ORIGINAL_UUID --confirm-original ORIGINAL_UUID --input review.json --yes
binadit spam purchases continue ORIGINAL_UUID --confirm-original ORIGINAL_UUID --input review.json --yes

review.json contains the confirmation object shown above with real current versions. The CLI checks UUID, filter and response format and only shows the public fields. Renewal and continuation first check the current capability. These commands do not create a new local mutation intent or request key. --wait, --all, --dry-run, --idempotency-key and global version/body overrides are rejected for these commands.

Contract for AI agents

  1. Read the actual quote and current capability. Never invent a price, account mapping, person, grant or supplier identifier.
  2. Preserve the first request body, key, principal and original_purchase_id. A new key is not recovery.
  3. Distinguish checkout acceptance, recurring agreement acknowledgement, supplier creation, DNS child completion and final local publication. A queue status is not evidence of service completion.
  4. Read the original metadata before an explicit action. Supply the exact original/filter/company versions and the matching single confirmation. Never send a replacement checkout or invoice ID.
  5. Renewal changes only separately retained current authority. It preserves the immutable first approval, financial/source ceilings and original task. Foreign-company platform administration needs its own explicit server contract.
  6. Reconciliation may inspect known original effects and finish local publication. It cannot discover an uncertain create by name, repeat POST, replace an unknown agreement, send an unattempted DNS notification or adopt someone else's service.
  7. If a retained PATCH was accepted but its reply was lost, read its original result. Only a separately confirmed continuation can send a remaining never-attempted notification; do not PATCH again.
  8. On 409, preserve the original and explain the held phase. On 412, reread and have the exact current review confirmed. On missing trusted ACK evidence, stop automatic mutation and use the original support reference.

Abandon an order that never started

POST /api/v1/accounts/{account}/spam/purchases/{original}/actions/abandon uses the same three versions and confirmations as recovery, with confirm_never_attempted_abandon: true. Rust: binadit spam purchases abandon ORIGINAL_UUID --confirm-original ORIGINAL_UUID --input abandon.json --yes. The portal shows the same action for a prepared order.

The server locks the same original request as checkout. The order can only be canceled without a checkout witness, invoice, agreement, supplier attempt or child. The original row remains as signed evidence, the local job is canceled, and the unused filter identity is released. An uncertain answer from accounting, payment or supplier remains blocked; this action does not repeat anything and does not withdraw payment. After network loss, check the original status; do not create a replacement request based on a missing response.

Local business assignment by administrators

From your own real management context, use POST .../accounts/{operator}/admin/spam/assignments/review with filter_id, source_account_id, target_account_id. The response gives filter_version, source_version, target_version. Submit these values with the same three IDs and confirm_assignment: true to POST .../accounts/{operator}/admin/spam/assignments, using the regular idempotency key. Rust: binadit spam assignments review --input selection.json and binadit spam assignments commit --input reviewed-assignment.json --yes. The portal uses the same service after passkey checking and also checks the originally displayed versions.

This is local metadata adoption for unbound filters. An existing periodic agreement, original order or pending change requires a separately reviewed contract transfer and is rejected with a 409. Primary domains and aliases must already demonstrably belong to the target company; saved old MX records must be restored or reconciled first. The action does not change any supplier, invoice, agreement or DNS record and does not tacitly transfer any payment responsibility.