Files.fm API

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 describes the actions and field types.

Prerequisites

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

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.

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

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

3. Create a task

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

{
  "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.

{"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.

{
  "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.

{
  "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:

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)

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
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.