Skip to content

API Reference ​

API Teldock adalah layanan REST yang disajikan oleh backend Node.js. Semua route di bawah ini di-mount dengan prefiks /api, kecuali endpoint WebDAV yang di-mount pada /webdav.

Base URL dan konvensi ​

text
http://localhost:3001/api

Di produksi, frontend dan API disajikan dari origin yang sama di balik Nginx, sehingga base URL-nya menjadi https://yourdomain.com/api.

Response envelope ​

Respons sukses membungkus payload di dalam data:

json
{
  "success": true,
  "data": { }
}

Error menggunakan success: false dengan string error yang mudah dibaca:

json
{
  "success": false,
  "error": "File not found"
}

Authentication ​

Endpoint terproteksi memerlukan bearer access token:

http
Authorization: Bearer <access-token>

Peroleh token dari POST /auth/register atau POST /auth/login, lalu perbarui dengan POST /auth/refresh.

Kode status error ​

StatusArti
400Validasi gagal atau ada field wajib yang kosong.
401Access token tidak dikirim, atau kredensial tidak valid.
403Token tidak valid/kedaluwarsa, atau pemanggil bukan pemilik resource.
404Resource yang diminta tidak ada.
409Konflik (user, folder, atau tag duplikat; file terenkripsi tidak bisa di-preview).
413Upload melebihi MAX_UPLOAD_BYTES, atau sumber pratinjau melebihi batas pratinjau 25 MB.
415Upload WebDAV ditolak oleh whitelist MIME.
416Rentang byte yang diminta tidak dapat dipenuhi.
429Rate limit terlampaui.
500Error server tak terduga.
502Download dari Telegram gagal saat streaming shared link.
503FFmpeg tidak terpasang, sehingga pratinjau video tidak tersedia.

Rate limit dan header ​

CakupanBatasJendela
Semua route /api/100 request15 menit
POST /api/auth/login20 percobaan1 jam
Semua route /webdav5000 request15 menit
Autentikasi /webdav gagal20 percobaan15 menit

Respons menyertakan header standar RateLimit-*:

HeaderDeskripsi
RateLimit-LimitJumlah maksimum request yang diizinkan pada jendela saat ini.
RateLimit-RemainingRequest yang tersisa pada jendela saat ini.
RateLimit-ResetDetik hingga jendela direset.

INFO

Server dikonfigurasi dengan standardHeaders: true dan legacyHeaders: false, sehingga header lama X-RateLimit-Limit, X-RateLimit-Remaining, dan X-RateLimit-Reset tidak dikirim.

Auth ​

Base path: /api/auth

MethodPathAuthDeskripsi
POST/auth/registerPublicMembuat akun dan mengembalikan token.
POST/auth/loginPublicAutentikasi dengan email dan password.
POST/auth/refreshPublicMenukar refresh token dengan access token baru.
GET/auth/meBearerMengembalikan profil pengguna saat ini.

POST /auth/register ​

Request:

json
{
  "email": "user@example.com",
  "password": "a-strong-password",
  "username": "user",
  "firstName": "Ada",
  "lastName": "Lovelace"
}

Response (201):

json
{
  "success": true,
  "message": "User registered successfully",
  "data": {
    "user": {
      "id": "0f9a6d3e-1c2b-4a5d-8e7f-1234567890ab",
      "email": "user@example.com",
      "telegramId": null,
      "username": "user",
      "firstName": "Ada",
      "storageQuotaBytes": null,
      "storageUsedBytes": 0
    },
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expiresAt": 1790000000000
  }
}

POST /auth/login ​

Request:

json
{
  "email": "user@example.com",
  "password": "a-strong-password"
}

Response (200):

json
{
  "success": true,
  "message": "Login successful",
  "data": {
    "user": {
      "id": "0f9a6d3e-1c2b-4a5d-8e7f-1234567890ab",
      "email": "user@example.com",
      "username": "user",
      "storageQuotaBytes": null,
      "storageUsedBytes": 10485760
    },
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expiresAt": 1790000000000
  }
}

POST /auth/refresh ​

Request:

json
{
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response (200):

json
{
  "success": true,
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expiresAt": 1790000000000
  }
}

GET /auth/me ​

Response (200):

json
{
  "success": true,
  "data": {
    "user": {
      "id": "0f9a6d3e-1c2b-4a5d-8e7f-1234567890ab",
      "email": "user@example.com",
      "telegramId": null,
      "username": "user",
      "firstName": "Ada",
      "lastName": "Lovelace",
      "avatarUrl": null,
      "storageQuotaBytes": null,
      "storageUsedBytes": 10485760,
      "isPremium": false,
      "premiumUntil": null
    }
  }
}

