# Bitdefender GravityZone Cloud Public API Reference

> **Authoritative product + API docs:** GravityZone Support Center —
> https://www.bitdefender.com/business/support/en/77211-79436-welcome-to-gravityzone.html
> (everything about the product and the Public API). Use it to confirm any
> UNVERIFIED method/param below before relying on it.

Verified spec for the methods used by this skill. Sourced from Bitdefender's
archived Public API documentation. Methods are flagged **VERIFIED** (signature
confirmed and exposed in the CLI) or **UNVERIFIED** (signature not confirmed —
callable only via the generic `raw` subcommand, never exposed as a dedicated CLI
command).

---

## Connection

- **Base URL:** `https://cloud.gravityzone.bitdefender.com/api/v1.0/jsonrpc`
- **Module endpoint:** `<base>/<module>` (e.g. `.../jsonrpc/network`)
- **Auth:** HTTP Basic. Username = API key, password = empty string `""`.
- **Transport:** HTTPS POST, `Content-Type: application/json`.

### JSON-RPC envelope (request)

```json
{
  "id": "1",
  "jsonrpc": "2.0",
  "method": "<methodName>",
  "params": { ...method params... }
}
```

### Response

- **Success:** body has a `result` field. The skill returns `body["result"]`.
- **Error:** body has an `error` object. The skill surfaces
  `error.data.details` if present, else `error.message`.

```json
{ "error": { "code": -32602, "message": "...", "data": { "details": "..." } } }
```

---

## ACG tenant IDs (hardcoded, partner root)

| Constant | Value | Meaning |
|---|---|---|
| `ACG_ROOT_COMPANY_ID` | `5c4280716c0318f3478b456a` | ACG partner company root |
| `ACG_COMPANIES_CONTAINER_ID` | `5c4280716c0318f3478b456e` | Container holding all client companies |

In `getNetworkInventoryItems` results, `type == 1` denotes a company node.

---

## general (`/general`)

| Method | Params | Status | Notes |
|---|---|---|---|
| `getApiKeyDetails` | `{}` | VERIFIED | Key scopes / rights. |

## licensing (`/licensing`)

| Method | Params | Status | Notes |
|---|---|---|---|
| `getLicenseInfo` | `{}` | VERIFIED | Seats, expiry, usage. CLI `status`. |
| `getMonthlyUsage` | `{}` | VERIFIED LIVE | endpoint/encryption/email/mobile monthly usage. CLI `monthly-usage`. |
| `getMonthlyUsagePerCompany` | — | DOES NOT EXIST | "method not found". |

## integrations (`/integrations`)

| Method | Params | Status | Notes |
|---|---|---|---|
| `getConfiguredIntegrations` | `page?, perPage?` | VERIFIED LIVE | Configured third-party integrations (empty live). CLI `integrations`. |
| `getPSAIntegrationList` / `getIntegrationsList` | — | DOES NOT EXIST | wrong names; "method not found". |

## packages (detail)

| Method | Params | Status | Notes |
|---|---|---|---|
| `getPackageDetails` | `packageId (req)` | VERIFIED (probe) | Installation package detail. CLI `package-details`. |

## companies (`/companies`) — COMPLETE (6 methods; no updateCompany/getCompaniesList)

> `updateCompany` and `getCompaniesList` return "method not found" — they do NOT
> exist. Enumerate companies via `network.getNetworkInventoryItems` (the `companies`
> CLI cmd). `type`: 0=Partner, 1=Customer.

| Method | Params | Status | Notes |
|---|---|---|---|
| `getCompanyDetails` | `{}` or `{companyId}` | VERIFIED LIVE | Own company when no arg. CLI `company [id]`. |
| `getCompanyDetailsByUser` | `username` | VERIFIED LIVE | Company that owns a user. CLI `company-by-user`. |
| `createCompany` | `type (req), name (req), parentId?, address?, country?, state?, phone?, industry?, canBeManagedByAbove?, assignedProductType?, licenseSubscription{type,reservedSlots,endSubscription,autoRenewPeriod,...}` | VERIFIED (docs + probe) | CLI `company-create`, gated. STATE-CHANGING. Docs: 77211-126236-createcompany.html |
| `suspendCompany` | `companyId` | VERIFIED (probe) | CLI `company-suspend`, gated. STATE-CHANGING. |
| `activateCompany` | `companyId` | VERIFIED (probe) | CLI `company-activate`, gated. STATE-CHANGING. |
| `deleteCompany` | `companyId` | VERIFIED (probe) | CLI `company-delete`, gated. STATE-CHANGING. |

