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.
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.
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)
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
{
"query": "librarySync"
}
cURL Example
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
{
"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
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.
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
{
"query": "librarySync",
"data": {
"since": "2026-07-20T12:30:00"
}
}
cURL Example
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
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_urlentries. 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 -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)
{
"query": "libraryUpload",
"data": {
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"name": "Training Video",
"folderId": 5
}
}
Response
{
"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.
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
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.
|
{
"query": "libraryFolderCreate",
"data": {
"name": "Ground School",
"parentId": null
}
}
Response
{
"apiVersion": "1.3.6",
"success": true,
"folder": {
"id": 47,
"parentId": null,
"name": "Ground School",
"ownerType": "user",
"ownerId": 42
}
}
Rename Folder
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. |
{
"query": "libraryFolderRename",
"data": {
"folderId": 47,
"name": "Ground School 2025"
}
}
Response
{
"apiVersion": "1.3.6",
"success": true,
"folder": {
"id": 47,
"name": "Ground School 2025"
}
}
Delete Folder
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. |
{
"query": "libraryFolderDelete",
"data": {
"folderId": 47
}
}
Response
{
"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. |
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
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. |
{
"query": "libraryFileRename",
"data": {
"fileId": 103,
"name": "B737 Operations Manual Rev2"
}
}
Response
{
"apiVersion": "1.3.6",
"success": true,
"file": {
"id": 103,
"name": "B737 Operations Manual Rev2"
}
}
Delete File
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. |
{
"query": "libraryFileDelete",
"data": {
"fileId": 103
}
}
Response
{
"apiVersion": "1.3.6",
"success": true,
"deletedFileId": 103
}
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
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>
|
{
"query": "userStatistics"
}
Response
{
"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
-
On first launch, call
librarySyncwithoutsince. Store all folders and files locally. - Save the returned
syncedAttimestamp. -
On subsequent launches, pass
syncedAtasdata.since. -
Merge returned folders/files into local cache. Remove entries
where
deletedAtis non-null. -
Use
fileHashto skip re-downloading unchanged files.
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.
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.
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.