# Vanta

Vanta is an evidence destination, not an MDM: once an MDM inventory source (Jamf Pro or Iru) is connected, the platform pushes one resource per managed device into a Vanta **private integration** on a schedule, and a Custom Test over those resources turns real agent coverage into continuously-tested compliance evidence. Shared concepts (the coverage model and what the evidence attests) are on the [MDM installations](/docs/ai-control-plane/reference/device-agent/mdm-installations) page.

## 1. Create a scope-limited private integration

In the Vanta **Developer Console**, create a private integration (OAuth application) for this integration and grant it only the **`connectors.self:write-resource`** scope: writing its own resources is all it needs.

> Dedicate this OAuth application to the Speakeasy integration. Vanta allows **one active access token per application** (every new token mint revokes the previous one), so sharing the application with a script or another tool causes the two consumers to continually revoke each other. The integration absorbs a single mid-push revocation gracefully, but a shared application will produce intermittent sync failures.

Copy the **client ID** and **client secret**; both are entered together in the dashboard and stored write-only.

## 2. Define the Custom Resource

In the integration's **Resources** tab, click **+ Create Resource** and choose the **Custom Resource** base resource type. Every record carries the three base fields Vanta requires (`uniqueId`, `displayName`, and `externalUrl`) automatically; you define the evidence fields as custom properties (JSON Type Definition):

```json
{
  "properties": {
    "serial_number": { "type": "string" },
    "hostname": { "type": "string" },
    "assigned_user_email": { "type": "string" },
    "agent_active": { "type": "boolean" },
    "agent_attestation": { "type": "string" },
    "agent_last_seen_at": { "type": "string" }
  }
}
```

| Custom property | Type | Meaning |
| --- | --- | --- |
| `serial_number` | string | Hardware serial from the MDM |
| `hostname` | string | Device name from the MDM |
| `assigned_user_email` | string | The MDM-assigned user (empty when unassigned) |
| `agent_active` | boolean | Whether the attested agent has a recent heartbeat |
| `agent_attestation` | string | `"device"` (this machine reported in) or `"user"` (only its assigned user did) |
| `agent_last_seen_at` | string | The attested agent's latest heartbeat, in RFC 3339; an empty string when no agent has ever reported |

All six properties sit under `properties` (all required). `agent_last_seen_at` is sent as an **empty string** (not omitted) for a device whose agent has never reported: Vanta's resource schema marks every declared property required, so an omitted field is rejected at sync. An empty string reads as "unknown" without implying a heartbeat that never happened.

Copy the **resource id** from the resource definition, the third and final value the dashboard needs.

## 3. Connect in the dashboard

1. Open **Device Agent → MDM Integrations**, then **Connect** on the Vanta row.
2. Enter the **OAuth client ID**, **client secret**, and **Custom Resource ID**. Credentials are stored encrypted and are never shown again after saving.
3. **Save**, then **Test connection**. The test mints a token, validating the OAuth credentials and scope. It cannot validate the resource id (the write-only scope has no read to probe with), so a typo there surfaces as a failed first sync instead.
4. Enable the connection. New connections start paused: the flow is save, test, then enable.

Once enabled, evidence pushes hourly as a **full-state sync**: each push is the complete device set, departed devices are marked gone automatically, an empty fleet truthfully clears stale evidence, and retries cannot duplicate (Vanta upserts by `uniqueId`).

## 4. Define the Custom Test

Create a Custom Test over the resource (for example, *fail when any resource has `agent_active` = false*) and map it to the relevant SOC 2 / ISO controls. One stale device fails the test and routes to an owner.

> Each resource states its own attestation strength in `agent_attestation`, and both values can appear in one push:
>
> - `"device"`: that machine's own agent reported in, matched on hardware serial. `agent_active` means **this device** is running the agent.
> - `"user"`: matched on the MDM-assigned user's email. `agent_active` means only that **the assigned user** runs the agent on some machine, which is strictly weaker.
>
> A machine whose agent cannot read a hardware serial stays `"user"` even once your organization is on device-level matching, so the strength genuinely varies row by row. `agent_last_seen_at` is an empty string when no agent has ever reported, rather than a null or a zero timestamp.
>
> If your auditor requires per-device attestation, phrase the Custom Test to require both `agent_active` = true **and** `agent_attestation` = `"device"`. Testing `agent_active` alone accepts the weaker claim.
