Library API

Overview

The Library API provides access to documents, images, and video links organized in a folder hierarchy. Content is scoped by subscription tier and virtual airline membership, allowing apps to sync only the resources the pilot is entitled to.

Developer Key Required

The library permission must be enabled on your developer key. Without it, requests will return an error. Contact VPT support to enable library access for your key.

Tier-Based Content

Each folder and file has a minProductLevel field. The API automatically filters content based on the user's highest active subscription level. Level 0 means available to all tiers.

Library Sync (Full)

POST /api

Returns all folders and files the authenticated user has access to. On first launch or when the local cache is empty, perform a full sync by omitting the since parameter.

Request Parameters

Parameter Type Required Description
query string Required Must be "librarySync"
Authorization header string Required Bearer JWT token: Authorization: Bearer <token>

Request Body

JSON
{
  "query": "librarySync"
}

cURL Example

cURL
curl -X POST "https://api.virtualperformancetool.com/api" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "X-API-Version: 1.3.6" \
  -H "X-Dev-Key: YOUR_DEV_KEY" \
  -d '{
    "query": "librarySync"
  }'

Response

JSON
{
  "apiVersion": "1.3.6",
  "success": true,
  "library": {
    "folders": [
      {
        "id": "1",
        "parentId": null,
        "name": "Training Documents",
        "ownerType": "system",
        "ownerId": null,
        "minProductLevel": "0",
        "sortOrder": "0",
        "createdAt": "2026-07-20 10:00:00",
        "updatedAt": "2026-07-20 10:00:00"
      },
      {
        "id": "3",
        "parentId": "1",
        "name": "Dangerous Goods",
        "ownerType": "system",
        "ownerId": null,
        "minProductLevel": "2",
        "sortOrder": "1",
        "createdAt": "2026-07-20 10:05:00",
        "updatedAt": "2026-07-20 10:05:00"
      }
    ],
    "files": [
      {
        "id": "1",
        "folderId": "1",
        "name": "FlightOps Manual.pdf",
        "type": "file",
        "mimeType": "application/pdf",
        "filePath": "Library/uploads/system/0/FlightOps_Manual_1721472000_a1b2c3d4.pdf",
        "url": null,
        "fileSize": "2048576",
        "fileHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
        "version": "1",
        "minProductLevel": "0",
        "ownerType": "system",
        "ownerId": null,
        "createdAt": "2026-07-20 10:10:00",
        "updatedAt": "2026-07-20 10:10:00",
        "deletedAt": null,
        "downloadUrl": "https://api.virtualperformancetool.com/Library/uploads/system/0/FlightOps_Manual_1721472000_a1b2c3d4.pdf"
      },
      {
        "id": "5",
        "folderId": "1",
        "name": "Welcome Video",
        "type": "video_url",
        "mimeType": null,
        "filePath": null,
        "url": "https://www.youtube.com/watch?v=example",
        "fileSize": "0",
        "fileHash": null,
        "version": "1",
        "minProductLevel": "0",
        "ownerType": "system",
        "ownerId": null,
        "createdAt": "2026-07-20 10:15:00",
        "updatedAt": "2026-07-20 10:15:00",
        "deletedAt": null
      }
    ],
    "syncedAt": "2026-07-20 12:30:00",
    "userProductLevel": 3,
    "storage": {
      "va": {
        "usedBytes": 47185920,
        "quotaMb": 100
      }
    }
  }
}

Incremental Sync

POST /api

To reduce bandwidth, pass the since parameter with the timestamp from your last successful sync. The API returns only folders and files that have been created, updated, or soft-deleted since that time.

Detecting Deletions

During incremental sync, soft-deleted files are included with a non-null deletedAt field. Your client should remove these from the local cache.

Additional Parameters

Parameter Type Required Description
data.since string Optional ISO 8601 or MySQL datetime string (e.g. "2026-07-20T12:30:00"). Omit for full sync.

Request Body

JSON
{
  "query": "librarySync",
  "data": {
    "since": "2026-07-20T12:30:00"
  }
}

cURL Example

cURL
curl -X POST "https://api.virtualperformancetool.com/api" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "X-API-Version: 1.3.6" \
  -H "X-Dev-Key: YOUR_DEV_KEY" \
  -d '{
    "query": "librarySync",
    "data": {
      "since": "2026-07-20T12:30:00"
    }
  }'

Upload File / URL

POST /api

Allows the authenticated user to add content to their personal library. Accepted content:

  • Files — PDF and image files (JPG, PNG, GIF, WebP, SVG), uploaded as multipart/form-data. Counts against the user's personal storage quota.
  • YouTube URLs — Linked videos stored as video_url entries. No storage quota consumed.

Files are always stored as owner_type = "user" and are only visible to the uploading user via librarySync.

Request Parameters

