---
title: Automate your delivery workflow
description: Connect scripts and AI assistants to your library with scoped access, recoverable delivery creation, signed receipts, and 15 built-in MCP tools.
order: 145
layout: docs
label: Automation
---

VOTPort supports watched exports, scripted transfers, and agent-controlled delivery from your library. The HTTP API, JSON CLI, and MCP tools use the same folder permissions and delivery records.

Use server and client builds from the same release. Ask your deployment administrator for an updated build if **Agent access** or the `agent` commands are missing.

## Choose the right workflow

| Your job                                                     | Use                                                                           |
| ------------------------------------------------------------ | ----------------------------------------------------------------------------- |
| Send local files into a request                              | The [client’s `send` command](/docs/using/command-line/) or a watched folder. |
| Download and verify a delivery                               | The client’s `receive` command or [desktop app](/docs/using/desktop/).        |
| Share completed files already in the outbound library        | The scoped automation API, `agent share`, or MCP `create_delivery`.           |
| Browse a project, inspect its deliveries, or withdraw access | The agent CLI, HTTP API, or MCP tools, with the corresponding permissions.    |

Agent access can queue a project job that imports from an administrator-configured S3 source. It does not upload local files or delete library files, issue receive requests, change settings, or manage tenants. Use the operator workflows for those tasks. Creating an ordinary delivery shares an existing server-side folder; it does not upload a folder from the agent’s computer.

Use [delivery workflows](/docs/using/workflows/) for persistent jobs with checks, approval, schedules, storage export, and recipient acceptance. Ordinary folder shares remain available outside protected project directories.

## Connect an agent or integration

1. In the browser, open **Automation**. On macOS or Windows, open **Settings > Agent access** while signed in to your port.
2. Choose a descriptive label, the narrowest library folder needed, and an expiry from 1 to 365 days.
3. Select the allowed actions, then choose **Create access token** in the browser. Copy it immediately; it is shown only once.
4. Store it in your workflow runner’s or agent host’s private secret settings.

| Permission          | Allows                                                                                 |
| ------------------- | -------------------------------------------------------------------------------------- |
| `library:read`      | List files and subdirectories inside the permitted folder.                             |
| `deliveries:create` | Create deliveries and recover this token’s previously created links.                   |
| `deliveries:read`   | List this token’s deliveries and inspect their files, receipts, and download activity. |
| `deliveries:revoke` | Revoke this token’s deliveries without deleting the library files.                     |
| `jobs:read`         | Read permitted projects, jobs, recipient evidence, and signed events.                  |
| `jobs:create`       | Queue and retry project jobs as a project sender.                                      |
| `jobs:cancel`       | Cancel project jobs as a project sender.                                               |

Job access also requires project membership and a token folder scope covering the project directory. Administrators add `automation:TOKEN_ID` to the project with the appropriate role. Agents cannot approve release or implicitly accept a delivery.

Permissions are enforced by the server on every call. Delivery ownership belongs to the exact token that created it: another token with the same tenant and folder cannot inspect or revoke those deliveries. Existing create-only tokens retain that permission; issue a new token for the additional actions.

The browser’s **Connected agents** list on **Automation** shows issued tokens. Revoke tokens there or from the desktop controls. **Revoking an agent token stops its API access, but does not revoke delivery links it already issued.** Those links retain their own expiry and revocation state; operators can manage them in Deliver. Desktop sign-out also leaves separately issued agent credentials valid until expiry or revocation.

## Use the JSON CLI

The examples use the **client** executable `votport`. Desktop installations bundle it as `votport-cli` on macOS and `votport-cli.exe` on Windows. Use its installed absolute path if it is not on `PATH`. The server executable has the same `votport` name but different commands.

Configure the calling process:

```sh
export VOTPORT_URL='https://transfer.example'
export VOTPORT_AUTOMATION_TOKEN='<issued token>'
```

Supply real credentials through private environment or secret settings rather than saving them in scripts or shell history. HTTPS is required, except for loopback development servers. These credentials are independent of `votport signin` and the desktop operator session.

