> ## Documentation Index
> Fetch the complete documentation index at: https://docs.airmdr.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Zscaler

> The connection allows AirMDR to authenticate to Zscaler Internet Access (ZIA) and run the configured integration skills. Available operations depend on the skills supported by AirMDR and the role assigned to the credential in Zscaler.

> **Purpose**
>
> This guide explains how to create Zscaler Internet Access (ZIA) API credentials and enter them in AirMDR.
>
> \
> Connect ZIA to AirMDR to enrich web indicators (URL classification and Cloud Sandbox verdicts), read the policy and configuration that explains why traffic was allowed or blocked, resolve users, locations and devices, read the admin and event logs, and contain a threat by adding a URL, domain, IP or file hash to the tenant block lists.
>
> > [!NOTE]
> >
> > Zscaler supports **two API authentication models**, and AirMDR connects with either one. Fill in **only one** set of credentials:
> >
> > * **OneAPI (recommended):** OAuth 2.0 client credentials issued by the Zscaler **Authentication Service** (also called ZIdentity). AirMDR selects this method whenever a **Client ID** and **Client Secret** are present.
> > * **Legacy ZIA API:** an API key plus an API-capable admin username and password. Use this only for a tenant that is not yet on the Authentication Service. Zscaler is retiring legacy ZIA API authentication at the end of 2026.
> >
> > AirMDR chooses the method automatically from the fields you complete; there is no mode selector.

> **Supported Versions**
>
> | Component | Applicability |
> | - | - |
> | Zscaler service | Zscaler Internet Access (ZIA). |
> | OneAPI | OAuth 2.0 client credentials through the Zscaler Authentication Service (ZIdentity), calling ZIA endpoints under `/zia/api/v1` on `api.zsapi.net`. |
> | Legacy ZIA API | API key with admin username and password, calling ZIA endpoints under `/api/v1` on `zsapi.<cloud>`. Retired by Zscaler at the end of 2026. |
> | Optional capabilities | The Cloud Sandbox submission and IoT Discovery skills require those features to be licensed on the tenant. |
> | AirMDR integration version | Confirm the supported connector release and tested Zscaler compatibility with the AirMDR Integration team. |

> **Authentication**
>
> ### Option 1 — OneAPI (OAuth 2.0 client credentials)
>
> AirMDR exchanges the Client ID and Client Secret for a short-lived bearer token at the Authentication Service token endpoint, then calls the ZIA API with that token. The connection requires three values:
>
> | Field | Description | Where to obtain it | Example |
> | - | - | - | - |
> | **Vanity Domain** | The ZIdentity domain label for your organization. It is the first part of your Authentication Service sign-in URL `https://<vanity-domain>.zslogin.net`. A full host or a full token URL is also accepted. | Read it from the address bar when you sign in to the Authentication Service admin portal. | `acme` |
> | **Client ID** | The API client ID created in the Authentication Service. | **Administration → API Configuration → OneAPI → API Clients**, on the client you create. | `<client-id>` |
> | **Client Secret** | The secret generated for that API client. Shown only once at creation. | Generated when you create the API client with the **Secret** authentication method. | `<client-secret>` |
>
> AirMDR sends the token request exactly as Zscaler documents it:
>
> ```text theme={null}
> POST /oauth2/v1/token HTTP/1.1
> Host: <vanity-domain>.zslogin.net
> Content-Type: application/x-www-form-urlencoded
>
> grant_type=client_credentials
> client_id=<Client ID>
> client_secret=<Client Secret>
> audience=https://api.zscaler.com
> ```
>
> The returned bearer token is sent on every ZIA call as `Authorization: Bearer <access_token>` against `https://api.zsapi.net/zia/api/v1`.
>
> ### Option 2 — Legacy ZIA API (API key + admin credentials)
>
> AirMDR obfuscates the API key with a timestamp as Zscaler requires, signs in to obtain a session, and calls the ZIA API with that session. The connection requires four values:
>
> | Field | Description | Where to obtain it | Example |
> | - | - | - | - |
> | **Cloud Name** | The ZIA cloud your tenant lives on, as a bare domain. It is the part after `admin.` in your ZIA console URL. AirMDR calls `https://zsapi.<cloud>/api/v1`. | Read it from your ZIA admin console URL. | `zscalertwo.net` |
> | **API Key** | The ZIA API key. | **Administration → API Key Management** in the ZIA admin portal. | `<zia-api-key>` |
> | **Username** | The login ID of an API-capable ZIA admin account. Every change AirMDR makes is attributed to this account in the ZIA audit log. | The ZIA admin account you dedicate to the integration. | `soc@example.com` |
> | **Password** | The password of that admin account. | The ZIA admin account you dedicate to the integration. | `<password>` |
>
> ### Optional for either method
>
> | Field | Description | Example |
> | - | - | - |
> | **Base URL** | Overrides the API host. Leave empty to use the default (`api.zsapi.net` for OneAPI, `zsapi.<cloud>` for legacy). A scheme and trailing slash are both optional. | `api.zsapi.net` |
>
> > [!NOTE]
> >
> > Enter secret values (Client Secret, API Key, Password) without quotation marks or any prefix. AirMDR stores every secret field encrypted and never logs it.
>
> **Role and permission considerations**
>
> * ZIA access is governed by the role attached to the credential. A ZIA role maps to a resource in the Authentication Service for OneAPI, and to the admin account's role for the legacy API.
> * Grant a **read** role for the retrieval skills.
> * The containment skills additionally need **write** access over the ZIA security policy, URL categories and firewall destination groups, plus permission to **activate** configuration — a ZIA change is saved but not enforced until it is activated.

