Work with Custom Connections
1. General
Custom Connections let you push your own data into Drata so it can be used for compliance evidence. The behavior depends on the provider type you choose when creating the connection:
| Provider type | Schema required? | Record endpoint |
|---|---|---|
CUSTOM |
Yes — you define the schema via schema or sampleData + displayNameKey |
/custom-connections/{connectionId}/resources/{resourceId}/records |
MDM |
No — Drata uses a fixed common device model | /custom-connections/{connectionId}/devices |
HRIS |
No — Drata uses a fixed common HRIS model | /custom-connections/{connectionId}/hris-user-identities |
Note: Passing
schema,sampleData,displayNameKey, orworkspaceIdsfor anMDMorHRISconnection will return a400 Bad Request.
Sections 3 and 4 of this recipe (record and session management) apply to CUSTOM connections only. For MDM and HRIS connections, refer to the Devices and HRIS User Identities endpoint references respectively.
For CUSTOM connections, records can be uploaded two ways:
- Direct upload — immediately live, good for incremental updates to individual records
- Session-based upload — stage a full batch before committing it; when you complete the session, Drata atomically replaces the active dataset with the new batch
The session-based approach is recommended for bulk syncs where you want an all-or-nothing replacement of your data.
2. Setup
2.1 Create a Custom Connection
POST https://public-api.drata.com/public/v2/custom-connectionsCUSTOM connection (user-defined schema)
You define the schema for your records. Use schema to provide a JSON Schema directly, or sampleData to have Drata infer the schema from a representative record. displayNameKey is required and must be a top-level key in the schema.
Option A: Provide a JSON Schema directly
{
"name": "Software Inventory",
"providerTypes": ["CUSTOM"],
"workspaceIds": [1],
"displayNameKey": "packageName",
"description": "Software packages installed across the fleet.",
"schema": {
"type": "object",
"properties": {
"packageName": { "type": "string" },
"version": { "type": "string" },
"vendor": { "type": "string" },
"installedAt": { "type": "string" },
"isApproved": { "type": "boolean" }
},
"additionalProperties": true
}
}Option B: Provide sample data and let Drata infer the schema
{
"name": "Software Inventory",
"providerTypes": ["CUSTOM"],
"workspaceIds": [1],
"displayNameKey": "packageName",
"description": "Software packages installed across the fleet.",
"sampleData": {
"packageName": "1Password",
"version": "8.10.36",
"vendor": "AgileBits",
"installedAt": "2024-01-15T00:00:00Z",
"isApproved": true
}
}| Field | Required | Description |
|---|---|---|
name |
Yes | Display name for the connection |
providerTypes |
Yes | ["CUSTOM"] |
workspaceIds |
Yes | At least one workspace ID |
schema |
No* | JSON Schema for your records. Provide either schema or sampleData, not both. *Required if sampleData is not provided. |
sampleData |
No* | A representative record from which Drata infers the schema. Provide either sampleData or schema, not both. *Required if schema is not provided. |
displayNameKey |
Yes | Top-level schema field used as the human-readable label for each record in the Drata UI (e.g. "packageName"). Must exist as a property in the provided or inferred schema. |
description |
No | Optional description |
MDM connection (fixed device model)
MDM connections use Drata's built-in device data model. Do not provide schema, sampleData, displayNameKey, or workspaceIds — MDM connections are global.
{
"name": "Fleet MDM",
"providerTypes": ["MDM"],
"description": "Device inventory synced from our MDM solution."
}After creating, use the Devices endpoints to upload device records.
HRIS connection (fixed HRIS model)
HRIS connections use Drata's built-in HRIS data model. Do not provide schema, sampleData, displayNameKey, or workspaceIds — HRIS connections are global.
{
"name": "Employee Directory",
"providerTypes": ["HRIS"],
"description": "Employee roster synced from our internal HRIS."
}After creating, use the HRIS User Identities endpoints to upload employee records.
Common fields for all connection types:
| Field | Required | Description |
|---|---|---|
name |
Yes | Display name for the connection |
providerTypes |
Yes | One of: CUSTOM, MDM, HRIS |
description |
No | Optional description |
Reference: Create Custom Connection API
2.2 Retrieve the Resource ID (CUSTOM connections only)
All CUSTOM record and session operations require a resourceId. This is created automatically when you create the connection and is tied to the schema you provided.
Fetch it by expanding customResources on the connection:
GET https://public-api.drata.com/public/v2/custom-connections/{connectionId}?expand[]=customResourcesResponse (relevant fields):
{
"id": 42,
"customResources": [
{
"id": 7,
"name": "Software Inventory",
"schema": { ... },
"createdAt": "2025-01-01T00:00:00Z",
"updatedAt": "2025-01-01T00:00:00Z"
}
]
}Use customResources[0].id as the resourceId in all subsequent record and session requests.
Reference: Get Custom Connection API
3. Managing Records Directly
CUSTOMconnections only. ForMDMandHRISconnections, use the Devices and HRIS User Identities endpoints instead.
Use the direct upload approach for incremental updates — adding, updating, or removing individual records without replacing the full dataset.
3.1 Upsert Records
Records are matched by id. If a record with that ID already exists it is updated; otherwise a new record is created. You can send a single object or an array.
POST https://public-api.drata.com/public/v2/custom-connections/{connectionId}/resources/{resourceId}/recordsRequest Payload (single record):
{
"data": {
"id": "PKG-001",
"packageName": "1Password",
"version": "8.10.36",
"isApproved": true
}
}Request Payload (multiple records):
{
"data": [
{
"id": "PKG-001",
"packageName": "1Password",
"version": "8.10.36",
"isApproved": true
},
{
"id": "PKG-002",
"packageName": "Zoom",
"version": "6.2.0",
"isApproved": true
}
]
}Note: If an active session exists for this connection/resource, directly uploaded records are automatically grouped under it.
Reference: Upsert Records API
3.2 Update a Record
Update a specific record by its recordId.
PUT https://public-api.drata.com/public/v2/custom-connections/{connectionId}/resources/{resourceId}/records/{recordId}Request Payload:
{
"data": {
"version": "8.10.40",
"isApproved": false
}
}Reference: Update Record API
3.3 Delete a Record
DELETE https://public-api.drata.com/public/v2/custom-connections/{connectionId}/resources/{resourceId}/records/{recordId}Returns 204 No Content on success.
Reference: Delete Record API
3.4 List Records
GET https://public-api.drata.com/public/v2/custom-connections/{connectionId}/resources/{resourceId}/recordsOptionally filter by session using the sessionId query parameter:
GET https://public-api.drata.com/public/v2/custom-connections/{connectionId}/resources/{resourceId}/records?sessionId=upload-2025-04-01Reference: List Records API
4. Session-Based Record Management
CUSTOMconnections only. ForMDMandHRISconnections, use the Devices and HRIS User Identities endpoints instead.
Sessions are designed for bulk syncs where you want to stage an entire dataset and commit it atomically. When you complete a session, it becomes the authoritative dataset — everything not in that session is permanently deleted.
4.1 Session States
| State | Description |
|---|---|
IN_PROGRESS |
Session is open. Records are staged but not yet live. |
ACTIVE |
Session has been completed. Its records are the live dataset. |
CANCELLED |
Session was aborted. All staged records are discarded. |
ARCHIVED |
System-managed. A previously ACTIVE session that was replaced by a newer one. Its records have been deleted. |
Only one session can be IN_PROGRESS at a time per connection/resource.
4.2 Upload Records to a Session
Choose any string as your sessionId — if the session doesn't exist yet it will be created in IN_PROGRESS state. You can call this endpoint multiple times with the same sessionId to upload in batches.
POST https://public-api.drata.com/public/v2/custom-connections/{connectionId}/resources/{resourceId}/sessions/{sessionId}Session ID rules: 3–64 characters, letters/numbers/hyphens/underscores only (e.g. upload-2025-04-01, batch_sync_v2).
Request Payload:
{
"data": [
{
"id": "PKG-001",
"packageName": "1Password",
"version": "8.10.36",
"isApproved": true
},
{
"id": "PKG-002",
"packageName": "Zoom",
"version": "6.2.0",
"isApproved": true
}
]
}Records uploaded to a session are staged and not visible as live data until the session is completed.
Reference: Upsert Records with Session API
4.3 Complete a Session
Once all records are uploaded, complete the session to make them live.
POST https://public-api.drata.com/public/v2/custom-connections/{connectionId}/resources/{resourceId}/sessions/{sessionId}/actionsRequest Payload:
{
"action": "complete"
}What happens on completion:
-
The session transitions from
IN_PROGRESS→ACTIVE - All records in the session become the live dataset
- Any previously ACTIVE session is archived and its records are permanently deleted
- Any records that were uploaded directly (not via a session) are also permanently deleted
Warning: Completing a session is destructive and irreversible. Every record not part of the completing session — including any records uploaded via the direct endpoint — will be hard deleted.
Response:
{
"sessionId": "upload-2025-04-01",
"status": "ACTIVE",
"action": "complete",
"connectionId": 42,
"resourceId": 7
}Reference: Perform Session Action API
4.4 Cancel a Session
To discard a session and all its staged records without committing them:
POST https://public-api.drata.com/public/v2/custom-connections/{connectionId}/resources/{resourceId}/sessions/{sessionId}/actionsRequest Payload:
{
"action": "cancel"
}The session transitions to CANCELLED and all staged records are deleted. The previously active dataset (if any) is unaffected.
Reference: Perform Session Action API
4.5 List Sessions
GET https://public-api.drata.com/public/v2/custom-connections/{connectionId}/resources/{resourceId}/sessionsFilter by status using the status query parameter:
GET https://public-api.drata.com/public/v2/custom-connections/{connectionId}/resources/{resourceId}/sessions?status=IN_PROGRESSReference: List Sessions API
5. Managing Custom Connections
5.1 List Custom Connections
GET https://public-api.drata.com/public/v2/custom-connectionsUse expand[] to include sub-objects in the response:
| Value | Description |
|---|---|
customResources |
Includes the resource(s) and their schemas |
createdByUser |
Includes the user or API key that created the connection |
GET https://public-api.drata.com/public/v2/custom-connections?expand[]=customResourcesReference: List Custom Connections API
5.2 Get Custom Connection
GET https://public-api.drata.com/public/v2/custom-connections/{connectionId}Supports the same expand[] values as List.
Reference: Get Custom Connection API
5.3 Update Custom Connection
Only clientAlias and description can be updated after creation.
PUT https://public-api.drata.com/public/v2/custom-connections/{connectionId}Request Payload:
{
"clientAlias": "Fleet Software Tracker",
"description": "Software packages synced nightly from our asset management tool"
}Reference: Update Custom Connection API
5.4 Delete Custom Connection
DELETE https://public-api.drata.com/public/v2/custom-connections/{connectionId}Returns 204 No Content on success. Deletes the connection and all associated records.
Reference: Delete Custom Connection API