> For the complete documentation index, see [llms.txt](https://docs.sudoplatform.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sudoplatform.com/guides/digital-account-protection/actions.md).

# Actions

An action represents a privacy request the user can take against a data holder relationship. Available actions are generated when a data holder is scanned and analyzed.

Once a data holder has been scanned and analyzed, the system will derive a set of privacy requests, or actions, that the user can undertake to improve their privacy, or digital account protection. Common examples are \
&#x20;\- unsubscribing from marketing communications\
&#x20;\- requesting a copy of their data\
&#x20;\- asking for their data to be deleted. \
An **available action** is a derived suggestion of something the user *could* do against a data holder; an **action** is the instance that is created once the user chooses to proceed.

### Listing Available Actions <a href="#listing-available-actions" id="listing-available-actions"></a>

Before initiating anything, use the `listAvailableActions` method to discover what actions are currently possible for a given data holder relationship. Available actions are derived from multiple sources; some are always possible for the virtual presence type, while others are surfaced from analysis of the organization or from what was found during a discovery scan.

A call to `listAvailableActions` returns a `ListOutput` object containing a list of matching `items` and a `nextToken` to support pagination. If no results are found, the result will contain empty items. Always check the value of the returned `nextToken`—there are no more results to retrieve when `nextToken` is undefined.

{% tabs %}
{% tab title="Typescript" %}

```typescript
try {
  let nextToken: string | undefined = undefined
  do {
    const listOutput = await privacyInteractionClient.listAvailableActions({
      dataHolderId,
    })
    for (const action of listOutput.items) {
      // Handle each available action
    }
    nextToken = listOutput.nextToken
  } while (nextToken !== undefined)
} catch (error) {
  // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
do {
    var nextToken: String?
    repeat {
        let listOutput = try await privacyInteractionClient.listAvailableActions(forDataHolderId: dataHolderId)
        for action in listOutput.items {
            // Handle each available action.
        }
        nextToken = listOutput.nextToken
    } while nextToken != nil
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kt
launch {
    try {
        var nextToken: String? = null
        do {
            val listOutput = withContext(Dispatchers.IO) {
                privacyInteractionClient.listAvailableActions(
                    ListAvailableActionsInput(
                        dataHolderId = dataHolderId,
                        nextToken = nextToken,
                    ),
                )
            }
            for (action in listOutput.items) {
                // Handle each available action
            }
            nextToken = listOutput.nextToken
        } while (nextToken != null)
    } catch (e: ActionException) {
        // Handle/notify user of errors
    }
}
```

{% endtab %}
{% endtabs %}

**Input Parameters:**

| Parameter      | Type     | Required | Description                                                 |
| -------------- | -------- | -------- | ----------------------------------------------------------- |
| `dataHolderId` | `string` | Yes      | The data holder relationship to list available actions for. |

Each `AvailableAction` describes what the action does and how it would be fulfilled. Use the `intent`, `title`, and `description` to present the action to the user, and note the `fulfilmentMethod` ; you must pass the same method back when initiating the action.

**Available Action Fields:**

| Field              | Type                     | Description                                                                   |
| ------------------ | ------------------------ | ----------------------------------------------------------------------------- |
| `intent`           | `ActionIntent`           | The user-facing intent of the action (e.g. `STOP_CONTACT`, `DELETE_MY_DATA`). |
| `additionalInfo`   | `string`                 | Additional info, populated when `intent` is `OTHER`.                          |
| `fulfilmentMethod` | `ActionFulfilmentMethod` | How the action would be fulfilled — `ASSISTED` or `DELEGATED`.                |
| `origin`           | `ActionOrigin`           | Which source contributed this action — `STATIC`, `ANALYSIS`, or `DISCOVERY`.  |
| `title`            | `string`                 | Short presentation hint for the action's title.                               |
| `description`      | `string`                 | Short presentation hint describing the action.                                |

#### Action Intents <a href="#action-intents" id="action-intents"></a>

Every action carries an `intent` describing what the user wants to achieve.

| Intent           | Description                                              |
| ---------------- | -------------------------------------------------------- |
| `STOP_CONTACT`   | Unsubscribe from or opt out of marketing communications. |
| `ACCESS_MY_DATA` | Data subject access or portability request.              |
| `DELETE_MY_DATA` | Account deletion or data erasure.                        |
| `LIMIT_DATA_USE` | Opt out of sale or tracking, and manage consent.         |
| `OTHER`          | Anything unmapped; carries `additionalInfo`.             |

New intents may be introduced over time. Your application should tolerate unknown values — an unrecognized intent is represented as `OTHER` rather than failing, so newly added intents do not break existing clients.

#### Fulfilment Methods <a href="#fulfilment-methods" id="fulfilment-methods"></a>

An action is fulfilled in one of two ways, described by its `fulfilmentMethod`:

* **Assisted** — The service returns structured materials (contact points, an unsubscribe URL, or a prepared email template) for your application to complete the action. The service supplies the organization's contact details and any source-provided instructions, but never the user's own data. Any placeholders in a returned email template (e.g. `{{fullName}}`) are for fields your application supplies client-side.
* **Delegated** — The service performs the action on the user's behalf. No further materials are returned to the client.

The `fulfilmentMethod` you pass when initiating an action must match the method offered on the corresponding `AvailableAction`. Initiation fails if the server re-resolves a different method.

### Initiating an Action <a href="#initiating-an-action" id="initiating-an-action"></a>

To start an action, call `initiateAction` with the data holder relationship, the `intent` the user chose, and the `fulfilmentMethod` that was offered for that intent on the corresponding available action.

For a **delegated** action, the service begins performing the action on the user's behalf. For an **assisted** action, the returned `Action` carries an `assistedPayload` containing the materials your application needs to complete the action.

{% tabs %}
{% tab title="Typescript" %}

```typescript
const input = {
  dataHolderId,
  intent: ActionIntent.StopContact,
  fulfilmentMethod: ActionFulfilmentMethod.Assisted,
}
try {
  const action = await privacyInteractionClient.initiateAction(input)
  // The action is now initiated.
  // `action.status` will typically be `PENDING` or `IN_PROGRESS`.
  // For an assisted action, inspect `action.assistedPayload` for the materials
  // needed to complete it.
} catch (error) {
  // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
let input = InitiateActionInput(
    dataHolderId: dataHolderId,
    intent: .stopContact,
    fulfilmentMethod: .assisted
)
do {
    let action = try await privacyInteractionClient.initiateAction(withInput: input)
    // The action is now initiated.
    // `action.status` will typically be `.pending` or `.inProgress`.
    // For an assisted action, inspect `action.assistedPayload` for the materials
    // needed to complete it.
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kt
val input = InitiateActionInput(
    dataHolderId = dataHolderId,
    intent = ActionIntent.STOP_CONTACT,
    fulfilmentMethod = ActionFulfilmentMethod.ASSISTED,
)
try {
    val action = privacyInteractionClient.initiateAction(input)
    // The action is now initiated.
    // `action.status` will typically be `PENDING` or `IN_PROGRESS`.
    // For an assisted action, inspect `action.assistedPayload` for the
    // materials needed to complete it.
} catch (e: ActionException) {
    // Handle/notify user of errors
}
```

{% endtab %}
{% endtabs %}

**Input Parameters:**

| Parameter          | Type                     | Required | Description                                                                                                                  |
| ------------------ | ------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `dataHolderId`     | `string`                 | Yes      | The data holder relationship to scope the action to.                                                                         |
| `intent`           | `ActionIntent`           | Yes      | The intent of the action to initiate.                                                                                        |
| `fulfilmentMethod` | `ActionFulfilmentMethod` | Yes      | The fulfilment method the client was offered for this intent. Initiation fails if the server re-resolves a different method. |

### Confirming an Action Outcome <a href="#confirming-an-action-outcome" id="confirming-an-action-outcome"></a>

When an assisted or delegated action has been completed, call `confirmActionOutcome` with the action's unique identifier to confirm the outcome. This transitions the action from `COMPLETED_UNVERIFIED` to `COMPLETED_VERIFIED`.

{% tabs %}
{% tab title="Typescript" %}

```typescript
try {
  const action = await privacyInteractionClient.confirmActionOutcome(actionId)
  // `action.status` will be `COMPLETED_VERIFIED`.
} catch (error) {
  // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
do {
    let action = try await privacyInteractionClient.confirmActionOutcome(withId: actionId)
    // `action.status` will be `.completedVerified`.
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kt
launch {
    try {
        val action = withContext(Dispatchers.IO) {
            privacyInteractionClient.confirmActionOutcome(actionId)
        }
        // `action.status` will be COMPLETED_VERIFIED.
    } catch (e: ActionException) {
        // Handle/notify user of errors
    }
}
```

{% endtab %}
{% endtabs %}

#### Action States <a href="#action-states" id="action-states"></a>

An action transitions through the following states:

| State                  | Description                                              |
| ---------------------- | -------------------------------------------------------- |
| `PENDING`              | The action has been created but not yet started.         |
| `IN_PROGRESS`          | The action is being performed.                           |
| `COMPLETED_UNVERIFIED` | The action completed but has not been verified.          |
| `COMPLETED_VERIFIED`   | The action completed and has been verified.              |
| `FAILED`               | The action failed to complete.                           |
| `REQUIRES_USER_INPUT`  | The action requires further input from the user.         |
| `CONTRADICTED`         | Subsequent evidence contradicts the action's completion. |

When an action enters the `COMPLETED_UNVERIFIED` state, your application can call `confirmActionOutcome` to transition it to `COMPLETED_VERIFIED`. When an action enters the `REQUIRES_USER_INPUT` state, your application should gather the required input from the user before the action can proceed.

#### Action Fields <a href="#action-fields" id="action-fields"></a>

A persisted `Action` returned by `initiateAction` and `confirmActionOutcome` contains the following fields:

| Field               | Type                     | Description                                                         |
| ------------------- | ------------------------ | ------------------------------------------------------------------- |
| `id`                | `string`                 | Unique identifier associated with the action.                       |
| `virtualPresenceId` | `string`                 | The virtual presence this action belongs to.                        |
| `dataHolderId`      | `string`                 | The data holder relationship this action is scoped to.              |
| `intent`            | `ActionIntent`           | The user-facing intent of the action.                               |
| `additionalInfo`    | `string`                 | Additional info, populated when `intent` is `OTHER`.                |
| `fulfilmentMethod`  | `ActionFulfilmentMethod` | How the action is fulfilled.                                        |
| `status`            | `ActionStatus`           | Current lifecycle status of the action.                             |
| `assistedPayload`   | `AssistedPayload`        | Materials for an assisted action. Undefined for a delegated action. |
| `initiatedAt`       | `Date`                   | When the action was initiated.                                      |
| `completedAt`       | `Date`                   | When the action completed.                                          |

#### Subscribing to Action Updates <a href="#subscribing-to-action-updates" id="subscribing-to-action-updates"></a>

To receive real-time notifications when an action changes status, see [Subscriptions](https://docs.sudoplatform.com/~/revisions/U8P5YQbTWlABRqHUlUfP/guides/privacy-interaction/subscriptions).
