# Batch set owners

**Endpoint:** `POST {veza_url}/api/v1/batch_set_owners`\
**Authentication:** Bearer token (`admin`, `operator`, or `nhi_security_admin` role)

Assigns, adds, or removes owners across multiple entities in a single bulk operation. Unlike the private owners API, this endpoint queries existing owner state internally — callers do not need to fetch current ownership before making changes.

Owner updates are applied asynchronously and typically reflect within a few seconds.

***

## Minimal Working Example

Assign one owner to one entity:

```bash
curl -X POST "https://your-tenant.veza.com/api/v1/batch_set_owners" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "batches": [
      {
        "entity_type": "AwsIamUser",
        "entity_ids": ["aws-iam-user-abc123"],
        "assigned_owners": {
          "owners": [
            {
              "entity_id": "okta-user-xyz789",
              "entity_type": "OktaUser"
            }
          ]
        }
      }
    ]
  }'
```

A `200 OK` with an empty body indicates success.

***

## Request Structure

### Top-Level

| Field     | Type             | Required | Description                                                                                                                                                       |
| --------- | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `batches` | array of `Batch` | Yes      | One or more batches of entity updates. All batches are validated before any are applied. Maximum 1,000 total entities and 1,000 unique owners across all batches. |

### Batch Object

Each batch targets a set of entities of the same type and applies the same owner operation to all of them.

| Field                        | Type               | Required | Description                                                                                                                                                               |
| ---------------------------- | ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `entity_type`                | string             | Yes      | Type of the entities in this batch (e.g., `AwsIamUser`). All entities must be the same type.                                                                              |
| `entity_ids`                 | array of string    | Yes      | Veza entity IDs to update. All entities in the batch receive the same owner operation.                                                                                    |
| `assigned_owners`            | `OwnersAssignment` | No       | Owners to assign. Replaces the entity's manually-assigned owners. Permanently removed owners are not re-added even if listed here. Omit (not empty) to skip.              |
| `added_owners`               | array of `Owner`   | No       | Owners to add. Applied after `assigned_owners`. Un-removes any owner that was previously permanently removed.                                                             |
| `removed_owners_incremental` | array of `Owner`   | No       | Owners to permanently remove from the entity regardless of source. Applied after `assigned_owners` and `added_owners`. Appended to any existing permanently-removed list. |
| `removed_owners_update`      | `OwnersAssignment` | No       | Owners to permanently remove. Replaces the existing permanently-removed list (overrides `removed_owners_incremental`). Omit (not empty) to skip.                          |

### OwnersAssignment Object

| Field    | Type             | Description                                                                                                                                                                            |
| -------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `owners` | array of `Owner` | The owners for this assignment. An empty array assigns with no owners (clears existing). To skip the operation entirely, omit the parent field instead of passing an empty assignment. |

### Owner Object

| Field         | Type   | Required    | Description                                                                                                                                                                                        |
| ------------- | ------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `entity_id`   | string | Conditional | Veza internal owner ID. Use this **or** `external_id`, not both.                                                                                                                                   |
| `external_id` | string | Conditional | External identifier (e.g., email). Matched against the `idp_unique_id` property. Works for native IdP users and OAA IdP users. **Not supported for OAA HRIS employees** — use `entity_id` instead. |
| `entity_type` | string | Yes\*       | Owner entity type (e.g., `OktaUser`). \*Optional if a global IdP is configured.                                                                                                                    |

***

## Update Strategies

The four owner operation fields interact in a defined precedence order. All operations in a batch are applied together to each entity:

| Strategy                 | Field                        | Precedence | Effect                                                                                                                            |
| ------------------------ | ---------------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **Assign**               | `assigned_owners`            | 1st        | Replaces all manually-assigned owners. Does not un-remove permanently-removed owners.                                             |
| **Add**                  | `added_owners`               | 2nd        | Appends owners. If an owner was permanently removed, this un-removes them.                                                        |
| **Remove (incremental)** | `removed_owners_incremental` | 3rd        | Permanently removes owners regardless of source. Appended to any existing permanently-removed list.                               |
| **Remove (replace)**     | `removed_owners_update`      | 4th        | Permanently removes owners. Replaces the entire permanently-removed list. Overrides `removed_owners_incremental` if both are set. |

> **Note on permanently removed owners:** When an owner is added to the permanently-removed list (via `removed_owners_incremental` or `removed_owners_update`), they will not reappear even if an enrichment rule or `assigned_owners` would otherwise include them — unless `added_owners` explicitly un-removes them.

***

## Common Use Cases

### 1. Assign owners to many entities at once

Use `assigned_owners` to set a definitive owner list across many entities. Existing manually-assigned owners are replaced; enrichment-sourced owners are unaffected.