## network (`/network`)

| Method | Params | Status | Notes |
|---|---|---|---|
| `getNetworkInventoryItems` | `parentId?, page?, perPage?, filters?` | VERIFIED | Inventory tree: companies/groups/endpoints. `type==1` = company. |
| `getEndpointsList` | `parentId?, page?, perPage<=100, filters?, options?` | VERIFIED | Endpoint list under a parent. `filters` supports name / OS / security status / policy. |
| `getManagedEndpointDetails` | `endpointId, options?` | VERIFIED | Full detail: `malwareStatus`, `agent{productVersion,engineVersion,signatureOutdated,productOutdated,lastUpdate}`, `modules`, `state`, `policy`, `companyId`, `lastSeen`. |
| `getScanTasksList` | `name?, status?, page?, perPage?` | VERIFIED | List scan tasks. |
| `createScanTask` | `targetIds[], type, name?, customScanSettings?` | VERIFIED | Start a scan. `type`: 1=Quick, 2=Full, 3=Memory, 4=Custom (verify against console). |
| `moveEndpoints` | `endpointIds[], groupId` | VERIFIED | Move endpoints into a group. |
| `createCustomGroup` | `name, parentId?` | VERIFIED | Create a custom group; returns new group id. |
| `deleteEndpoint` | `endpointId` | VERIFIED (destructive) | Remove an endpoint from inventory. CLI-gated behind `--confirm`. |
| `deleteCustomGroup` | `groupId` | VERIFIED (destructive) | Delete a custom group. CLI-gated behind `--confirm`. |
| `moveCustomGroup` | `groupId, parentId` (NOT newParentId — verified live) | VERIFIED | Re-parent a custom group. |
| `assignPolicy` | `policyId, targetIds[], forcePolicyInheritance?, inheritFromAbove?` | VERIFIED (docs+probe) | CLI `assign-policy`, gated. See policies section. |
| `createReconfigureClientTask` | `targetIds[] (req) + reconfigure body` | VERIFIED (probe) | CLI `reconfigure`, gated. STATE-CHANGING. |
| `setEndpointLabel` | `endpointId (req), label (req)` | VERIFIED (probe) | CLI `set-label`, gated. STATE-CHANGING. |
| `getEndpointTags` | `{}` | VERIFIED LIVE | List endpoint tags (returns a list). CLI `endpoint-tags`. |
| `createUninstallTask` + variants | — | DOES NOT EXIST | No uninstall-task method under `/network` in this API version (createUninstallTask / createUninstallClientTask / createUninstallRoleTask / uninstallClientTask all "method not found"). Uninstall via the console. |
| `getEndpointsByPolicy`, `getManagedEndpointDetailsByIp`, `createScanTaskByMailboxes` | — | DOES NOT EXIST | "method not found" on this tenant/version. |

## packages (`/packages`)

| Method | Params | Status | Notes |
|---|---|---|---|
| `getPackagesList` | `page?, perPage<=100` | VERIFIED | List installation packages. |
| `createPackage` | `packageName, companyId?, description?, language?, modules?, scanMode?, settings?, roles?, deploymentOptions?` | VERIFIED | Create an installer package. Returns the new package id. |
| `getInstallationLinks` | `packageName, companyId?` | VERIFIED | Returns Windows / Mac / Linux installer download URLs for a package. |
| `deletePackage` | `packageId` | VERIFIED (destructive) | Delete a package. Param is `packageId` (NOT packageName/companyId - those error "not expected", verified live 2026-06-21). CLI: `delete-package --id <packageId> --confirm`. |

## policies (`/policies`) — FULL READ + ASSIGN (authoring is console-only)

> **Corrected 2026-06-21:** the earlier "shallow only" claim was WRONG.
> `getPolicyDetails` returns the COMPLETE granular module configuration
> (general/antimalware/firewall/content-control/etc.), confirmed live on a real
> policy. You CAN: list policies, read the full config, and assign an existing
> policy to endpoints/groups (`network.assignPolicy`, param shape now verified).
> You still CANNOT **create / edit / clone** a policy body via the Public API —
> authoring stays in the GravityZone console.

