List devices (paginated, filterable; supports keyset cursor)
GET
/devices/:id
Get device details
POST
/devices/provision
Pre-create a device row before any agent has enrolled. Returns a single-use enrollment payload.
POST
/devices/:id/move-org
Relocate a device to a different organization within the same partner.
POST
/devices/:id/commands
Send command to device. Rejects a duplicate refresh_inventory with 409 ALREADY_PENDING.
POST
/devices/bulk/commands
Send the same command to many devices. Returns commands, skipped, and failed arrays.
DELETE
/devices/:id
Decommission device
GET /devices supports a cursor-based paging mode in addition to the legacy page/limit shape. Pass cursor, sort (hostname / lastSeen / enrolled), sortDir, limit (max 1000), and optional filters like orgIds, siteIds, groupIds, includeDecommissioned, and includeTotal. The response carries { devices, nextCursor, limit, total? }; pass nextCursor back as cursor to fetch the next page. The list payload also exposes mainAgentSilentSince and watchdogStatus per device so callers can render the Agent silent (watchdog OK) badge described in Agent Watchdog.
Permanently dismiss an alert. Terminal and valid from any status (including resolved); dismissed alerts are hidden from GET /alerts unless you filter to status=dismissed
POST
/alerts/bulk
Bulk state change for up to 100 alerts — action is one of acknowledge, resolve, suppress, or dismiss
GET /patches accepts ?source= (microsoft, apple, linux, third_party, custom) and returns source on every patch. Third-party patches also carry version, vendor, and a cveIds array populated by OSV.dev enrichment.
The vulnerabilities dashboard is a fleet-wide, fix-first queue. The /software endpoints power the default By software view (findings grouped by the update that clears them); / powers the By CVE view. Bulk and /remediate endpoints let you triage across every affected device at once.
Method
Path
Description
GET
/vulnerabilities
List open findings, one row per CVE (By CVE view)
GET
/vulnerabilities/software
List findings grouped by remediation unit (By software view)
Unified tracked-incident + EDR-finding feed (see below)
GET /incidents/feed merges native tracked incidents (kind: "tracked", source: "breeze") with not-yet-promoted Huntress and SentinelOne findings (kind: "finding", source: "huntress" or "s1") into a single feed, ordered by severity rank (p1 first) then detection time (most recent first).
severity is p1-p4. trackedIncidentId is null unless a finding has already been promoted to a tracked incident; linkOut carries a link to the EDR console for finding rows when the provider exposes one. Raw EDR finding rows additionally require devices:read – a caller with only alerts:read sees native tracked incidents only.
Just-in-time elevation: UAC-intercept and technician JIT-admin requests, approvals, and the executable/signer rules that auto-decide them. Full request/response shapes and the elevation flow live in PAM API; this section covers the endpoint surface and rule-matching fields.
Method
Path
Description
GET
/pam/elevation-requests
List and filter elevation requests
GET
/pam/active
List currently-active (unexpired, approved) elevations
POST
/pam/elevation-requests/:id/respond
Approve or deny a pending request
POST
/pam/elevation-requests/:id/revoke
Revoke an active elevation before it expires
GET
/pam/rules
List executable/signer auto-decision rules
POST
/pam/rules
Create a rule
POST
/pam/rules/preview
Preview which recent requests a draft rule would have matched
A rule matches an elevation candidate on one or more of these fields (POST/PATCH /pam/rules); at least one is required:
Field
Type
Notes
matchSigner
string
Code-signer name (executable rule). Mutually exclusive with matchSignerGroupId
matchSignerThumbprint
string
SHA-256 Authenticode signer certificate thumbprint – 64 hex characters (/^[0-9a-fA-F]{64}$/), stored lowercased. Pins the rule to one exact code-signing certificate. Mutually exclusive with matchSignerGroupId
matchSignerGroupId
uuid | null
Reference a reusable signer group instead of matchSigner/matchSignerThumbprint
matchHash
string
SHA-256 file hash, 64 hex characters
matchPathGlob
string
Executable path glob
matchParentImage
string
Parent process image path
matchCommandLine
string
Command-line substring/glob
matchUser
string
Subject username
matchAdGroup
string
Subject AD group
matchSignerGroupId cannot be combined with matchSigner or matchSignerThumbprint on the same rule – a rule pins to a group or to a direct signer identity, not both; the API rejects the combination with a 400.
Reach a discovered LAN device’s web UI through a bridge agent. The proxy page first mints a one-time ticket, then all browser traffic flows through the reverse-proxy route (authenticated by a signed, path-scoped cookie — no bearer token on the proxied requests).
Method
Path
Description
POST
/tunnels/:id/http-ticket
Mint a one-time HTTP-proxy ticket (5-min TTL) for a tunnel session
ALL
/tunnel-http/:tunnelId/*
Authenticated HTTP reverse proxy to the target device’s web UI
Saved reports schedule via schedule (daily / weekly / monthly) plus a config.schedule object (time, day, date) that pins the exact run time, and config.emailRecipients (up to 50 addresses) that emails the generated file – a branded PDF attachment for pdf-format reports, CSV for csv/excel – on every scheduled run. Both are validated and persisted on create and update.
Selected catalog and billing operations. Resource CRUD follows the standard REST pattern under /catalog, /invoices, /quotes, and /contracts; the endpoints below are the bulk and assist operations most useful to integrators.
Method
Path
Description
POST
/catalog/enrich
AI-draft a catalog item’s fields from a product name or SKU (returns a draft to review; writes nothing)
POST
/invoices/bulk-issue
Issue multiple draft invoices
POST
/invoices/bulk-void
Void multiple invoices (with a shared reason)
POST
/invoices/bulk-delete
Delete multiple draft invoices
POST
/quotes/bulk-send
Send multiple draft quotes
POST
/quotes/bulk-delete
Delete multiple draft quotes
GET
/quotes/:id
Get quote detail, blocks, lines, branding, and any staged Pax8 order summary (pax8OrderId, pax8OrderLineCount)
POST
/contracts/bulk-cancel
Cancel multiple contracts
POST
/contracts/bulk-delete
Delete multiple draft contracts
Bulk endpoints accept a list of IDs and return per-item results, so partial success is possible.
Pax8 integration and ordering routes require partner or system scope plus billing:manage. An organization-scoped token is refused even when it can access the target organization. Partner-scoped callers use the partner from their token. System-scoped callers supply partnerId only on routes that accept it and require it for system scope. Company map and subscription link/unlink routes instead derive the partner from their tenant-scoped integrationId. Every mutation is MFA-gated and audited.
Method
Path
MFA
Description
GET
/pax8/integration
No
Get the active integration and credential-presence/sync-status fields
POST
/pax8/integration
Yes
Create or update the integration; queues an initial sync when active
POST
/pax8/integration/test
Yes
Test the active integration; returns `{ success, data?
POST
/pax8/sync
Yes
Queue a company, subscription, and product sync; returns { queued, jobId, integrationId }
GET
/pax8/companies
No
List company mappings and non-PII ordering-readiness flags
POST
/pax8/companies/map
Yes
Map, unmap, or ignore a Pax8 company
GET
/pax8/subscriptions
No
List subscription observations, contract-line linkage, and Breeze billing quantities
POST
/pax8/subscriptions/link
Yes
Link or re-point a subscription snapshot to a manual contract line
DELETE
/pax8/subscriptions/link
Yes
Unlink a subscription snapshot (idempotent)
GET
/pax8/products
No
List up to 200 active catalog items mapped to Pax8 products
GET
/pax8/products/:productId/provision-details
No
Read live Pax8 provisioning-field metadata for a product
GET
/pax8/products/:productId/dependencies
No
Read live Pax8 commitment/dependency rules for a product
GET
/pax8/orders
No
List orders; optional orgId returns that organization’s history
GET
/pax8/orders/:id
No
Get { order, lines } for an accessible order
POST
/pax8/orders
Yes
Create or reuse the organization’s mutable direct order
POST
/pax8/orders/:id/lines
Yes
Stage a new subscription, quantity change, or cancellation on a mutable direct order
PATCH
/pax8/orders/:id/lines/:lineId
Yes
Update commitment/provisioning values on a mutable new-subscription line, including a quote-staged line
DELETE
/pax8/orders/:id/lines/:lineId
Yes
Remove a line from a mutable direct order
POST
/pax8/orders/:id/preflight
Yes
Mock-validate new-subscription lines with Pax8; returns the raw Pax8 body on 422
POST
/pax8/orders/:id/submit
Yes
Claim and execute the order once; returns per-line outcomes
POST
/pax8/orders/:id/reconcile
Yes
Read Pax8 state to classify uncertain writes; never issues a Pax8 write
GET
/pax8/drift?integrationId=:id
No
List known Pax8 quantity observations that differ from linked Breeze manual quantities
GET /pax8/companies returns { data, integrationId }. Each row includes the mapping fields plus these readiness booleans:
{
"statusActive": true,
"primaryAdminReady": true,
"primaryBillingReady": true,
"primaryTechnicalReady": true,
"orderReady": true
}
orderReady is true only when the company is Active and the synchronized metadata contains primary Admin, Billing, and Technical contacts. Contact PII is not returned. POST /pax8/companies/map accepts:
Set orgId to null to unmap it. A direct order requires exactly one non-ignored, order-ready mapping. Quote acceptance can stage an order without a mapping; preflight and submit resolve and validate the mapping later.
GET /pax8/subscriptions supports integrationId, orgId, unmappedOnly, and limit (1–500, default 100). Important quantity and linkage fields are:
Field
Meaning
breezeQuantity
The linked manual contract line’s billing quantity, or null when not linked/available
quantity
Pax8’s latest reported quantity string; inspect quantityKnown before using it
quantityKnown
false when Pax8 did not provide credible quantity evidence; an unknown value is not zero
contractLineId
The linked Breeze contract line, when present
syncEnabled
Whether scheduled sync records quantity observations for this link; it does not authorize overwriting billing quantity
lastObservedQuantity, lastObservedAt
Last recorded known Pax8 observation for a sync-enabled link
activeCommitmentId, activeCommitmentAmbiguous
Evidence used to select the commitment that governs quantity and cancellation actions
GET /pax8/drift requires integrationId and returns { data }, where each row contains contractLineId, orgId, pax8SubscriptionId, productName, breezeQuantity, and pax8Quantity. Results are limited to sync-enabled links on manual contract lines whose Pax8 quantity is known and differs from Breeze. The endpoint performs no Pax8 call and no write.
GET /pax8/products returns local, active mappings as { data: [{ pax8ProductId, catalogItemId, catalogName, catalogSku, catalogDescription, productName, vendorSkuId, billingFrequency, commitmentTermMonths }] }. It does not call Pax8. Provisioning details and dependencies do call the configured Pax8 API.
GET /pax8/products/:productId/provision-details:
{
"data": [{
"key": "msDomain",
"label": "Microsoft domain",
"description": null,
"valueType": "Input",
"possibleValues": null
}]
}
GET /pax8/products/:productId/dependencies:
{
"data": {
"commitments": [{
"id": "commitment-id",
"term": "Annual",
"allowForQuantityIncrease": true,
"allowForQuantityDecrease": false,
"allowForEarlyCancellation": false,
"cancellationFeeApplied": false
}]
}
}
Provision fields may have valueTypeInput, Single-Value, or Multi-Value. Their submitted representation is { "key": "...", "values": ["..."] }. Pax8 does not expose reliable requiredness metadata, so clients should not invent required fields; preflight is authoritative.
POST /pax8/orders accepts { "orgId": "<uuid>" } and returns the order in { data } with 201. If that organization already has a mutable direct order, the same order is returned. Quote-originated orders are created by quote acceptance, not this endpoint.
Order status is one of draft, awaiting_details, ready, submitting, completed, partially_failed, failed, or cancelled. Each line has a submitState of pending, in_flight, succeeded, failed, or needs_reconcile. GET /pax8/orders?orgId=<uuid> returns the organization’s complete, newest-first history (up to 100); without orgId, it returns the accessible non-terminal partner queue. GET /pax8/orders/:id returns { data: { order, lines } }.
Stage lines on a mutable direct order with POST /pax8/orders/:id/lines. The body is strict—unknown fields are rejected—and depends on action. Public callers cannot add lines to a quote-staged order.
New subscription—pax8ProductId, catalogItemId, billingTerm, and a quantity greater than zero are required:
The pax8ProductId and catalogItemId must be the exact active tuple returned by GET /pax8/products; both the Pax8 integration and catalog item must still be active when the line is staged and again when it is submitted. Do not mix a Pax8 product ID with a different catalog item. A direct new-subscription request cannot supply contractLineId.
Existing subscription quantity—targetSubscriptionId and a quantity of zero or greater are required:
{
"action": "change_quantity",
"targetSubscriptionId": "subscription-id",
"quantity": "15"
}
Cancellation—targetSubscriptionId is required. Cancellation is immediate, not scheduled:
{
"action": "cancel",
"targetSubscriptionId": "subscription-id"
}
For immediate cancellation, omit cancelDate as shown. If a caller includes it, use the current UTC calendar date (YYYY-MM-DD); future-dated cancellation is unsupported and rejected with 422 so Breeze cannot set the billing quantity to zero before Pax8 cancellation takes effect.
For change_quantity and cancel, do not send contractLineId. The strict public schema rejects caller-controlled linkage. Breeze derives exactly one linked manual contract line from targetSubscriptionId, uses its manual quantity as billing truth, and fails closed if the link or quantity is missing or changes during authorization.
Valid billing terms are Monthly, Annual, 2-Year, 3-Year, One-Time, Trial, and Activation. Quantity changes and cancellations are rejected with 422 when the active commitment cannot be determined or does not allow that action. A target subscription must belong to the order’s organization. Only one change or cancellation may target a given subscription in an order.
The line-create response is { data: <line> } with 201. PATCH /pax8/orders/:id/lines/:lineId accepts at least one of commitmentTermId (string or null) and provisioningDetails; it applies only to a mutable new_subscription line and deliberately preserves its quote/catalog/contract linkage. Public add and delete operations are direct-order-only. Quote-staged lines are immutable in membership: clients cannot add or delete them, and may only complete their commitment/provisioning values through this PATCH. Deleting a mutable direct-order line returns { "removed": true }.
POST /pax8/orders/:id/preflight sends a Pax8 mock order for the order’s new_subscription lines. An order containing only quantity changes/cancellations returns { "ok": true } without a mock call because those actions were dependency-checked while staged. Success is { "ok": true }; validation failure is HTTP 422 with Pax8’s raw JSON or text body so clients can associate details[] with the relevant line.
POST /pax8/orders/:id/submit claims the order and its pending lines before making any external write. A concurrent submit loses the claim with 409. The response is HTTP 200 even when some work needs attention:
Treat the returned status and every line’s submitState as the result—not HTTP 200 alone. Successful linked actions update only manual contract-line quantities; cancellation records 0. A definitive Pax8 rejection becomes failed. A timeout, transport error, or server response whose write outcome is uncertain becomes needs_reconcile.
Call POST /pax8/orders/:id/reconcile instead. It performs read-only Pax8 order/subscription lookups and returns { "resolved": <number>, "stillUnknown": <number> }. It never repeats the write. When stillUnknown is nonzero, leave the order for manual investigation.
Accepting a Pax8-backed quote stages its order transactionally without sending anything to Pax8. The authenticated GET /quotes/:id response persists discoverability across reloads:
pax8OrderId is null and pax8OrderLineCount is 0 when no Pax8-backed order was staged. Use the ID with GET /pax8/orders/:id, then complete provisioning and submit through the normal endpoints.
Core ticket CRUD follows the standard REST pattern under /tickets; the endpoints below cover soft-delete, restore, and bulk actions.
Method
Path
Description
GET
/tickets?deleted=only
List soft-deleted tickets (the Archived queue). Requires tickets:manage.
DELETE
/tickets/:id
Soft-delete a ticket. Requires tickets:manage. Reversible; by-id operations on a deleted ticket return 404.
POST
/tickets/:id/restore
Restore a soft-deleted ticket. Requires tickets:manage.
POST
/tickets/bulk
Bulk assign / status change / delete across up to 100 ticket IDs. The delete action requires tickets:manage; assign and status changes require tickets:write. Returns per-ticket updated/skipped/failed counts.
Over the transport, the server speaks JSON-RPC 2.0. Alongside tools/* and resources/*, it advertises an instructions string on initialize and a prompts capability with five guided MSP workflows, exposed via the prompts/list and prompts/get methods. See MCP Server → Guided prompts.
GET /devices accepts a limit of up to 500 per page (default 50) so partners can pull large fleets in fewer round trips; other list endpoints keep the standard default of 100. The dashboard’s devices list has its own per-page selector (10–200).