# Compliance API

> Read daily compliance evidence for SOC 2, PCI DSS and HECVAT, ask for and download signed evidence packs, change the settings and connect Drata or Sprinto.

Source: https://dev.apitraffic.io/docs/api-reference/compliance

Compliance records, every day, the state of the API controls ApiTraffic can see, and maps them to the controls of the frameworks you are audited against. See [Compliance](https://dev.apitraffic.io/docs/compliance) for how it works in the app, and [Compliance platforms](https://dev.apitraffic.io/docs/compliance-platforms) for pushing evidence to Drata or Sprinto.

**Availability:** on for every account. While it is switched off for an account, every route here answers `404` with `COMPLIANCE_NOT_ENABLED`. **Plan:** the view needs **Compliance** (`complianceView`), packs need **Evidence packs** (`complianceEvidencePacks`) too, and the compliance platform routes need **Compliance platform push** (`complianceGrcPush`). **Permissions:** any member, or an API token, reads the evidence and asks for and downloads packs. Changing the settings, and connecting, mapping (with listing the platform's controls) and pushing packs to compliance platforms, are for owners and admins, signed in: an API token cannot. A token with access scopes needs `security:read` to read and `security:write` to ask for a pack.

**Scope:** evidence is kept for the whole account and for each environment, never per bucket. The routes that read evidence take `environmentSid`; without it, a signed-in member reads the whole account. An API token belongs to one environment: without `environmentSid`, or with its own, it reads that environment, and asking for another environment is refused. Listing packs and asking for one also refuse it the account-wide packs (an empty `environmentSid`). A credential tied to no environment reads them all, and one limited to some buckets is refused.

## Control states

A control's state on a day comes from its evidence checks, or its supporting checks when it has none:

| State | Meaning |
| --- | --- |
| `pass` | Every counted check passed. |
| `attention` | A counted check needs attention. |
| `partial` | Some passed; the rest had no records that day. |
| `not_assessed` | No records that day. |
| `records` | Backed by record exports only: evidence without a verdict. |

Counts are counts of controls, never a percentage.

## Frameworks

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/frameworks`

The frameworks in the compliance library: `frameworks`, each with `id` (`soc2`, `pci-dss`, `hecvat`), `name`, `version`, `kind` (`controls`, or `questionnaire` for HECVAT), `enabled` (on for the account) and `items` (its controls or questions).

## Overview

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/overview`

Each framework that is on, with `items` (how many controls it has) and `counts` of controls in each state on `asOf` (the last day of the period with evidence), and the period's `exceptions`. Also `period`, `libraryVersion` (the compliance library in use), `snapshotLibraryVersions` (those the period's evidence was recorded with), `notes` (why a check's state changed when the library changed) and `cannotSee`: what ApiTraffic cannot see for you.

### Query parameters

- **environmentSid (query, string)**: One environment's evidence. Omit for the whole account (an API token reads its own environment; see Scope above).

- **from (query, string)**: First day of the period (`YYYY-MM-DD`, UTC). Default: the saved audit period, or the last 12 months.

- **to (query, string)**: Last day of the period. Default: yesterday, or today once the checks have been run today.

## Run the checks now

`POST https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/run`

Asks for the checks to run now, for every environment and the whole account, instead of waiting for the daily run. Within a minute or two, today is recorded as it stands. The next daily run records the same day again, in full. Asking while a run is waiting or under way, or within a minute of the last one finishing, returns that run. Owners and admins, or an `administrator` API token; a credential limited to some buckets is refused.

- **status (string, required)**: `requested` (waiting for the processor), `running`, `done` or `failed` (with `error`; ask again).

- **requestedBy (string | null, required)**: The person who asked, or `null` when the first visit to an account with no evidence asked.

- **day (string | null, required)**: The UTC day the run recorded, once it is `done`.

The overview returns the latest run as `run`. The first time it is read for an account with no evidence, it asks for one.

## Exceptions

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/exceptions`

Takes the same query parameters as the overview. Returns `period` and `exceptions`: every check in attention on any day of the period.

- **checkId (string, required)**: The check.

- **title (string, required)**: Its title.

- **attentionDays (integer, required)**: Days in attention in the period.

- **open (boolean, required)**: Still in attention on the period's last day.

- **spans (object[], required)**: Each run of days in attention: `from`, `to`, `reason`, and `resolvedOn`, the day it passed again.

- **usedBy (object[])**: The controls it backs: `framework`, `item` and `coverage` (`evidence` or `supporting`).

## A framework's controls

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/frameworks/{frameworkId}`

Takes `environmentSid`, `from` (default: 90 days before yesterday) and `to`. Returns the framework with `counts` and `controls`, each with:

- **id (string, required)**: The control or question id (`CC6.1`, `6.3.3`).

- **title (string, required)**: Its title, and `section` when the framework has sections.

- **state (string, required)**: Its state on `asOf`.

- **strip (object[], required)**: Its state on each day of the period: `day` and `state`. `days` counts the days in each state.

- **checks (object[], required)**: The checks and exports behind it: `kind` (`check` or `export`), `id`, `title`, `coverage`, `state` and `reason`. `counted` lists the checks its state comes from.

- **shows (string | null)**: What ApiTraffic shows for it.

- **stillNeed (string | null)**: What you still need: the part of the control you cover yourself.

- **suggestedAnswer (object | null)**: For a questionnaire (HECVAT): `answer` to copy, for `state`. Check it against your copy of the workbook before you send it.

## One check on one day

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/checks/{checkId}`

Takes `environmentSid` and `day` (default: yesterday). Returns the check's `state`, `reason` and `detail` on that day, `productionOnly`, `usedBy`, and `records`: each record behind it as it was that day, with `kind`, `key`, `state`, `since` (the day it took that state) and `data`. Records never hold request data. `truncated` is `true` when there were more records than the 1,000 listed.

## Evidence packs

A pack is a zip file for one framework (or all of them) and one period, with `summary.pdf`, CSV files, `manifest.json` and `manifest.sig`. See [Evidence packs](https://dev.apitraffic.io/docs/compliance#evidence-packs).

- **sid (string, required)**: The pack's identifier (`cpk_` and 24 hex digits).

- **frameworkId (string, required)**: A framework id, or `all`.

- **environmentSid (string | null)**: The environment, or `null` for the whole account.

- **periodStart (string, required)**: First day, and `periodEnd` the last.

- **kind (string, required)**: `monthly`: the canonical pack generated on the 2nd of each month; `on_demand`: asked for.

- **status (string, required)**: `queued`, `building`, `ready` or `failed` (with `error`).

- **manifestSha256 (string | null)**: The SHA-256 of `manifest.json`, which `manifest.sig` signs with `signatureAlgorithm` and the key `keyId`.

- **libraryVersion (string | null)**: The compliance library it was built with.

- **fileCount (integer | null)**: Files in the pack, and `byteSize` its size.

- **requestedBy (string | null)**: Who asked for it; `null` for a monthly pack.

- **retainUntil (string | null)**: Kept until then: six years. Locked until then too where the storage has Object Lock (Amazon S3), not on storage without it (DigitalOcean Spaces).

- **bucketSids (string[] | null, required)**: The buckets a pack asked for covers, or `null` for every bucket.

### List packs

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/packs`

Newest first. Takes `environmentSid` (empty for account-wide packs only), `limit` (1 to 100, default 50) and `before` (packs created before this time, for paging). A token lists its own environment's packs. Returns `packs` and `configured`: `false` when this installation has no storage for evidence packs, so none can be built or asked for (`COMPLIANCE_PACKS_NOT_CONFIGURED`).

### Get a pack

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/packs/{packSid}`

### Ask for a pack

`POST https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/packs`

- **frameworkId (body, string, required)**: A framework id, or `all` for every framework that is on.

- **environmentSid (body, string)**: One environment. Omit for the whole account (an API token gets a pack for its own environment).

- **bucketSids (body, string[])**: Some buckets only (1 to 50): their records, each check judged again from them, and the account-wide checks (account settings, posture) as the account's. Omit for every bucket. The pack's `manifest.json` lists `scope.bucketSids`, `scope.accountWideChecks` and `scope.recordsWithoutBucket`.

- **from (body, string, required)**: First day (`YYYY-MM-DD`), within the six years evidence is kept.

- **to (body, string, required)**: Last day, up to yesterday.

Returns the pack, `queued`. It is built within a few minutes. A pack asked for never replaces a month's canonical pack. An account may ask for a limited number of packs a day; past it the answer is `429` with `COMPLIANCE_PACK_LIMIT`.

### Download a pack

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/packs/{packSid}/download`

Records the download in the account history, then redirects (`302`) to a link valid for 60 seconds. With `link=true` it answers `200` with `url` and `expiresInSeconds` instead. A pack that is not `ready` answers `409`.

## Settings

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/settings`

`PATCH https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/settings`

- **frameworks (string[], required)**: The frameworks on. `frameworksSet` is `false` while following the default: every framework.

- **slaDays (object, required)**: `critical` (critical and KEV findings, 30 by default) and `high` (90 by default): days a finding may stay open.

- **auditPeriod (object, required)**: `start` and `end` of the default period, or `null`.

- **separatePackEnvironments (string[], required)**: Environments that also get their own monthly pack.

A change takes any of `frameworks` (`null` for the default), `slaCritical` and `slaHigh` (1 to 365, `null` for the default), `auditPeriodStart`, `auditPeriodEnd` and `separatePackEnvironments`. Owners and admins, signed in. Every change is recorded in the account history.

## Compliance platforms

`{provider}` is `drata` or `sprinto`.

### List platforms

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/integrations`

Returns `platforms`, each with `key`, `name`, `auth` (what connecting needs: `fields`, each with `key`, `label`, `secret`, `required` and `options`), `targetLabel` (`control` or `monitor`), `maxFileBytes`, and `connection`: the account's connection, or `null`. A credential is never returned.

### The connection object

- **provider (string, required)**: The platform.

- **status (string, required)**: `connected` (pushing), `needs_mapping` (no control mapped, so nothing is pushed), `failing` (three days of failures in a row) or `revoked` (the platform refused the credential: connect again).

- **config (object, required)**: Settings that are not secret: `region`, `workspaceId`.

- **credentialHint (string | null)**: The credential's last four characters.

- **failedDays (integer, required)**: Days in a row pushing failed, with `lastFailureDay` and `lastError`.

- **lastSyncedAt (string | null)**: The last successful push.

### Get a connection

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/integrations/{provider}`

The connection with its `mappings` and recent `pushes` (`packSid`, `status`: `queued`, `pushing`, `pushed`, `failed` or `skipped`, `attempts`, `error`, `remoteId`, `pushedAt`).

### Connect

`PUT https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/integrations/{provider}`

- **credentials.apiKey (body, string)**: The platform's API key or token. Omit to keep the stored one and change only `config`.

- **config.region (body, string)**: The platform's region.

- **config.workspaceId (body, string)**: Drata: the workspace evidence goes to.

The credential is checked with the platform before it is stored, encrypted. Returns the connection and, for Drata, `workspaces` the key can see. Owners and admins, signed in.

### Disconnect

`DELETE https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/integrations/{provider}`

Destroys the credential and removes the mappings and push history. Evidence already in the platform stays there.

### Map controls

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/integrations/{provider}/targets`

`GET https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/integrations/{provider}/mappings`

`PUT https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/integrations/{provider}/mappings`

`targets` lists the platform's controls (Drata) or monitors (Sprinto), each with `id`, `code` and `label`, searched with `q`. With `suggest=true`, `suggestions` holds a suggested target for each control of the frameworks on.

`PUT mappings` replaces the mappings with `mappings`, each with `frameworkId`, `controlId`, `targetId` and `targetLabel` (up to 1,000). With none, the connection needs mapping and nothing is pushed. Every change is recorded in the account history.

### Push a pack now

`POST https://api.apitraffic.io/v1/accounts/{accountSid}/compliance/integrations/{provider}/push`

- **packSid (body, string, required)**: A ready, account-wide pack.

Queues the push and returns `queued`. Monthly packs are pushed on their own. Owners and admins, signed in.

## Errors

| Status | Code | When |
| --- | --- | --- |
| 400 | `COMPLIANCE_PERIOD_INVALID` | The period is not two dates in order, within the six years evidence is kept. |
| 400 | `COMPLIANCE_SETTINGS_INVALID`, `COMPLIANCE_MAPPING_INVALID` | A setting or mapping names something that is not there. |
| 400 | `COMPLIANCE_INTEGRATION_REFUSED` | The platform did not accept the credential or settings. |
| 403 | `COMPLIANCE_SCOPE_NOT_ALLOWED` | The credential asked for another environment than its own or for the account-wide packs, or it is limited to some buckets. |
| 404 | `COMPLIANCE_NOT_ENABLED` | Compliance is switched off for the account. |
| 404 | `COMPLIANCE_FRAMEWORK_NOT_FOUND`, `COMPLIANCE_CHECK_NOT_FOUND`, `COMPLIANCE_PACK_NOT_FOUND`, `COMPLIANCE_INTEGRATION_NOT_FOUND` | Not found. |
| 409 | `COMPLIANCE_PACK_NOT_READY` | The pack is not ready to download yet. |
| 429 | `COMPLIANCE_PACK_LIMIT` | Too many packs asked for today. |
| 503 | `COMPLIANCE_PACKS_NOT_CONFIGURED`, `COMPLIANCE_INTEGRATION_UNAVAILABLE` | Packs are not available on this installation, or the platform could not be reached. |