| Method | Params | Status | Notes |
|---|---|---|---|
| `getPoliciesList` | `page?, perPage?` | VERIFIED | List policies (id, name). |
| `getPolicyDetails` | `policyId` | VERIFIED | **Full** granular config (not shallow). |
| `assignPolicy` (`/network`) | `policyId, targetIds[], inheritFromAbove:false (REQUIRED w/ policyId), forcePolicyInheritance?` | VERIFIED LIVE 2026-06-21 | Assigning a policyId REQUIRES `inheritFromAbove:false` in the same call or the API rejects with a misleading "inheritFromAbove should not be used" error. `{targetIds, inheritFromAbove:true}` (no policyId) = make target inherit. CLI `assign-policy`, gated. |

## reports (`/reports`) — COMPLETE

| Method | Params | Status | Notes |
|---|---|---|---|
| `getReportsList` | `page?, perPage?` | VERIFIED LIVE | List saved reports. CLI `reports`. |
| `createReport` | `name (req), type, targetIds, recurrence/format...` | VERIFIED (probe) | CLI `report-create --name [--extra-json]`, gated. STATE-CHANGING. |
| `getDownloadLinks` | `reportId (req)` | VERIFIED (probe) | Report download links. CLI `report-links --id`. |
| `deleteReport` | `reportId (req)` | VERIFIED (probe) | CLI `report-delete --id`, gated. STATE-CHANGING. |
| `getReportConfiguration` | — | DOES NOT EXIST | "method not found". |

## accounts (`/accounts`) — COMPLETE (all 7 methods wrapped)

| Method | Params | Status | Notes |
|---|---|---|---|
| `getAccountsList` | `page?, perPage?` | VERIFIED LIVE | List console accounts/users. CLI `accounts`. |
| `getAccountDetails` | `accountId?` | VERIFIED LIVE | No id ⇒ the API key's own account. CLI `account [id]`. |
| `getNotificationsSettings` | `{}` | VERIFIED LIVE | Notification config. CLI `notif-settings`. |
| `createAccount` | `email (req), userName, password, role, profile{fullName,language,timezone}, phoneNumber{countryCode,subscriberNumber}, rights{manageInventory,managePoliciesRead/Write,...}` | VERIFIED (docs + probe) | CLI `account-create`, gated. STATE-CHANGING. Docs: 77212-125284-createaccount.html |
| `updateAccount` | `accountId (req) + fields` | VERIFIED (probe) | CLI `account-update --id --set-json`, gated. STATE-CHANGING. |
| `deleteAccount` | `accountId (req)` | VERIFIED (probe) | CLI `account-delete --id`, gated. STATE-CHANGING. |
| `configureNotificationsSettings` | settings object (NO required field — empty payload is accepted) | VERIFIED (probe) | CLI `notif-configure --settings-json`, gated. STATE-CHANGING. ⚠ never probe with `{}` on a live tenant — it is a setter. |

## push (`/push`) — event push service (VERIFIED reachable)

> Powers event-driven alerting (GravityZone POSTs security events to a receiver
> you specify) instead of polling `sweep`. `get`/`stats` error with "…were not
> set" until configured — that is an EXPECTED unconfigured state, handled cleanly
> by the CLI (rc0 + INFO), NOT a failure.

| Method | Params | Status | Notes |
|---|---|---|---|
| `getPushEventSettings` | `{}` | VERIFIED LIVE | Current settings. CLI `push-settings`. |
| `getPushEventStats` | `{}` | VERIFIED LIVE | Delivery stats. CLI `push-stats`. |
| `sendTestPushEvent` | `eventType (req)` | VERIFIED (probe) | Fire a test event to the configured receiver. CLI `push-test --event-type`, gated. |
| `setPushEventSettings` | `status (req), serviceType, serviceSettings{url,requireValidSslCertificate,authorization}, subscribeToEventTypes{<event flags>}` | VERIFIED (official docs + probe) | Configure the service. `serviceType` ∈ `splunk`/`cef`/`jsonRPC`. Receiver MUST support TLS 1.2+. `subscribeToEventTypes` is a map of event flags (av, fw, aph, registration, task-status, modules, network-sandboxing, antiexploit, dp, uc, …) set true to subscribe. Returns bool. CLI `push-set`, gated. STATE-CHANGING. Needs a receiver URL. Docs: 77209-135319-setpusheventsettings.html

