# Digital delivery (/ai/reference/digital/digital-fulfillment)

Toolset `digital_fulfillment`, 17 tools.

## Records [#records]

### `delivery_channels` [#delivery_channels]

Where a product's keys and files are delivered, by product id: default follows the store, account delivers in the shopper's account only, email also emails them.

- Permission: `products.read`
- Tools: `delivery_channels_get`
- Needs digital products enabled

### `digital_delivery` [#digital_delivery]

How an order's digital items were delivered, by order id: without_waiver lists what stays in the shopper's account because no withdrawal waiver was given. Include activities for the key delivery history with warnings about missing keys, and files for the file entitlements.

- Permission: `orders.read`
- Tools: `digital_delivery_get`
- Includes: `activities`, `files`
- Needs digital products enabled

### `digital_file` [#digital_file]

A private file the store delivers after purchase. With product_id (and variant_id) the list shows the files offered on that product, with the plan's file limits; otherwise it is the store's whole file library, searched by q or one file by id, each with the products it is offered on. Files are added in the admin, not here.

- Permission: `products.read`
- Tools: `digital_file_list`
- Needs digital products enabled

Filters on the list:

| Filter | Type | Required | Description |
| --- | --- | --- | --- |
| `q` | string |  | Search file name or title in the library |
| `id` | string |  | One library file |
| `product_id` | string |  | Only files offered on this product |
| `variant_id` | string |  |  |

### `file_delivery` [#file_delivery]

How a product delivers its files, by product id: the setup (selling status, download limit, expiry days, active flag), how many files are offered, and the per-variant setups in configs. Include readiness to see whether it can sell and what is missing.

- Permission: `products.read`
- Tools: `file_delivery_get`
- Includes: `readiness`
- Needs digital products enabled

### `key_request` [#key_request]

A shopper request for the keys of an order item waiting in the delivery queue, pending ones first. Filter by status, order_id or product_id.

- Permission: `products.read`
- Tools: `key_request_list`
- Needs digital products enabled

Filters on the list:

| Filter | Type | Required | Description |
| --- | --- | --- | --- |
| `q` | string |  | Match order, item, product or customer ID |
| `status` | string |  | Request status, e.g. pending |
| `order_id` | string |  |  |
| `product_id` | string |  |  |

## Actions [#actions]

### `delivery_channels_set` [#delivery_channels_set]

Choose where a product delivers its keys and files.

Applies to every key pool and file setup of the product; default goes back to following the store. Refused when the product has no digital delivery set up.

- Action key: `delivery_channels.set`
- Permission: `products.write`
- Approval: Waits for approval when the store requires it for this action.
- Effect: Changes the live store.
- Retries: safe to repeat with the same input.
- Needs digital products enabled

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `product_id` | string | yes | Product ID. at least 1 characters |
| `channels` | string | yes | one of "default", "account", "email" |

Example input:

```json
{
  "product_id": "019bb58e-0ec1-79c1-9f40-d39d8d07674b",
  "channels": "email"
}
```

### `digital_delivery_deliver_keys` [#digital_delivery_deliver_keys]

Run key delivery again for the digital items of an order that are missing keys.

The same guarded delivery the storefront runs after payment: items that already have keys keep them, the rest get keys from stock. Reports how many were delivered now. Check digital_delivery_get with include activities first.

- Action key: `digital_delivery.deliver_keys`
- Permission: `orders.write`
- Approval: Waits for approval when the store requires it for this action.
- Effect: Changes the live store.
- Retries: safe to repeat with the same input.
- Sends something to customers.
- Needs digital products enabled

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `order_id` | string | yes | Order ID |

Example input:

```json
{
  "order_id": "019bb3ef-6501-7dc3-a2e7-726e91520b7a"
}
```

### `digital_file_attach` [#digital_file_attach]

Offer a library file to the buyers of a product, or of one variant.