```json
{
  "batches": [
    {
      "entity_type": "AwsS3Bucket",
      "entity_ids": ["bucket-1", "bucket-2", "bucket-3"],
      "assigned_owners": {
        "owners": [{"entity_id": "okta-user-xyz", "entity_type": "OktaUser"}]
      }
    }
  ]
}
```

### 2. Add owners without clearing existing

Use `added_owners` to append owners without disturbing what's already there.

```json
{
  "batches": [
    {
      "entity_type": "VirtualMachine",
      "entity_ids": ["vm-abc"],
      "added_owners": [
        {"external_id": "ops-team@example.com", "entity_type": "OktaUser"}
      ]
    }
  ]
}
```

### 3. Permanently block an enriched owner from returning

Use `removed_owners_incremental` to prevent a specific owner from being re-added by enrichment rules on the next sync.

```json
{
  "batches": [
    {
      "entity_type": "AwsIamRole",
      "entity_ids": ["role-xyz"],
      "removed_owners_incremental": [
        {"entity_id": "okta-user-former", "entity_type": "OktaUser"}
      ]
    }
  ]
}
```

### 4. Mixed batch across entity types

Target different entity types in separate batches within a single request.

```json
{
  "batches": [
    {
      "entity_type": "AwsIamUser",
      "entity_ids": ["iam-user-1", "iam-user-2"],
      "assigned_owners": {
        "owners": [{"entity_id": "okta-user-xyz", "entity_type": "OktaUser"}]
      }
    },
    {
      "entity_type": "GithubRepo",
      "entity_ids": ["repo-abc"],
      "added_owners": [
        {"external_id": "dev-lead@example.com", "entity_type": "OktaUser"}
      ]
    }
  ]
}
```

***

## Limits

| Constraint                        | Limit |
| --------------------------------- | ----- |
| Total entities across all batches | 1,000 |
| Unique owners across all batches  | 1,000 |

***

## Common Errors

**400: Unknown or unprovisioned `entity_type`**

The owner's `entity_type` is not a known node type in the graph — the integration may not be provisioned, or the type string is incorrect.

```json
{
  "code": "InvalidArgument",
  "message": "Invalid Arguments",
  "details": [{"field_violations": [{"field": "types", "description": "Must supply at least one valid type"}]}]
}
```

Fix: Verify the integration for that owner type is provisioned in Veza. Check the exact `entity_type` string via Graph Search or `GET /api/v1/providers/custom`.

**400: Owner type not allowed as an owner**

The `entity_type` provided is a resource type (e.g., `AwsS3Bucket`), not a user or identity type.

```json
{
  "code": "InvalidArgument",
  "details": [{"field_violations": [{"field": "entity_type", "description": "issue with entity {external_id}: owner not of an allowed type"}]}]
}
```

Fix: Use an identity provider user type. See [Owner Type Reference](#owner-type-reference).

**400: Owner not found**

The `external_id` value doesn't match any entity in Veza. Verify the owner exists in your IdP integration and that you're using an IdP-backed user type (not an OAA HRIS employee).

***

## Owner Type Reference

**Native identity providers:**

| Identity Provider       | `entity_type`         |
| ----------------------- | --------------------- |
| Okta                    | `OktaUser`            |
| Azure AD                | `AzureADUser`         |
| Active Directory        | `ActiveDirectoryUser` |
| Ping Identity           | `PingOneUser`         |
| OneLogin                | `OneLoginUser`        |
| AWS IAM Identity Center | `AwsSsoUser`          |
| Google Workspace        | `GoogleWorkspaceUser` |

**OAA custom providers:**

| OAA Template                     | `entity_type`                  |
| -------------------------------- | ------------------------------ |
| Custom IdP (`identity_provider`) | `OAA.{idp_type}.IDPUser`       |
| HRIS (`hris`)                    | `OAA.{hris_type}.HRISEmployee` |

The `{idp_type}` and `{hris_type}` values come from the `idp_type` or `hris_type` field in your OAA payload.

> **OAA HRIS employees:** `external_id` is not supported for HRIS employee types. Use `entity_id` instead.

**Finding your custom type:**

* **UI:** Access Visibility → Graph → search for a user → View Details → copy the `entity_type`
* **API:** `GET /api/v1/providers/custom`

***

## Verification

After the API returns, verify ownership changes via:

1. **Graph Search:** Access Visibility → Graph → find entity → Entity Owners section
2. **Query Builder (VQL):**

   ```
   SHOW AwsIamUser
   WHERE entity_id = "your-entity-id"
   ```
3. **NHI Dashboard:** NHI Security → Accounts → Entity Owner column


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.veza.com/4yItIzMvkpAvMVFAamTf/developers/api/management/owners/batchsetowners.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