> Receiver pattern for the webhook (Phase-2): stand up an HTTPS endpoint (TLS
> 1.2+, valid cert) that accepts GravityZone's event POSTs — a coord-API route
> or an RMM ingest route — then `push-set --status 1 --url <that-endpoint>
> --confirm`. `serviceType jsonRPC` posts JSON-RPC event batches.

## quarantine (`/quarantine`)

| Method | Params | Status | Notes |
|---|---|---|---|
| `getQuarantineItemsList` | `companyId, page, perPage, filters?` | VERIFIED LIVE | Service-scoped path `quarantine/computers`. CLI `quarantine --company`. |
| `createRemoveQuarantineItemTask` | `quarantineItemsIds (req)` | VERIFIED (probe) | Path `quarantine/computers`. CLI `quarantine-remove --items`, gated. STATE-CHANGING. |
| `createRestoreQuarantineItemTask` | `quarantineItemsIds (req), addExclusionInPolicy?` | VERIFIED (probe) | CLI `quarantine-restore --items [--extra-json]`, gated. STATE-CHANGING. |

## incidents (`/incidents`) — EDR / incident response

> The incidents module backs the EDR controls: endpoint isolation, the hash
> blocklist, and the incident list. READ methods are safe; the state-changing
> methods (isolate / restore / blocklist add+remove) are CLI-gated behind
> `--confirm`. `isolate` and `addToBlocklist` / `removeFromBlocklist` are NEW
> destructive verbs — the `raw` subcommand also gates any method whose name
> contains `isolat`, `addtoblocklist`, or `removefromblocklist`.

| Method | Params | Status | Notes |
|---|---|---|---|
| `getBlocklistItems` | `companyId?, page?, perPage?` | VERIFIED LIVE | Returns `{total, page, perPage, pagesCount, items:[{id, source, sourceInfo, hashType, hash, companyId}]}`. Returned 26 items live. `perPage` defaults to 100 in the CLI. `companyId` scopes to one company; omit for the whole tenant. |
| `getIncidentsList` | `parentId, page?, perPage (500-10000), filters?` | UNVERIFIED / possibly unavailable | `parentId` = a company/group id and is REQUIRED. `perPage` must be 500-10000 (the API rejected 100 with "Invalid value for 'perPage' parameter. The value should be between 500 and 10000"); the CLI defaults it to 500. **However**, live re-testing on 2026-05-30 returned `Method not found` for this method on the `/incidents` module, while `getBlocklistItems` on the SAME module succeeds in the same request — so this is NOT rate-limiting or a bad key. The method is likely gated behind an EDR/incidents license feature that is OFF on this tenant, or is named differently in this API version. The CLI `incidents` subcommand is wired up but will surface `Method not found` until the feature is enabled / the correct name is confirmed. |
| `createIsolateEndpointTask` | `endpointId` (SINGLE) | VERIFIED LIVE 2026-06-21 | Takes ONE `endpointId` per call (NOT an `endpointIds` array — that errors "not expected"). Client loops for multiple. Cuts endpoint off network (BD mgmt link preserved). CLI `isolate`, gated. |
| `createRestoreEndpointFromIsolationTask` | `endpointId` (SINGLE) | VERIFIED LIVE 2026-06-21 | One `endpointId` per call. FAILS if the isolation task is still in progress ("cannot be restored") — wait + retry. CLI `unisolate`, gated. |
| `addToBlocklist` | `companyId, hashType, hashList[], sourceInfo, operatingSystems?` | VERIFIED (destructive) | `hashType` is an int (1 is the common value seen live; see the console / API docs for the full mapping). `hashList` is an array of hash strings. `sourceInfo` is a free-text description. CLI-gated behind `--confirm`. |
| `removeFromBlocklist` | `hashItemId` *(UNVERIFIED param name)* | VERIFIED method, UNVERIFIED param | Removes one blocklist entry. The param name `hashItemId` is UNVERIFIED — the `id` field from `getBlocklistItems` is the candidate. Confirm against the official API reference before relying on it. CLI-gated behind `--confirm`; the CLI `--id` value comes from `blocklist` output. |
| `getCustomRulesList` | `page?, perPage?` | VERIFIED LIVE | EDR custom rules (returned 1 live). CLI `custom-rules`. |
| `createCustomRule` | `name (req), settings/companyId/tags via extra` | VERIFIED (probe) | CLI `custom-rule-create`, gated. STATE-CHANGING. |
| `deleteCustomRule` | `ruleId (req)` | VERIFIED (probe) | CLI `custom-rule-delete --id`, gated. STATE-CHANGING. |
| `changeIncidentStatus` | `type (req) + id/status` | VERIFIED (probe) | CLI `incident-status --type --set-json`, gated. STATE-CHANGING. |
| `updateIncidentNote` | `type (req) + id/note` | VERIFIED (probe) | CLI `incident-note --type --set-json`, gated. STATE-CHANGING. |