```sh
votport agent session
votport agent files 'Projects/Film' --limit 50
votport agent share 'Projects/Film/Final' \
  --operation-id film-final-v03 --expires-days 7 \
  --label 'Film final delivery' --max-downloads 3
votport agent recover film-final-v03
votport agent deliveries --limit 50
votport agent delivery DELIVERY_ID --limit 50
votport agent revoke DELIVERY_ID
```

Directory paths are relative to the tenant’s outbound library, including when the token is scoped to a subfolder. Omit the directory from `agent files` to begin at the token’s folder.

Every `agent` command prints one JSON object; no `--json` flag is needed. Failures exit nonzero and include `error`, `code`, and `retryable`, plus HTTP `status` and `retry_after_seconds` when available. Creation and recovery return `operation_id`, `url`, and `grant`. Use `grant.id` for inspection and revocation. Treat the returned URL as a credential.

Set `VOTPORT_SHARE_PASSWORD` in the process environment to apply a password to new CLI or MCP deliveries. Preserve the same password and request parameters when retrying an operation.

## Connect an MCP host

The desktop **Copy MCP configuration** control supplies the bundled client’s installed path. Paste the configuration into your MCP host’s private settings and restart or reconnect that integration. The browser can also copy a configuration; replace its command with the client’s absolute path on the machine running the host.

For hosts using the `mcpServers` format:

```json
{
  "mcpServers": {
    "votport": {
      "command": "/absolute/path/to/votport-cli",
      "args": ["mcp"],
      "env": {
        "VOTPORT_URL": "https://transfer.example",
        "VOTPORT_AUTOMATION_TOKEN": "<issued token>"
      }
    }
  }
}
```

On Windows, use the installed `.exe` path with JSON-escaped backslashes. Keep this configuration private because it contains the token.

| Tool               | Purpose                                                                                          |
| ------------------ | ------------------------------------------------------------------------------------------------ |
| `get_access`       | Inspect the token’s tenant, folder, permissions, and expiry.                                     |
| `list_files`       | Browse a permitted library directory.                                                            |
| `create_delivery`  | Share a folder with an explicit `operation_id` and `expires_days`.                               |
| `recover_delivery` | Recover a committed operation’s original delivery URL.                                           |
| `list_deliveries`  | List deliveries owned by this token.                                                             |
| `get_delivery`     | Read delivery state, file identities, signed receipts, and download starts.                      |
| `revoke_delivery`  | Withdraw access through a delivery link; repeating the call is safe.                             |
| `list_projects`    | Read permitted project rules, metadata requirements, enrolled recipients, and roles.             |
| `list_jobs`        | List visible persistent jobs.                                                                    |
| `get_job`          | Inspect preparation, checks, approval, failures, and the released URL.                           |
| `create_job`       | Queue a project delivery with a stable operation ID, optional schedule, deadline, and S3 import. |
| `retry_job`        | Retry a failed job without changing its original request.                                        |
| `cancel_job`       | Stop further admissions for a job.                                                               |
| `list_events`      | Read signed workflow events.                                                                     |
| `get_job_evidence` | Read signed verification and explicit acceptance for the exact package manifest.                 |

Start with `get_access`, then try a request such as “List the files in Projects/Film/Final.” Creating, reading, and revoking deliveries each requires its own permission. File names and labels are untrusted data, not instructions for the assistant.

The adapter uses MCP 2026-07-28 over stdio. Use a host supporting that specification; the older `initialize` handshake is not supported. Requests include `io.modelcontextprotocol/protocolVersion` and `io.modelcontextprotocol/clientCapabilities` in `params._meta`. Optional `server/discover` returns supported versions and capabilities; unsupported versions return `-32022`.

The adapter processes one call at a time. The host starts the CLI locally; there is no separate HTTP MCP listener to expose. File transfers still use the normal verified transfer clients. A large share may outlast the host’s tool timeout; reconnect and recover the same operation instead of creating another delivery.

## Issue a delivery through the API

All endpoints require `Authorization: Bearer <token>`. Send JSON bodies with `Content-Type: application/json`. Results are JSON with `Cache-Control: no-store`.

