# Actors And Access Control

> API Kickstart for users, service accounts, roles, and role assignments.

Source: https://business-api-docs.youhodler.com/docs/reference/actors-and-access-control

This group covers the actor model and the authorization model. Read it in
scope-building order: create principals first, define reusable permission
bundles second, bind those bundles into tenant scope third, and then add
execution-control surfaces like policies or approval queues.

> **Why this group exists:** `users` and `service-accounts` create principals. `roles`, `role-assignments`, and `capabilities` define access scope. `policies`, `approvals`, and `action-tokens` shape what governed execution may do after access already exists.

## Principals, Scope, And Control

### Create user

Human operator principal. Create a user when a person needs to review, approve, or operate inside enterprise scope through a canonical human actor resource.

[API Reference: Create user (POST)](/docs/api/reference/users/users-create)

**Request URL — POST**
```http
POST https://business-api.youhodler.com/users
```
**Request Body — application/json**
```json
{
  "display_name": "Jane Doe",
  "email": "jane.doe@acme.example",
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```
**201 Created**

```json
{
  "created_at": "2026-05-01T10:00:00Z",
  "display_name": "Jane Doe",
  "email": "jane.doe@acme.example",
  "etag": "W/\"a1b2c3d4\"",
  "federation": null,
  "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "identity_source": "platform-managed",
  "resource": "human_actor",
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "status": "active",
  "updated_at": "2026-05-01T10:00:00Z"
}
```

**400 Bad Request**

```json
{
  "code": "invalid_request",
  "details": {
    "reason": "capability_scope_mismatch"
  },
  "message": "A required field is missing or invalid"
}
```

### Create service account

Backend principal. Create a service account when execution should happen from server-side infrastructure instead of a human session.

[API Reference: Create service account (POST)](/docs/api/reference/service-accounts/service-accounts-create)

**Request URL — POST**
```http
POST https://business-api.youhodler.com/service-accounts
```
**Request Body — application/json**
```json
{
  "description": "Withdrawal automation account",
  "parent_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "roles": [
    {
      "role_ref": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
    }
  ]
}
```
**201 Created**

```json
{
  "client_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "client_secret": "cs_live_abc123placeholder",
  "client_secret_expires_at": "2026-05-01T10:00:00Z",
  "principal_ref": "service-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "role_assignment_errors": [],
  "role_assignments": [],
  "service_account": {
    "description": "Withdrawal automation account",
    "created_at": "2026-05-01T10:00:00Z",
    "current_secret_expires_at": "2026-05-01T10:00:00Z",
    "etag": "W/\"sa-etag-0001\"",
    "external_id": "sa-ext-001",
    "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "parent_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "previous_secret_expires_at": null,
    "principal_ref": "service-accounts/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
    "resource": "service_account",
    "status": "active",
    "updated_at": "2026-05-01T10:00:00Z"
  }
}
```

**400 Bad Request**

```json
{
  "code": "invalid_request",
  "details": {
    "reason": "capability_scope_mismatch"
  },
  "message": "Request validation failed"
}
```

### Create role

Reusable access bundle. Create a role before granting scope so principals can inherit a named capability set instead of accumulating one-off permission logic.

[API Reference: Create role (POST)](/docs/api/reference/roles/roles-create)

**Request URL — POST**
```http
POST https://business-api.youhodler.com/roles
```
**Request Body — application/json**
```json
{
  "name": "Enterprise Admin",
  "description": "Full administrative access within an enterprise",
  "permissions": [
    "withdrawals.create",
    "deposits.read",
    "clients.read"
  ],
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```
**201 Created**

```json
{
  "name": "Enterprise Admin",
  "description": "Full administrative access within an enterprise",
  "created_at": "2026-05-01T10:00:00Z",
  "etag": "W/\"a1b2c3d4\"",
  "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "permissions": [
    "withdrawals.create",
    "deposits.read",
    "clients.read"
  ],
  "platform_managed": false,
  "resource": "role",
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "status": "active",
  "updated_at": "2026-05-01T10:00:00Z"
}
```

**400 Bad Request**

```json
{
  "code": "invalid_request",
  "details": {
    "reason": "missing_required_field"
  },
  "message": "The request is invalid."
}
```

