# DVS tasks integration quickstart

Use this workflow to discover IDs and prepare a correct task request without guessing. DVS and DMS name the same public data-management API. The [full DMS reference](filesfm_api_dms.md) describes the actions and field types.

## Prerequisites

- A dedicated Files.fm user in an organization with DVS enabled.
- An API access token from the account's API-key settings.
- Section **write** permission on both `task` and `project_2`, even for API reads. Contact/client lookup needs the corresponding section permission.
- The name of the existing project. `project_2` is the DVS projects register; it is not the separate Objects API.

Base URL: `https://api.files.fm`. Every DVS action uses **POST JSON** and includes `user` and `user_access_token`. A website session alone and an MCP Bearer token are not this authentication format. Never put credentials in URLs.

## 1. Discover fields and projects

```http
POST /api_dvs/task/get_fields
Content-Type: application/json

{"user":"YOUR_USER","user_access_token":"YOUR_API_TOKEN"}
```

Read `fields[].name`, `type`, `required`, `filter`, `options`, `section`, and `depends_on`. Required task fields currently include `name` and `dvs_project_id`. Dropdown option IDs belong to this organization; example values from documentation are not reusable IDs.

```http
POST /api_dvs/project_2/get_documents
Content-Type: application/json

{"user":"YOUR_USER","user_access_token":"YOUR_API_TOKEN","limit":200,"offset":0}
```

Match the requested project against `items[].name` and retain its integer `dvs_document_id`. Continue with `offset += items.length` until `offset >= total`. Stop and ask for a choice if a name is absent or ambiguous. A short page is not itself the documented completion condition; use `total`.

Filters use field names with `filter: true` from `get_fields`. Unknown filter names are ignored, not rejected. Multiple values for a field are OR; different fields are AND. Lists omit HTML descriptions; use `get_document` for full content.

## 2. Discover assignable users and status options

```http
POST /api_dvs/task/get_users
Content-Type: application/json

{"user":"YOUR_USER","user_access_token":"YOUR_API_TOKEN","dvs_project_id":123}
```

Here `123` represents the project ID just discovered. Resolve `users[].display_name` to an integer `id`; do not substitute email addresses or usernames in task user fields. Only use the users returned for that project.

Resolve `dropdown_status`, `dropdown_priority`, and other dropdown values from the task field's `options`. For external followers, look up `contact_person` document IDs; those are different from platform user IDs. [Contact and client relationships](filesfm_api_dms.md#supported-registers)

## 3. Create a task

After discovery, construct this body using the real IDs and any additional required fields:

```json
{
  "user": "YOUR_USER",
  "user_access_token": "YOUR_API_TOKEN",
  "create_params": {
    "dvs_project_id": 123,
    "name": "Review integration",
    "responsible": 456,
    "dropdown_status": 789,
    "description": "<p>Review the integration.</p>"
  }
}
```

Send to `POST /api_dvs/task/create_document`. Optional fields may be omitted. IDs `123`, `456`, and `789` above are illustrative; replace them with discovery results.

```json
{"dvs_document_id":4822}
```

Retain the returned task ID. Creation and updates can send notifications. The API has no documented idempotency key: after a timeout or uncertain write outcome, reconcile with task reads before retrying. Invalid relation IDs may fail after part of a write has occurred; a failure is not proof that nothing was saved.

## 4. Read, update, and comment

Call `task/get_document` with auth and `dvs_document_id` to read the full saved record. IDs in read responses are often objects such as `{ "id": 456, "display_name": "..." }`; write requests need the scalar IDs.

```json
{
  "user": "YOUR_USER",
  "user_access_token": "YOUR_API_TOKEN",
  "dvs_document_id": 4822,
  "update_params": { "dropdown_status": 790 }
}
```

Send to `POST /api_dvs/task/update_document`. Discover `790` from `get_fields`. This is a partial update: omitted fields keep their values; arrays supplied for workers/relations replace that field's selection. The task's project cannot be changed through this API.

```json
{
  "user": "YOUR_USER",
  "user_access_token": "YOUR_API_TOKEN",
  "dvs_document_id": 4822,
  "comment": "Integration reviewed."
}
```

Send to `POST /api_dvs/task/add_comment`. Mention a platform user with `@[USER:456]`; mentions can notify users. There is no documented task delete action in this API. Clean up test records through the authorized DVS UI.

## curl

Set credentials in your local environment. The following uses Node to write JSON to stdin, keeping the token out of the URL and curl arguments:

```bash
export FILESFM_USER='YOUR_USER'
export FILESFM_API_TOKEN='YOUR_API_TOKEN'
node -e 'process.stdout.write(JSON.stringify({user:process.env.FILESFM_USER,user_access_token:process.env.FILESFM_API_TOKEN}))' |
  curl --silent --show-error --fail-with-body --max-time 30 \
    'https://api.files.fm/api_dvs/task/get_fields' \
    -H 'Content-Type: application/json' --data-binary @-
```