> **Connection Methods (direct vs Remote Agent)**
>
> ZIA is a cloud service reachable over the public internet, so AirMDR connects **directly** in the normal case and no Remote Agent is required.
>
> If your environment requires outbound API traffic to originate from a specific network, AirMDR can route the ZIA calls through a **Remote Agent**. See [Remote Agent Overview](https://docs.airmdr.com/Integrations/RemoteAgent-Overview). No credential changes are needed; attach the Remote Agent to the connection.

## Pre-requisites

> > [!TIP]
> >
> > An active Zscaler Internet Access (ZIA) tenant.
>
> > [!TIP]
> >
> > For OneAPI: a subscription to the Zscaler **Authentication Service**, and an administrator with Full permission on the **API Clients** and **API Resources** modules. Contact your Zscaler account team if the subscription is not present.
>
> > [!TIP]
> >
> > For the legacy API: a ZIA admin account with API access and an API key.
>
> > [!TIP]
> >
> > A ZIA role with the read and (for containment) write and activate permissions required by the skills you intend to use.

## Setup Steps

Complete **one** of the two methods below.

**1. OneAPI — Find your Vanity Domain**

1. Sign in to the Zscaler **Authentication Service** admin portal.
2. Look at the browser address bar. The host is `https://<vanity-domain>.zslogin.net`.
3. The `<vanity-domain>` label is the value to enter in AirMDR's **Vanity Domain** field.
   > [!NOTE]
   >
   > The Vanity Domain is assigned to your organization; you retrieve it, you do not create it. For a government (FedRAMP) tenant the identity domain is `zidentitygov.net` or `zidentitygov.us`; set **Cloud Name** to `gov` or `govus` so AirMDR builds the correct token URL.

**2. OneAPI — Create an API Client**

1. Open **Administration → API Configuration → OneAPI → API Clients**.
   > [!NOTE]
   >
   > Some tenants show this under **Integration → API Clients**. Use whichever path your tenant presents.
2. Click **Add API Client**.
3. On the **Client** tab, enter a name (for example `AirMDR-Integration`), a description, and set the status to active. Set an access token lifetime (between 1 minute and 24 hours).
4. For the client authentication method, choose **Secret**.
5. On the **Resources** tab, assign a ZIA resource/role:
   * a **read** role for the retrieval skills, or
   * a role with **write** and **activate** permissions if you will use the containment skills.
6. Save, then copy the **Client ID** and **Client Secret**.
   > [!WARNING]
   >
   > **The Client Secret is displayed only once.**\
   > Copy and securely store it in your designated password manager or vault before leaving the screen.

**3. Legacy — Create an API Key and API-capable admin**

Use this method only if your tenant is not on the Authentication Service.

1. In the ZIA admin portal, open **Administration → API Key Management** and create (or copy) the API key.
2. Ensure the admin account you will use has API access and a role covering the ZIA resources the skills read and write.
3. Note the **Cloud Name** — the part after `admin.` in your ZIA console URL (for example `zscalertwo.net`).
   > [!WARNING]
   >
   > Store the API key and the admin password securely in your designated password manager or vault.

**4. Enter the credentials in AirMDR**

1. In AirMDR, open the Zscaler connection form.
2. Complete **only** the fields for your chosen method:
   * **OneAPI:** Vanity Domain, Client ID, Client Secret.
   * **Legacy:** Cloud Name, API Key, Username, Password.
3. Leave **Base URL** empty unless Zscaler has given your tenant a dedicated API host.
4. Save the connection, then run **Verify Authentication** (see below).

## Zscaler Credential Reference Table

| AirMDR Field | Method | What to Enter | Where to Get It | Example |
| - | - | - | - | - |
| **Vanity Domain** | OneAPI | The ZIdentity domain label, the first part of `https://<vanity-domain>.zslogin.net`. | Authentication Service sign-in URL. | `acme` |
| **Client ID** | OneAPI | The API client ID. | Administration → API Configuration → OneAPI → API Clients. | `<client-id>` |
| **Client Secret** | OneAPI | The API client secret (enter only the value). | Shown once when the API client is created. | `<client-secret>` |
| **Cloud Name** | Legacy | The ZIA cloud as a bare domain. | The part after `admin.` in the ZIA console URL. | `zscalertwo.net` |
| **API Key** | Legacy | The ZIA API key (enter only the value). | Administration → API Key Management. | `<zia-api-key>` |
| **Username** | Legacy | The API-capable ZIA admin login ID. | The admin account dedicated to AirMDR. | `soc@example.com` |
| **Password** | Legacy | The admin account password (enter only the value). | The admin account dedicated to AirMDR. | `<password>` |
| **Base URL** | Optional | Overrides the API host. | Leave empty for the default. | `api.zsapi.net` |

> [!NOTE]
>
> Complete only one method's fields. AirMDR selects **OneAPI** whenever a Client ID and Client Secret are present; otherwise it uses the **legacy** fields.

## Validate Connectivity

Run the check for the method you configured. A `200` with a JSON body confirms the credential reaches the ZIA API.

### OneAPI

> [!TIP]
>
> The API client must be assigned a ZIA resource/role. A token with no ZIA resource authenticates but cannot read ZIA endpoints.

1. Open a Bash terminal on an approved system.
2. Run the following, replacing the Vanity Domain and entering the Client ID and Secret when prompted:
   > **Request Sample**
   >
   > ```text theme={null}
   > ZS_VANITY="acme"
   >
   > read -r -p "Enter Client ID: " ZS_CLIENT_ID
   > read -r -s -p "Enter Client Secret: " ZS_CLIENT_SECRET
   > printf '\n'
   >
   > ZS_TOKEN="$(curl --silent --show-error \
   >   --request POST "https://${ZS_VANITY}.zslogin.net/oauth2/v1/token" \
   >   --header "Content-Type: application/x-www-form-urlencoded" \
   >   --data-urlencode "grant_type=client_credentials" \
   >   --data-urlencode "client_id=${ZS_CLIENT_ID}" \
   >   --data-urlencode "client_secret=${ZS_CLIENT_SECRET}" \
   >   --data-urlencode "audience=https://api.zscaler.com" \
   >   | sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p')"
   >
   > curl --silent --show-error \
   >   --get "https://api.zsapi.net/zia/api/v1/status" \
   >   --header "Authorization: Bearer ${ZS_TOKEN}" \
   >   --header "Accept: application/json" \
   >   --write-out '\nHTTP status: %{http_code}\n'
   >
   > unset ZS_CLIENT_SECRET ZS_TOKEN
   > ```
3. Confirm the HTTP status is `200`. A token response carrying an `access_token` plus a `200` on `/status` means the credential is working.
   > [!NOTE]
   >
   > If the token request returns `invalid_client`, the Vanity Domain is correct but the Client ID/Secret do not belong to that tenant. If it returns a generic permission error instead of JSON, the Vanity Domain itself is wrong — recheck the sign-in URL.

### Legacy ZIA API

1. Because the legacy sign-in requires the API key to be obfuscated with a timestamp, the simplest check is to **save the connection in AirMDR and run Verify Authentication**, which performs the obfuscation, sign-in and an authenticated read for you.

## Verify Authentication in AirMDR

After saving the connection, run the **Verify Authentication** skill. It makes a real authenticated read of the activation status and the organization over whichever method the fields selected, so a credential that is wrong, revoked or missing a role is distinguished from a query that simply matched nothing. Reading the organization needs its own role, and a denial there alone does not fail the check.

## Troubleshooting

| Symptom | Likely cause | Action |
| - | - | - |
| Token request returns a generic permission error (not JSON) | Wrong Vanity Domain | Recheck the label in your Authentication Service sign-in URL. |
| Token request returns `invalid_client` | Client ID/Secret do not belong to this tenant, or the secret is wrong | Recreate or recopy the API client credentials. |
| Authenticated, but reads return 403 | The role has no ZIA resource, or lacks the required permission | Assign a ZIA read role; add write and activate for containment. |
| A containment skill succeeds but nothing is blocked | The change was saved but not activated | Confirm activation; AirMDR containment skills activate by default. |
| Legacy sign-in rejected | API key, admin credentials or Cloud Name mismatch | Confirm all four legacy fields and that the key belongs to that cloud. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.