Parameter Type Required Description
query string Required Must be "libraryUpload"
Authorization header string Required Bearer JWT token: Authorization: Bearer <token>
file (form field) binary Optional* File to upload via multipart/form-data. Required if no data.url.
data.url string Optional* YouTube URL to add. Required if no file. Must match youtube.com/watch or youtu.be/.
data.name string Optional Display name. Defaults to the filename or "YouTube Video".
data.folderId integer Optional Folder to place the file in. Must be a system folder or one owned by the user. Omit to place at root.
data.minProductLevel integer Optional Minimum subscription level to see this file. Defaults to 0 (visible to all tiers).

File Upload (multipart/form-data)

cURL
curl -X POST "https://api.virtualperformancetool.com/api" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "X-API-Version: 1.3.6" \
  -H "X-Dev-Key: YOUR_DEV_KEY" \
  -F "query=libraryUpload" \
  -F "data={\"name\":\"My Checklist\",\"folderId\":5}" \
  -F "file=@/path/to/checklist.pdf"

YouTube URL (application/json)

JSON
{
  "query": "libraryUpload",
  "data": {
    "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "name": "Training Video",
    "folderId": 5
  }
}

Response

JSON
{
  "apiVersion": "1.3.6",
  "success": true,
  "message": "File uploaded successfully.",
  "file": {
    "name": "My Checklist",
    "size": 204800,
    "mimeType": "application/pdf",
    "path": "Library/uploads/user/42/My_Checklist_1745123456_a1b2c3d4.pdf"
  }
}

For YouTube URL uploads the response omits the file object and returns only success and message.

Storage Quota

File uploads are counted against the user's personal quota (products.library_storage_mb). If the upload would exceed the quota the API returns an error with the current usage. YouTube URLs never consume quota. Users whose subscription does not include library storage cannot upload files.

Create Folder

POST /api

Creates a new personal folder for the authenticated user. Folders can be nested; to create a subfolder pass an existing user-owned folder ID as data.parentId. Root-level folders (no parent) are placed at the top of the user's personal tree.

Request Parameters

Parameter Type Required Description
query string Required Must be "libraryFolderCreate"
Authorization header string Required Bearer JWT token: Authorization: Bearer <token>
data.name string Required Display name of the new folder. Maximum 100 characters.
data.parentId integer Optional ID of an existing user-owned folder to nest inside. Omit (or set to null) for a root-level folder. System and VA folders cannot be used as a parent.
JSON
{
  "query": "libraryFolderCreate",
  "data": {
    "name": "Ground School",
    "parentId": null
  }
}

Response

JSON
{
  "apiVersion": "1.3.6",
  "success": true,
  "folder": {
    "id": 47,
    "parentId": null,
    "name": "Ground School",
    "ownerType": "user",
    "ownerId": 42
  }
}

Rename Folder

POST /api

Renames a personal folder owned by the authenticated user. Only folders with ownerType = "user" that belong to the calling user can be renamed; system and VA folders are read-only.

Request Parameters

Parameter Type Required Description
query string Required Must be "libraryFolderRename"
Authorization header string Required Bearer JWT token: Authorization: Bearer <token>
data.folderId integer Required ID of the folder to rename.
data.name string Required New display name. Maximum 100 characters.
JSON
{
  "query": "libraryFolderRename",
  "data": {
    "folderId": 47,
    "name": "Ground School 2025"
  }
}

Response

JSON
{
  "apiVersion": "1.3.6",
  "success": true,
  "folder": {
    "id": 47,
    "name": "Ground School 2025"
  }
}

Delete Folder

POST /api

Permanently deletes a personal folder and all of its contents (subfolders and files). This operation is irreversible. Only folders with ownerType = "user" that belong to the calling user can be deleted.

Request Parameters

Parameter Type Required Description
query string Required Must be "libraryFolderDelete"
Authorization header string Required Bearer JWT token: Authorization: Bearer <token>
data.folderId integer Required ID of the folder to delete.
JSON
{
  "query": "libraryFolderDelete",
  "data": {
    "folderId": 47
  }
}

Response

JSON
{
  "apiVersion": "1.3.6",
  "success": true,
  "deletedFolderIds": [47, 51, 52]
}
Field Type Description
deletedFolderIds integer[] IDs of all folders removed (the requested folder plus all descendant subfolders). Use this list to purge entries from a local cache.
Irreversible

Deletion is permanent. All subfolders and files inside the folder are removed from the database and any uploaded file data is deleted from the server. Run a librarySync after deletion to confirm the removal in your local cache.

Rename File

POST /api

Renames a personal file owned by the authenticated user. Only files with ownerType = "user" that belong to the calling user can be renamed; system and VA files are read-only.

Request Parameters

Parameter Type Required Description
query string Required Must be "libraryFileRename"
Authorization header string Required Bearer JWT token: Authorization: Bearer <token>
data.fileId integer Required ID of the file to rename.
data.name string Required New display name. Maximum 255 characters.
JSON
{
  "query": "libraryFileRename",
  "data": {
    "fileId": 103,
    "name": "B737 Operations Manual Rev2"
  }
}

Response

JSON
{
  "apiVersion": "1.3.6",
  "success": true,
  "file": {
    "id": 103,
    "name": "B737 Operations Manual Rev2"
  }
}