For write calls, prepare the JSON body from discovered IDs in a local private file and use `--data-binary @request.json`. Protect and remove credential-bearing files after use. Do not use verbose HTTP traces with real credentials.

## JavaScript (Node 18+ or a trusted server)

```js
async function dvs(section, action, params = {}) {
  const response = await fetch(`https://api.files.fm/api_dvs/${section}/${action}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ ...params, user: process.env.FILESFM_USER,
      user_access_token: process.env.FILESFM_API_TOKEN }),
    signal: AbortSignal.timeout(30000)
  });
  const text = await response.text();
  if (!response.ok) throw new Error(`DVS HTTP ${response.status}`);
  if (!text) throw new Error('Missing success response');
  return JSON.parse(text);
}

const { fields } = await dvs('task', 'get_fields');
const projects = [];
let offset = 0;
while (true) {
  const page = await dvs('project_2', 'get_documents', { limit: 200, offset });
  projects.push(...page.items);
  offset += page.items.length;
  if (offset >= page.total) break;
  if (!page.items.length) throw new Error('Incomplete project listing');
}
const matches = projects.filter(p => p.name === process.env.FILESFM_PROJECT_NAME);
if (matches.length !== 1) throw new Error('Choose one existing project');
const projectId = matches[0].dvs_document_id;
const { users } = await dvs('task', 'get_users', { dvs_project_id: projectId });
const statusOptions = fields.find(f => f.name === 'dropdown_status')?.options || [];
// Select a user and status from users/statusOptions; omit them if not needed.
const createParams = { dvs_project_id: projectId, name: 'Review integration' };
console.log({ endpoint: '/api_dvs/task/create_document', create_params: createParams });

// Only run the following block when task creation and notifications are authorized:
// const created = await dvs('task', 'create_document', { create_params: createParams });
// const task = await dvs('task', 'get_document', { dvs_document_id: created.dvs_document_id });
// await dvs('task', 'update_document', { dvs_document_id: task.dvs_document_id,
//   update_params: { description: '<p>Integration verified.</p>' } });
// await dvs('task', 'add_comment', { dvs_document_id: task.dvs_document_id,
//   comment: 'Integration reviewed.' });
```

Keep API tokens on a trusted server, not in shipped browser JavaScript. Client-side UI should call your own authorized integration backend.

## PHP 7.4+

```php
<?php
function dvs($section, $action, array $params = []) {
    $params['user'] = getenv('FILESFM_USER');
    $params['user_access_token'] = getenv('FILESFM_API_TOKEN');
    $curl = curl_init('https://api.files.fm/api_dvs/' . $section . '/' . $action);
    curl_setopt_array($curl, [
        CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
        CURLOPT_POSTFIELDS => json_encode($params, JSON_THROW_ON_ERROR),
        CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30,
    ]);
    $body = curl_exec($curl);
    $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    $failed = $body === false;
    curl_close($curl);
    if ($failed) { throw new RuntimeException('DVS transport failed'); }
    if ($status !== 200) { throw new RuntimeException('DVS HTTP ' . $status); }
    return json_decode($body, true, 512, JSON_THROW_ON_ERROR);
}

$fields = dvs('task', 'get_fields')['fields'];
$projects = []; $offset = 0;
do {
    $page = dvs('project_2', 'get_documents', ['limit' => 200, 'offset' => $offset]);
    $projects = array_merge($projects, $page['items']);
    $offset += count($page['items']);
    if (!$page['items'] && $offset < $page['total']) {
        throw new RuntimeException('Incomplete project listing');
    }
} while ($offset < $page['total']);
$matches = array_values(array_filter($projects, function ($p) {
    return $p['name'] === getenv('FILESFM_PROJECT_NAME');
}));
if (count($matches) !== 1) { throw new RuntimeException('Choose one existing project'); }
$projectId = $matches[0]['dvs_document_id'];
$users = dvs('task', 'get_users', ['dvs_project_id' => $projectId])['users'];
$createParams = ['dvs_project_id' => $projectId, 'name' => 'Review integration'];
// After explicit write authorization:
// $created = dvs('task', 'create_document', ['create_params' => $createParams]);
// $task = dvs('task', 'get_document', ['dvs_document_id' => $created['dvs_document_id']]);
// dvs('task', 'update_document', ['dvs_document_id' => $task['dvs_document_id'],
//     'update_params' => ['description' => '<p>Integration verified.</p>']]);
// dvs('task', 'add_comment', ['dvs_document_id' => $task['dvs_document_id'],
//     'comment' => 'Integration reviewed.']);
```

## Failure handling and MCP

DVS errors can have an empty body. Check status first: `400` parameters, `401` authentication or missing session organization, `405` method/section/permission/not-found conditions, `500` backend failure. Do not log request bodies containing tokens. No universal public DVS request quota is promised; infrastructure can enforce additional limits.

Public MCP `filesfm_search_docs` and `filesfm_get_doc` can find and retrieve this guide without auth. Use that content to prepare REST requests. MCP does not create tasks, enumerate DVS projects, or supply your organization's IDs.