Files ​

Base path: /api/files

MethodPathAuthDeskripsi
POST/files/uploadBearerMengunggah file (multipart dengan streaming).
GET/filesBearerMendaftar file dengan filter dan paginasi.
GET/files/searchBearerMencari file berdasarkan nama.
POST/files/bulkBearerMenghapus atau memindahkan file secara massal.
POST/files/:id/download-urlBearerMembuat signed download URL.
GET/files/:id/downloadBearer atau signed URLStreaming file sebagai attachment.
POST/files/:id/preview-urlBearerMembuat signed preview URL.
GET/files/:id/previewBearer atau signed URLStreaming file secara inline.
GET/files/:id/versionsBearerMendaftar riwayat versi.
POST/files/:id/revert/:versionIdBearerMemulihkan versi sebelumnya.
POST/files/:id/shareBearerMembuat public share link.
PATCH/files/:idBearerMemperbarui nama file, folder, atau status favorit.
PUT/files/:id/tagsBearerMengganti tag file.
DELETE/files/:idBearerSoft-delete file.
GET/files/s/:tokenPublicMengakses shared link.

POST /files/upload ​

Upload multipart form. Body di-parse sebagai stream, sehingga file tidak pernah di-buffer di memori.

FieldTipeWajibDeskripsi
filefileYaFile yang diunggah.
folderIdstringTidakUUID folder tujuan.
encryptbooleanTidakMengenkripsi part yang disimpan.

Response (201):

json
{
  "success": true,
  "message": "File uploaded successfully",
  "data": {
    "file": {
      "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "displayFilename": "report.pdf",
      "mimeType": "application/pdf",
      "fileSize": 5242880,
      "isChunked": false,
      "partCount": 1,
      "isEncrypted": false
    },
    "versioned": false
  }
}

Jika sudah ada file dengan nama yang sama di folder tujuan, konten sebelumnya disimpan sebagai versi dan versioned bernilai true dengan pesan "File updated (previous saved as version)".

GET /files ​

Query parameter:

ParameterTipeDefaultDeskripsi
folderIdUUID—Filter berdasarkan folder.
pageinteger1Nomor halaman.
limitinteger50Jumlah item per halaman.
sortBystringcreatedAtKolom pengurutan.
sortOrderASC/DESCDESCArah pengurutan.
includeDeletedbooleanfalseSertakan file yang soft-deleted.
favoritebooleanfalseHanya favorit.
tagIdUUID—Filter berdasarkan tag.

Response (200):

json
{
  "success": true,
  "data": {
    "files": [
      {
        "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
        "displayFilename": "report.pdf",
        "mimeType": "application/pdf",
        "fileSize": 5242880,
        "isFavorite": false
      }
    ],
    "total": 1,
    "currentPage": 1,
    "totalPages": 1,
    "hasMore": false
  }
}

Query parameter: q (wajib), page, limit.

POST /files/bulk ​

Request:

json
{
  "action": "move",
  "fileIds": [
    "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
  ],
  "folderId": "9f8e7d6c-5b4a-4938-8271-6f5e4d3c2b1a"
}

action bernilai "delete" atau "move"; folderId hanya dipakai untuk move. Response (200):

json
{
  "success": true,
  "message": "Moved 2 file(s)",
  "data": { "count": 2 }
}

POST /files/:id/download-url ​

Response (200):

json
{
  "success": true,
  "data": {
    "url": "/api/files/7c9e6679-7425-40de-944b-e07fc1f90ae7/download?signature=eyJhbGciOiJIUzI1NiJ9..."
  }
}

POST /files/:id/preview-url ​

Mengembalikan signed URL untuk tampilan inline. Response (200):

json
{
  "success": true,
  "data": {
    "url": "/api/files/7c9e6679-7425-40de-944b-e07fc1f90ae7/preview?signature=eyJhbGciOiJIUzI1NiJ9..."
  }
}

WARNING

File terenkripsi tidak dapat di-preview. GET /files/:id/preview mengembalikan 409 untuk file terenkripsi; unduh saja file tersebut.

GET /files/:id/download dan GET /files/:id/preview ​

Endpoint ini menerima bearer token atau query parameter signature yang dihasilkan oleh endpoint download-url / preview-url. Keduanya mendukung permintaan HTTP Range dan merespons dengan 206 saat rentang parsial dilayani.