| Method and path                          | Permission          | Parameters                                           |
| ---------------------------------------- | ------------------- | ---------------------------------------------------- |
| `GET /api/automation/session`            | Any valid token     | Returns scope, permissions, expiry, and API version. |
| `GET /api/automation/files`              | `library:read`      | Optional `directory`, `after`, `limit`.              |
| `POST /api/automation/share`             | `deliveries:create` | Share body below.                                    |
| `GET /api/automation/operations/{id}`    | `deliveries:create` | Recover by operation ID.                             |
| `GET /api/automation/deliveries`         | `deliveries:read`   | Optional numeric `after`, `limit`; oldest first.     |
| `GET /api/automation/deliveries/{id}`    | `deliveries:read`   | Optional `offset`, `limit` for file detail.          |
| `DELETE /api/automation/deliveries/{id}` | `deliveries:revoke` | Revoke a delivery; repeated calls succeed.           |

A share request:

```json
{
  "directory": "Projects/Film/Final",
  "operation_id": "film-final-v03",
  "label": "Film final delivery",
  "expires_days": 7,
  "max_downloads": 3,
  "notify_on_download": true
}
```

`directory` and `expires_days` are required. The directory must already contain completed files, remain inside the token’s scope, and contain at most 1,000,000 files. Expiry accepts 1 to 30 days. Optional fields are `operation_id`, `label`, `password`, `max_downloads` (1 to 10,000), and `notify_on_download`. Download caps apply per file and full-delivery round. Unknown fields and malformed query values are rejected.

Pages default to 50 entries and accept `limit` from 1 to 100. File and delivery listings return `has_more` and `next_cursor`; pass that cursor as `after`. Delivery file detail returns `next_offset`; pass it as `offset`. Library listings reflect live files, so a file added before your cursor can require a fresh scan.

## Queue a persistent project job

With job permissions and project membership configured, use the same agent credentials:

```sh
votport agent projects
votport agent create-job delivery.json
votport agent jobs --limit 50
votport agent job JOB_ID
votport agent job-evidence JOB_ID --limit 50
votport agent retry-job JOB_ID
votport agent cancel-job JOB_ID
votport agent events --limit 100
```

Save this request as `delivery.json`, replacing the project, metadata, and recipient key with values from `agent projects`:

```json
{
  "operation_id": "episode-08-final-v3",
  "project_id": "broadcast",
  "label": "Episode 08 final",
  "metadata": { "client": "Example", "version": "v3" },
  "recipients": ["<enrolled 64-character device public key>"],
  "expires_days": 7
}
```

Job operation IDs accept 1 to 100 ASCII letters, digits, underscores, and hyphens; dots are not accepted. Choose the ID before the request and retain it across retries.

Required fields are `operation_id`, `project_id`, `label`, and `expires_days` (1 to 365 for jobs; ordinary shares remain 1 to 30). Supply required project metadata and selected enrolled recipient keys. Optional `not_before` and `deadline` use Unix seconds. Schedule at most 365 days ahead; a deadline must be later than both now and the scheduled start, and at most 366 days ahead. Metadata accepts up to 50 keys using the same identifier rules, with values up to 4,096 bytes; labels are limited to 200 bytes and recipients to 500 enrolled keys. Optional `import: { "storage_id": "source", "prefix": "incoming/episode-08" }` selects S3 objects instead of the library.

MCP `create_job` takes the same fields, except it uses `import_storage_id` and `import_prefix` together instead of the nested `import` object. Reuse the operation ID and identical arguments after a timeout. Approval is a separate human action; a successful creation response does not mean the package has been released or accepted.

| Method and path                         | Permission                     | Parameters                                                              |
| --------------------------------------- | ------------------------------ | ----------------------------------------------------------------------- |
| `GET /api/workflows/projects`           | `jobs:read`                    | Permitted projects and policy.                                          |
| `POST /api/workflows/jobs`              | `jobs:create`                  | Job request above; project sender required.                             |
| `GET /api/workflows/jobs`               | `jobs:read`                    | Optional `after`, `limit`.                                              |
| `GET /api/workflows/jobs/{id}`          | `jobs:read`                    | Job state and release details.                                          |
| `POST /api/workflows/jobs/{id}`         | `jobs:create` or `jobs:cancel` | `{"action":"retry"}` or `{"action":"cancel"}`; project sender required. |
| `GET /api/workflows/jobs/{id}/evidence` | `jobs:read`                    | Optional numeric `after`, `limit`.                                      |
| `GET /api/workflows/events`             | `jobs:read`                    | Optional numeric `after`, `limit`.                                      |