### Grant role assignment

Principal-to-scope binding. Grant a role assignment when a user or service account needs that role inside a specific enterprise or client boundary.

[API Reference: Grant role assignment (POST)](/docs/api/reference/role-assignments/role-assignments-create)

**Request URL — POST**
```http
POST https://business-api.youhodler.com/role-assignments
```
**Request Body — application/json**
```json
{
  "principal_ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "role_ref": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "scope_anchor_kind": "explicit",
  "scope_propagation": "subtree",
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
}
```
**201 Created**

```json
{
  "created_at": "2026-05-01T10:00:00Z",
  "etag": "W/\"a1b2c3d4\"",
  "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "principal_ref": "users/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "resource": "role_assignment",
  "role_ref": "roles/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "scope_anchor_kind": "explicit",
  "scope_propagation": "subtree",
  "scope_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
  "status": "active",
  "updated_at": "2026-05-01T10:00:00Z"
}
```

**400 Bad Request**

```json
{
  "code": "invalid_request",
  "details": {
    "reason": "missing_required_field"
  },
  "message": "The request is invalid."
}
```

### List capabilities

Product feature flags. Read capabilities to inspect which product-level features (e.g. `conversion`, `deposit`, `withdrawal`) are enabled or disabled for a given tenant scope. Note: this endpoint returns feature toggles, not the API permission names used in `POST /roles` (e.g. `clients.read`, `internal_transfers.create`).

[API Reference: List capabilities (GET)](/docs/api/reference/capabilities/capabilities-list)

**Request URL — GET**
```http
GET https://business-api.youhodler.com/capabilities?scope_ref=enterprises/11111111-1111-4111-8111-111111111111&page_size=50
```
**200 OK**

```json
{
  "items": [
    {
      "name": "withdrawals.create",
      "enabled": true
    },
    {
      "name": "deposits.read",
      "enabled": true
    },
    {
      "name": "clients.read",
      "enabled": false
    }
  ],
  "next_page_token": null
}
```

**400 Bad Request**

```json
{
  "code": "invalid_request",
  "message": "The request is invalid."
}
```

### Create policy

Execution control surface. Create a policy once access is already in place and you need canonical governance around later mutating operations.

[API Reference: Create policy (POST)](/docs/api/reference/policies/policies-create)

**Request URL — POST**
```http
POST https://business-api.youhodler.com/policies
```

**201 Created**

**400 Bad Request**

### List approvals

Governed work queue. List approvals when execution has already created decision cases and operators need to inspect pending review work.

[API Reference: List approvals (GET)](/docs/api/reference/approvals/approvals-list)

**Request URL — GET**
```http
GET https://business-api.youhodler.com/approvals?scope_ref=enterprises/11111111-1111-4111-8111-111111111111&status=pending
```
**200 OK**

```json
{
  "items": [
    {
      "action_family": "withdrawal",
      "created_at": "2026-05-01T10:00:00Z",
      "decision": null,
      "expires_at": "2026-05-01T10:00:00Z",
      "governed_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "initiated_by": {
        "actor": null,
        "approved_by": null,
        "authenticated_principal": {
          "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
          "kind": "user",
          "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
        },
        "enterprise_binding": {
          "tenant_type": "enterprise",
          "topology_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
        },
        "federation": null,
        "identity_source": "platform-managed",
        "initiated_by": null,
        "subject": {
          "id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
          "kind": "user",
          "tenant_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b"
        }
      },
      "operation_id": "b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
      "requirement_snapshot": {
        "authority_ref": "enterprises/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "expires_at": "2026-05-01T10:00:00Z",
        "governed_ref": "clients/b8e2f1a0-4c3d-4e5f-9a1b-2c3d4e5f6a7b",
        "initiator_cannot_approve": true,
        "reason_code": "high_value",
        "required_human_approvals": 1,
        "requirement_key": "withdrawal_approval",
        "source": "policy"
      },
      "resource": "approval",
      "status": "pending",
      "updated_at": "2026-05-01T10:00:00Z"
    }
  ],
  "next_page_token": null
}
```

**400 Bad Request**

```json
{
  "code": "invalid_request",
  "message": "Invalid request payload."
}
```