bash
# Menggunakan signed URL yang dikembalikan oleh /download-url
curl -OJ "https://yourdomain.com/api/files/7c9e6679-.../download?signature=eyJ..."

POST /files/:id/share ​

Request:

json
{
  "expiresIn": 86400,
  "downloadLimit": 5,
  "password": "optional-password",
  "allowPreview": true
}

Response (201):

json
{
  "success": true,
  "message": "Shared link created",
  "data": {
    "link": {
      "id": "3f1c2b4a-5d6e-4f70-8a91-b2c3d4e5f607",
      "shortUrl": "https://yourdomain.com/s/eyJhbGciOiJIUzI1NiJ9...",
      "expiresAt": "2026-10-01T12:00:00.000Z",
      "downloadLimit": 5,
      "usedDownloads": 0
    }
  }
}

GET /files/s/:token (public) ​

Endpoint shared link publik. Secara default mengembalikan metadata file, atau melakukan streaming file saat ?download=true dikirim dan link mengizinkan download.

json
{
  "success": true,
  "data": {
    "file": {
      "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "originalFilename": "report.pdf",
      "displayFilename": "report.pdf",
      "mimeType": "application/pdf",
      "fileSize": 5242880,
      "isEncrypted": false,
      "uploadedAt": "2026-09-01T10:00:00.000Z"
    },
    "expiresAt": "2026-10-01T12:00:00.000Z",
    "allowDownload": true,
    "usedDownloads": 0,
    "downloadLimit": 5
  }
}

Untuk link yang dilindungi password, kirim password pada header X-Share-Password. Tanpa password, endpoint merespons dengan { "success": true, "requiresPassword": true, ... }; dengan password yang salah, endpoint merespons 401 dengan { "success": false, "error": "Incorrect password" }.

PATCH /files/:id ​

json
{
  "displayFilename": "renamed.pdf",
  "folderId": "9f8e7d6c-5b4a-4938-8271-6f5e4d3c2b1a",
  "isFavorite": true
}

Sertakan minimal satu field. Gunakan folderId: null atau "root" untuk memindahkan file ke root.

PUT /files/:id/tags ​

json
{
  "tagIds": ["c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f"]
}

DELETE /files/:id ​

Melakukan soft-delete pada file. Kirim ?deleteFromTelegram=false untuk mempertahankan pesan di Telegram.

GET /files/:id/versions dan POST /files/:id/revert/:versionId ​

Mendaftar riwayat versi, atau memulihkan salah satunya:

json
{
  "success": true,
  "message": "Reverted to version 2",
  "data": {
    "version": {
      "id": "d4e5f607-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
      "versionNumber": 2,
      "filename": "report.pdf",
      "mimeType": "application/pdf",
      "fileSize": 5242880,
      "isChunked": false,
      "partCount": 1,
      "isEncrypted": false,
      "createdAt": "2026-09-01T10:00:00.000Z"
    }
  }
}

Folders ​

Base path: /api/folders

MethodPathAuthDeskripsi
GET/foldersBearerMendaftar folder (opsional parentFolderId).
POST/foldersBearerMembuat folder.
PUT/folders/:idBearerMengganti nama folder.
DELETE/folders/:idBearerMenghapus subtree folder.

Request pembuatan: { "name": "Documents", "parentFolderId": null, "icon": "folder" }. Menghapus folder akan melepaskan file di dalamnya (dipindahkan ke root), bukan menghapusnya.

Telegram ​

Base path: /api/user/telegram

MethodPathAuthDeskripsi
POST/user/telegram/connectBearerMenghubungkan bot token dan storage chat.
PUT/user/telegram/configBearerMemperbarui konfigurasi Telegram yang ada.
GET/user/telegram/statusBearerMelaporkan status koneksi.
DELETE/user/telegram/unlinkBearerMemutus koneksi Telegram.

Request dan response connect (201):

json
{
  "botToken": "123456789:AAExampleTokenValue",
  "chatId": "-1001234567890",
  "chatType": "channel",
  "username": "my_storage_channel"
}
json
{
  "success": true,
  "message": "Telegram connected successfully",
  "data": {
    "id": "5e4d3c2b-1a09-4876-b5c4-d3e2f1a0b9c8",
    "chatType": "channel",
    "username": "my_storage_channel",
    "isSetupComplete": true
  }
}

Bot token dan chat ID divalidasi ke Telegram API sebelum disimpan. Pembaruan config memerlukan botToken dan chatId secara bersamaan.

Bots ​

Base path: /api/bots (multi-bot pool)