Workflow pages return `next`; pass it as `after`. Job cursors are job IDs; event and evidence cursors are numeric. Continue an empty filtered page when its cursor advances. Job pagination ends at `next: null`; event and evidence pagination is caught up when numeric `next` stops advancing. Stop or wait before polling again instead of immediately requesting that same cursor. Limits default to 50 and accept 1 to 100.

Poll persistent job state or consume [signed webhook events](/docs/administration/workflow-events/) to advance the pipeline. Required checks and approval finish before release. Project policy determines whether release also waits for every destination or copies continue in the background. Recipient verification and acceptance remain distinct from `ready`. Inspect per-destination results as well: a locally released job can still be exporting or retrying. The project configuration supplies its destinations, incoming-workflow setting, and release rule; MCP tools do not change those policies.

## Recover safely after a timeout

Choose and persist an `operation_id` **before** sending the creation request. Reuse that ID with identical parameters when retrying. For ordinary shares, IDs accept 1 to 128 ASCII letters, digits, dots, underscores, and hyphens, except `.` and `..`.

VOTPort commits the delivery and recovery record together. Concurrent retries with the same token, ID, and parameters return the same delivery. Recovery also works after a server restart or the source folder disappearing; it does not recreate missing source files, refresh the snapshot, extend expiry, or reactivate a revoked link.

| Result                                       | Next step                                                                                                                               |
| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| Timeout or interrupted connection            | Recover by operation ID, or repeat the original creation request unchanged.                                                             |
| HTTP 429 or server/gateway failure           | Respect `Retry-After` when present, then retry with the same ID.                                                                        |
| HTTP 409, `operation_conflict`               | The ID was already used with different parameters. Recover the original operation; use a new ID only for an intentionally new delivery. |
| HTTP 409, `delivery_changed`                 | An operator rotated the link. Ask the operator for the current link.                                                                    |
| Authentication, permission, or scope failure | Correct the token or scope before retrying. A replacement token does not inherit the previous token’s deliveries.                       |

The raw HTTP share endpoint allows omitted operation IDs for one-off calls, but those calls cannot be safely replayed after a lost response. The agent CLI and MCP require an explicit ID.

Creation hashes the selected files and can take time. The HTTP client allows up to 30 minutes per request. Creation and recovery share a limit of 60 calls per IP per ten minutes; other automation calls allow 6,000. Preparation capacity is shared with browser and desktop operations.

## Read activity and retain evidence

Delivery detail includes each file’s VOT `suite`, `root`, `bytes`, base64 CBOR `receipt_b64`, `download_starts`, and first/last download timestamps. The delivery `state` is `active`, `expired`, or `revoked`; download caps and counters are reported separately.

**A download start is not proof that the recipient finished.** A library receipt identifies the source object. The receiving client verifies its local bytes against that identity. For project jobs, read signed verification and acceptance through `get_job_evidence`. Advance dependent work on the evidence your policy requires; a `ready` job or a download counter does not establish recipient acceptance.

Retain signed receipts with your delivery records and [verify the file and receipt](/docs/using/verification/) when needed. Audit entries identify creation and revocation as `automation:<token-id>`; creation includes the operation ID. Workflow webhooks have persistent attempts, retries, and replay. Query signed event history and job state to reconcile missed events; ordinary notifications remain separate.

## Watch an export folder

```sh
votport watch add './Exports' 'https://transfer.example/r/REQUEST_TOKEN'
votport watch list
votport watch run --json
votport watch remove WATCH_ID
```

Keep `watch run` running. It scans every two seconds and waits for a top-level file or folder to remain unchanged for ten seconds, using file count, total bytes, and change times. A successful send moves that drop into the watched folder’s `shipped` subfolder. A failed drop remains in place and is not continually resubmitted unchanged; resolve the failure and use the transfer’s retry or resume path.

For reliable exports, write outside the watched directory and move each completed drop into it. An exporter that pauses longer than ten seconds can otherwise look finished. Keep the folder writable so successful drops can move to `shipped`, and keep the destination request valid with sufficient quota.

Password-protected watches retain their password in the client’s private local configuration for unattended sending. Protect that machine and account. Removing a watch leaves its files in place.