> EDR custom rules + incident status/note ARE available on this tenant even
> though `getIncidentsList` is not (that one method is feature-gated/renamed).

## Dead / unavailable modules on this tenant (probed 2026-06-21)

In the API-key scope but NOT usable — calls return "not available" / "method
not found". Do not build against these without a license/feature change:

- `patchmanagement` — license OFF (`managePatchManagement: false`). "not available".
- `phasr` — license/feature OFF. `getStatus` → method not found.
- `maintenancewindows` — `getMaintenanceWindows(List)` → "not available".
- `integrations` — PARTLY ALIVE: `getConfiguredIntegrations` works (wrapped);
  `getPSAIntegrationList`/`getIntegrationsList` are wrong names (not found).
- `incidents.getIncidentsList` — "Method not found" (yet `getBlocklistItems` and
  the isolate tasks on the SAME module work — likely an EDR sub-feature gate).

---

## Verified vs Unverified summary

**VERIFIED (CLI-exposed):**
general.getApiKeyDetails, licensing.getLicenseInfo, companies.getCompanyDetails,
network.getNetworkInventoryItems, network.getEndpointsList,
network.getManagedEndpointDetails, network.getScanTasksList,
network.createScanTask, network.createCustomGroup, network.moveEndpoints,
network.moveCustomGroup, network.deleteEndpoint (gated),
network.deleteCustomGroup (gated), packages.getPackagesList,
packages.createPackage, packages.getInstallationLinks, packages.deletePackage
(gated), policies.getPoliciesList, policies.getPolicyDetails,
quarantine.getQuarantineItemsList, incidents.getBlocklistItems,
incidents.createIsolateEndpointTask (gated),
incidents.createRestoreEndpointFromIsolationTask (gated),
incidents.addToBlocklist (gated), incidents.removeFromBlocklist (gated;
param name UNVERIFIED), network.getScanTasksList, network.assignPolicy (gated;
param shape verified 2026-06-21), reports.getReportsList, accounts.getAccountsList,
accounts.getNotificationsSettings, push.getPushEventSettings,
push.getPushEventStats, push.setPushEventSettings (gated; `status` verified,
nested shape UNVERIFIED).

> NOTE: `incidents.getIncidentsList` is wired into the CLI (`incidents`
> subcommand) but returned `Method not found` on live re-test (2026-05-30) —
> see the incidents module table. Likely a license-gated EDR feature that is OFF
> on this tenant. Not counted as VERIFIED LIVE.

**UNVERIFIED (raw subcommand only — do NOT trust the param shape):**
network.assignPolicy, network.createReconfigureClientTask,
network.createUninstallTask, network.setEndpointLabel,
companies.getCompanyDetailsByUser, quarantine.createRemoveQuarantineItemTask,
quarantine.createRestoreQuarantineItemTask, incidents.changeIncidentStatus,
incidents.updateIncidentNote, incidents.createCustomRule,
incidents.getCustomRulesList, incidents.deleteCustomRule (destructive).
Whole modules raw-only/UNVERIFIED: patchmanagement (license OFF),
integrations, maintenancewindows.

Confirm any UNVERIFIED signature against the official Bitdefender API reference
before relying on it. The generic `raw --module M --method m --params '<json>'`
subcommand can call any method once you know the correct params.