MethodPathAuthDeskripsi
GET/botsBearerMendaftar bot pool milik pengguna.
POST/botsBearerMenambah dan memvalidasi bot token.
DELETE/bots/:idBearerMenghapus bot dari pool.

Request penambahan: { "token": "123456789:AAExampleTokenValue" }.

Shares ​

Base path: /api/shares

MethodPathAuthDeskripsi
GET/sharesBearerMendaftar link yang dibuat pengguna (page, limit).
DELETE/shares/:idBearerMencabut shared link.

Tags ​

Base path: /api/tags

MethodPathAuthDeskripsi
GET/tagsBearerMendaftar tag beserta jumlah file.
POST/tagsBearerMembuat tag.
PUT/tags/:idBearerMengganti nama atau warna tag.
DELETE/tags/:idBearerMenghapus tag.

Request pembuatan: { "name": "work", "color": "#10b981" }.

Smart folders ​

Base path: /api/smart-folders

MethodPathAuthDeskripsi
GET/smart-foldersBearerMendaftar filter tersimpan.
POST/smart-foldersBearerMembuat filter tersimpan.
DELETE/smart-folders/:idBearerMenghapus filter tersimpan.

Request pembuatan: { "name": "Recent images", "icon": "sparkles", "criteria": { "type": "image" } }. Key criteria yang didukung adalah favorite, tagId, type, dan q.

Previews ​

Base path: /api/previews

MethodPathAuthDeskripsi
POST/previews/generateBearerMembuat pratinjau untuk file gambar atau video milik pemanggil.

Request: { "fileId": "7c9e6679-7425-40de-944b-e07fc1f90ae7" }. File harus milik pemanggil. File gambar (image/*) dan video (video/*) hingga 25 MB didukung; file lebih besar mengembalikan 413. Response berisi data URL base64.

Untuk gambar, data.previews berisi varian hasil resize (tidak berubah). Untuk video, response menambahkan penanda type: "video" dan mengembalikan satu thumbnail JPEG 640x360 yang diambil pada detik ke-1, plus durasi dalam detik (null bila tidak dapat dibaca):

json
{
  "success": true,
  "data": {
    "type": "video",
    "previews": {
      "thumbnail": {
        "dataUrl": "data:image/jpeg;base64,...",
        "dimensions": { "width": 640, "height": 360 },
        "fileSize": 15021
      }
    },
    "duration": 2,
    "processingTime": 123
  }
}

Pratinjau video memerlukan FFmpeg di server; bila binary ffmpeg tidak tersedia, endpoint mengembalikan 503, sedangkan pratinjau gambar tetap berfungsi. Karena kedua pipeline menyangga sumber di memori, pratinjau video dibatasi 25 MB dan sebagian besar video berukuran besar melewatinya. Kode status pratinjau video: 400 (tipe MIME bukan gambar maupun video), 403 (pemanggil bukan pemilik file), 404 (file tidak ditemukan), 413 (sumber melebihi batas 25 MB), 503 (FFmpeg tidak terpasang), 500 (kegagalan lain).

Stats ​

Base path: /api/stats

MethodPathAuthDeskripsi
GET/stats/storageBearerAgregasi penggunaan storage per kategori.
GET/stats/duplicatesBearerMencari file dengan checksum yang sama.

WebDAV ​

Base path: /webdav (bukan di bawah /api)

WebDAV memakai autentikasi HTTP Basic dengan email dan password akun, dan ditujukan untuk Rclone serta klien sejenis. Router mengizinkan 5000 request per 15 menit (dapat diatur melalui WEBDAV_RATE_LIMIT_MAX), sedangkan percobaan autentikasi yang gagal dibatasi terpisah sebanyak 20 per 15 menit.

MethodFungsi
OPTIONSMengumumkan kemampuan DAV (DAV: 1, 2).
PROPFINDListing direktori (mendukung Depth: 0 dan Depth: 1).
GETMengunduh file, dengan dukungan Range.
HEADMengembalikan header file tanpa body.
PUTMengunggah file (whitelist MIME diterapkan).
DELETEMenghapus file atau folder.
MKCOLMembuat folder.
MOVEMengganti nama atau memindahkan file.

File dialamatkan dengan model path datar, misalnya /webdav/Documents/report.pdf. Lihat WebDAV & Rclone untuk penyiapan klien.

Health ​

MethodPathAuthDeskripsi
GET/healthPublicPemeriksaan liveness yang mengembalikan timestamp.
json
{
  "success": true,
  "message": "API is running",
  "timestamp": "2026-09-27T12:00:00.000Z"
}

Halaman terkait ​

Released under the MIT License.