- Action key: `digital_file.attach`
- Permission: `products.write`
- Approval: Waits for approval when the store requires it for this action.
- Effect: Changes the live store.
- Retries: safe to repeat with the same input.
- Needs digital products enabled

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Digital file ID. at least 1 characters |
| `product_id` | string | yes | Product ID. at least 1 characters |
| `variant_id` | string |  | Variant ID; leave out for the whole product. at least 1 characters |

Example input:

```json
{
  "id": "019bb26c-168e-72ea-85af-ba3ca1f36f3c",
  "product_id": "019bb58e-0ec1-79c1-9f40-d39d8d07674b"
}
```

### `digital_file_delete` [#digital_file_delete]

Delete a file from the digital library.

It stops being offered on every product. To only stop offering it, archive it.

- Action key: `digital_file.delete`
- Permission: `products.write`
- Approval: Always waits for a person to approve it.
- Effect: Changes the live store.
- Destructive: in compact mode it runs with `run_destructive_action`.
- Retries: runs at most once; a repeat with the same idempotency key returns the first result.
- Needs digital products enabled

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Digital file ID. at least 1 characters |

Example input:

```json
{
  "id": "019bb26c-168e-72ea-85af-ba3ca1f36f3c"
}
```

### `digital_file_detach` [#digital_file_detach]

Stop offering a library file on a product or variant; the file stays in the library.

- Action key: `digital_file.detach`
- Permission: `products.write`
- Approval: Always waits for a person to approve it.
- Effect: Changes the live store.
- Destructive: in compact mode it runs with `run_destructive_action`.
- Retries: safe to repeat with the same input.
- Needs digital products enabled

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Digital file ID. at least 1 characters |
| `product_id` | string | yes | Product ID. at least 1 characters |
| `variant_id` | string |  | Variant ID; leave out for the whole product. at least 1 characters |

Example input:

```json
{
  "id": "019bb26c-168e-72ea-85af-ba3ca1f36f3c",
  "product_id": "019bb58e-0ec1-79c1-9f40-d39d8d07674b"
}
```

### `digital_file_update` [#digital_file_update]

Change a library file's name, title, version, language or archived state.

status archived stops offering the file; active brings it back. language is a language code or multi; null clears title, version or language.

- Action key: `digital_file.update`
- Permission: `products.write`
- Approval: Waits for approval when the store requires it for this action.
- Effect: Changes the live store.
- Retries: safe to repeat with the same input.
- Needs digital products enabled

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Digital file ID. at least 1 characters |
| `filename` | string |  | at least 1 characters |
| `status` | string |  | one of "active", "archived" |
| `title` | string or null |  | 1 to 200 characters |
| `version` | string or null |  | at most 64 characters |
| `language` | string or null |  | Language code, or multi |

Example input:

```json
{
  "id": "019bb26c-168e-72ea-85af-ba3ca1f36f3c",
  "title": "Installer",
  "version": "1.2"
}
```

### `digital_key_assign` [#digital_key_assign]

Force-assign an available digital key to an order item and mark it delivered.

Nothing is sent to the shopper. A key already delivered to an order is refused; revoke or replace it instead.

- Action key: `digital_key.assign`
- Permission: `products.write`
- Approval: Waits for approval when the store requires it for this action.
- Effect: Changes the live store.
- Retries: runs at most once; a repeat with the same idempotency key returns the first result.
- Needs digital products enabled

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Digital key ID |
| `order_id` | string | yes | Order ID |
| `order_item_id` | string | yes | Order item ID |

Example input:

```json
{
  "id": "019bb26e-fbea-77b2-a205-feb8fd82b66b",
  "order_id": "019bb3ef-6501-7dc3-a2e7-726e91520b7a",
  "order_item_id": "019bb496-a0e1-70c9-a373-1b205a23af28"
}
```

### `digital_key_replace` [#digital_key_replace]

Revoke a delivered key and deliver the next available key of the product in its place.

The shopper gets an email with the new key. replacement_key_id picks a specific available key of the same product; the oldest one is used by default.