Delete File

POST /api

Permanently deletes a personal file owned by the authenticated user. Only files with ownerType = "user" that belong to the calling user can be deleted; system and VA files are read-only.

Request Parameters

Parameter Type Required Description
query string Required Must be "libraryFileDelete"
Authorization header string Required Bearer JWT token: Authorization: Bearer <token>
data.fileId integer Required ID of the file to delete.
JSON
{
  "query": "libraryFileDelete",
  "data": {
    "fileId": 103
  }
}

Response

JSON
{
  "apiVersion": "1.3.6",
  "success": true,
  "deletedFileId": 103
}
Irreversible

Deletion is permanent. The file record is removed from the database and any uploaded file data is deleted from the server. Run a librarySync after deletion to confirm the removal in your local cache.

User Statistics

POST /api

Returns statistics for the authenticated user, including library storage usage and quota. Storage used covers all personal uploads (files with ownerType = "user" that have not been deleted). Quota is the maximum storage allowed by the user's active subscription product.

Request Parameters

Parameter Type Required Description
query string Required Must be "userStatistics"
Authorization header string Required Bearer JWT token: Authorization: Bearer <token>
JSON
{
  "query": "userStatistics"
}

Response

JSON
{
  "apiVersion": "1.3.6",
  "success": true,
  "statistics": {
    "libraryUsedBytes": 5242880,
    "libraryAvailableMb": 100
  }
}
Field Type Description
statistics.libraryUsedBytes integer Total bytes consumed by the user's personal uploads. Divide by 1048576 to convert to MB.
statistics.libraryAvailableMb integer Storage quota in MB granted by the user's active subscription. 0 means no active subscription or no storage entitlement.

Response Fields

Field Type Description
library.folders array List of folder objects the user can access.
library.files array List of file objects the user can access.
library.syncedAt string Server timestamp of this sync. Store this value and pass it as since on the next sync.
library.userProductLevel integer The user's highest active subscription product level. Useful for client-side display logic.
library.storage object Storage usage and quota information. Always contains a user key. Contains a va key only if the user belongs to a VA.
library.storage.va.usedBytes integer Total bytes currently used by the user's VA library uploads.
library.storage.va.quotaMb integer Maximum storage in MB allocated to the VA. 0 means no quota has been set.
library.storage.user.usedBytes integer Total bytes used by the user's personal file uploads.
library.storage.user.quotaMb integer Personal storage quota in MB from the user's active subscription. 0 means no personal upload quota is available.

Folder Object

Field Type Description
id string Unique folder identifier.
parentId string|null Parent folder ID. null for root-level folders.
name string Display name of the folder.
ownerType string system (global), va (virtual airline), or user.
ownerId string|null ID of the owner (VA partner ID or user ID), or null for system content.
minProductLevel string Minimum subscription level required. 0 = all tiers.
sortOrder string Sort position among sibling folders.
createdAt string Creation timestamp.
updatedAt string Last modification timestamp.

File Object

Field Type Description
id string Unique file identifier.
folderId string ID of the containing folder.
name string Display name of the file.
type string file (downloadable document/PDF), image, or video_url (external link).
mimeType string|null MIME type of uploaded files (e.g. application/pdf).
filePath string|null Relative server path for uploaded files.
url string|null External URL for video_url type entries.
downloadUrl string|null Full download URL. Present only for uploaded files (has a filePath). Use this to download the file content.
fileSize string File size in bytes. 0 for URL entries.
fileHash string|null SHA-256 hash of the file content. Compare with your local copy to detect changes without downloading.
version string Integer version number. Incremented when the file content is replaced.
minProductLevel string Minimum subscription level. 0 = all tiers.
ownerType string system, va, or user.
ownerId string|null Owner identifier.
createdAt string Creation timestamp.
updatedAt string Last modification timestamp.
deletedAt string|null Soft-delete timestamp. Non-null means the file was removed and should be deleted from local cache. Only returned during incremental sync.

Integration Tips

Recommended Sync Flow
  1. On first launch, call librarySync without since. Store all folders and files locally.
  2. Save the returned syncedAt timestamp.
  3. On subsequent launches, pass syncedAt as data.since.
  4. Merge returned folders/files into local cache. Remove entries where deletedAt is non-null.
  5. Use fileHash to skip re-downloading unchanged files.
Building the Folder Tree

Folders reference their parent via parentId. Build a tree client-side by grouping folders by parentId. Root folders have parentId = null. Sort siblings by sortOrder, then name.

VA Content

Files and folders with ownerType = "va" are only returned for users who belong to that virtual airline. The server handles this filtering automatically based on the user's virtualAirline field.

User Uploads & Personal Folders

Users can organise their uploads into personal folders using libraryFolderCreate, libraryFolderRename, and libraryFolderDelete. These folders have ownerType = "user" and are only visible to the owning user. System and VA folders are read-only.

After calling libraryUpload or any folder mutation, run another librarySync (incremental or full) to reflect the changes in the library.files and library.folders response arrays.