- Action key: `digital_key.replace`
- Permission: `products.write`
- Approval: Always waits for a person to approve it.
- Effect: Changes the live store.
- Destructive: in compact mode it runs with `run_destructive_action`.
- Retries: runs at most once; a repeat with the same idempotency key returns the first result.
- Sends something to customers.
- Needs digital products enabled

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Current digital key ID |
| `reason` | string | yes | Why the key is taken back. one of "not_working", "already_used", "wrong_region", "wrong_platform", "customer_request", "other" |
| `note` | string |  | Note for the record; required when the reason is other. at most 1000 characters |
| `replacement_key_id` | string |  | A specific available key of the product |

Example input:

```json
{
  "id": "019bb26e-fbea-77b2-a205-feb8fd82b66b",
  "reason": "wrong_region",
  "note": "Shopper is in the UK"
}
```

### `digital_key_revoke` [#digital_key_revoke]

Take a delivered key back with a reason.

The key stays on the order as the record and never returns to the pool. To give the shopper a working key instead, use digital_key_replace.

- Action key: `digital_key.revoke`
- Permission: `products.write`
- Approval: Always waits for a person to approve it.
- Effect: Changes the live store.
- Destructive: in compact mode it runs with `run_destructive_action`.
- Retries: runs at most once; a repeat with the same idempotency key returns the first result.
- Needs digital products enabled

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Digital key ID |
| `reason` | string | yes | Why the key is taken back. one of "not_working", "already_used", "wrong_region", "wrong_platform", "customer_request", "other" |
| `note` | string |  | Note for the record; required when the reason is other. at most 1000 characters |

Example input:

```json
{
  "id": "019bb26e-fbea-77b2-a205-feb8fd82b66b",
  "reason": "not_working"
}
```

### `digital_key_value_set` [#digital_key_value_set]

Overwrite the stored value of a licence key; the old value is gone.

A buyer who already received the key keeps the old value, which stops working once the supplier cancels it. To give a buyer a different key use digital_key_replace.

- Action key: `digital_key.value_set`
- Permission: `products.write`
- Approval: Always waits for a person to approve it.
- Effect: Changes the live store.
- Destructive: in compact mode it runs with `run_destructive_action`.
- Retries: safe to repeat with the same input.
- Needs digital products enabled

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Digital key ID |
| `key_value` | string | yes | at least 1 characters |

Example input:

```json
{
  "id": "019bb26e-fbea-77b2-a205-feb8fd82b66b",
  "key_value": "AAAA-BBBB-CCCC"
}
```

### `file_delivery_update` [#file_delivery_update]

Change a product's or variant's file delivery setup; only the fields passed change.

selling_status ready sells the files, paused stops, needs_setup marks it unfinished. max_downloads and expiry_days take null for no limit. Check file_delivery_get with include readiness before setting ready.

- Action key: `file_delivery.update`
- Permission: `products.write`
- Approval: Waits for approval when the store requires it for this action.
- Effect: Changes the live store.
- Retries: safe to repeat with the same input.
- Needs digital products enabled

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `product_id` | string | yes | Product ID. at least 1 characters |
| `variant_id` | string or null |  | at least 1 characters |
| `selling_status` | string |  | one of "ready", "paused", "needs_setup" |
| `max_downloads` | integer or null |  | above 0 |
| `expiry_days` | integer or null |  | above 0 |
| `is_active` | boolean |  |  |

Example input:

```json
{
  "product_id": "019bb58e-0ec1-79c1-9f40-d39d8d07674b",
  "selling_status": "ready",
  "max_downloads": 5
}
```

### `key_request_expire` [#key_request_expire]

Mark a queued key request as expired and clear its stuck-delivery alert.

The shopper is not served from this request any more; the order keeps its items.

- Action key: `key_request.expire`
- Permission: `products.write`
- Approval: Always waits for a person to approve it.
- Effect: Changes the live store.
- Destructive: in compact mode it runs with `run_destructive_action`.
- Retries: safe to repeat with the same input.
- Needs digital products enabled

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Key request ID |

Example input:

```json
{
  "id": "019bb271-e7b3-7dfc-bb22-52068b94243c"
}
```
