Platform Overview
Disk.Top Open Platform
Build integrations with Disk.Top's cloud storage using OAuth 2.0 and REST APIs.
#Quick Links
- OAuth 2.0 Overview — Authorization Code, Device Code, Refresh Token grants
- Authorization Code Flow — Web & Wap apps
- Device Code Flow — CLI, TV, mobile QR
- Scopes — Permission model (sandbox vs full-disk)
- User API — Profile, quota
- Files API — Upload, list, search, download, stream
- Share API — Public share resolution, transfer
#Getting Started in 4 Steps
-
Create an app at /console — get
client_id+client_secret -
Redirect users to authorize:
GET https://openapi.disk.top/oauth/authorize?client_id=YOUR_ID&redirect_uri=YOUR_CALLBACK&response_type=code&scope=user.read+files.app_data&state=xyz -
Exchange
codeforaccess_token:POST https://openapi.disk.top/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=...&client_id=...&client_secret=...&redirect_uri=... -
Call APIs with Bearer token:
curl -H "Authorization: Bearer ACCESS_TOKEN" https://openapi.disk.top/v1/user/info
#Sandbox Model
By default (files.app_data scope), your app gets a dedicated directory under the user's cloud:
/我的应用数据/<YourAppName>/. All file operations are confined to this sandbox.
For full-disk access, request files.read_all / files.write_all scopes — users will see explicit warnings on the consent page.
OAuth 2.0 Overview
OAuth 2.0 Overview
Disk.Top supports three OAuth 2.0 grant types.
#1. Authorization Code Grant (Web)
Standard server-side flow with redirect_uri. Use for web/wap apps.
See Authorization Code Flow for details.
#2. Device Code Grant (CLI / TV)
For devices without a browser (CLI tools, Android TV, IoT). The device shows a user_code and verification_uri; user visits the URL on their phone, enters the code, and approves.
See Device Code Flow.
#3. Refresh Token
Standard grant_type=refresh_token — exchange a refresh_token for a new access_token. Refresh tokens rotate on each use.
POST https://openapi.disk.top/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=...&client_id=...&client_secret=...
#PKCE Support
All grants support PKCE (code_challenge / code_verifier). Recommended for mobile apps and SPAs where client_secret cannot be stored securely.
# Generate
code_verifier = base64url(random(32))
code_challenge = base64url(SHA256(code_verifier))
# In /oauth/authorize URL
&code_challenge=...&code_challenge_method=S256
# In /oauth/token request
&code_verifier=...Device Code Flow (CLI / TV)
Device Code Flow
For headless devices (CLI tools, Android TV, IoT) where a full browser-based OAuth flow is impractical.
#Step 1: Request a device code
POST https://openapi.disk.top/oauth/device-code
Content-Type: application/x-www-form-urlencoded
client_id=YOUR_CLIENT_ID&scope=user.read+files.app_data
Response:
{
"device_code": "sHxGyZ9rEd73E6PYg2yEdWWps9evt_oTDOqzFcxQJRxsZEUk",
"user_code": "8KXH-Y8R",
"verification_uri": "https://openapi.disk.top/oauth/device",
"verification_uri_complete": "https://openapi.disk.top/oauth/device?user_code=8KXH-Y8R",
"qr_url": "https://api.qrserver.com/v1/create-qr-code/?size=240x240&data=...",
"expires_in": 600,
"interval": 5
}
#Step 2: Display to user
Show the user_code AND/OR QR code on your device. User visits verification_uri on their phone, enters the code, and approves.
#Step 3: Poll for token
POST https://openapi.disk.top/oauth/device-token
Content-Type: application/x-www-form-urlencoded
device_code=sHxG...&client_id=YOUR_CLIENT_ID
Possible responses:
{"error":"authorization_pending"}— keep polling (respectinterval){"error":"access_denied"}— user denied; stop polling{"error":"expired_token"}— device_code expired; restart{"access_token": "...", "refresh_token": "...", ...}— success!
Scopes
Scopes
Permissions your app requests at authorization time. Users see the exact list on the consent page.
#Default (Sandbox Model)
user.read— Read user profile (uid, username, email, avatar, VIP status)files.app_data— Default sandbox. Read/write files within a dedicated directory/我的应用数据/<YourAppName>/in the user's cloud. Cannot access user's other files.
#Sensitive (Explicit Consent Required)
These scopes give your app broader access. Users see warnings on the consent page.
files.read_all— Read all user files (across all directories)files.write_all— Write/delete any user fileshare.read— List all the user's sharesshare.create— Create new shares on behalf of the user
#Best Practices
- Request the minimum scopes you need. Users abandon apps that ask too much.
- Use sandbox (
files.app_data) unless you really need full-disk access. - New apps default to sandbox-only — broader scopes require admin review.
- Users can revoke any time at disk.top/user/apps.
User API
User API
Endpoints to read the OAuth user's profile / quota and toggle share creation.
#User Profile
Returns the authenticated user (uid, nickname, avatar, VIP, granted scopes).
#Endpoint
https://openapi.disk.top/v1/user/info
#Method
GET
#Request Parameters
| Param | In | Required | Type | Description |
|---|---|---|---|---|
Authorization |
header | yes | string | Bearer {access_token}, scope user.read |
#Example Request
curl "https://openapi.disk.top/v1/user/info" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
#Response Fields
| Field | Type | Description |
|---|---|---|
data.uid |
int | User id |
data.username |
string | Login name |
data.nickname |
string | Display name |
data.email |
string | Email (masked) |
data.avatar_url |
string | Avatar URL |
data.is_vip |
bool | Is VIP |
data.vip_group |
int | VIP tier (1-10) |
data.vip_expire_ts |
int | VIP expiry unix ts; 0 = permanent or non-VIP |
data.storage_quota_bytes |
int | Total storage quota (bytes) |
data.created_at_ts |
int | Account creation unix ts |
data.oauth.client_id |
string | Currently authorized app's client_id |
data.oauth.scopes |
string[] | Granted scopes for this token |
#Example Response
{
"errno": 0,
"errmsg": "ok",
"data": {
"uid": 17,
"username": "dwtonline",
"nickname": "jam",
"email": "[email protected]",
"avatar_url": "https://disk.top/uploads/upload/avatar/17_xxx.jpg",
"is_vip": false,
"vip_group": 3,
"vip_expire_ts": 0,
"storage_quota_bytes": 1610612736000,
"created_at_ts": 1636115986,
"oauth": {
"client_id": "your_client_id",
"scopes": ["user.read","files.app_data"]
}
}
}
#Quota
Returns the user's total / used / free storage and percentage. Use this to render a storage progress bar.
#Endpoint
https://openapi.disk.top/v1/user/quota
#Method
GET
#Request Parameters
| Param | In | Required | Type | Description |
|---|---|---|---|---|
Authorization |
header | yes | string | Bearer {access_token}, scope user.read |
#Example Request
curl "https://openapi.disk.top/v1/user/quota" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
#Response Fields
| Field | Type | Description |
|---|---|---|
data.total_bytes |
int | Total quota (bytes) |
data.used_bytes |
int | Used |
data.free_bytes |
int | Free |
data.used_pct |
float | Used percentage (0-100) |
#Example Response
{
"errno": 0,
"errmsg": "ok",
"data": {
"total_bytes": 1610612736000,
"used_bytes": 33691310918,
"free_bytes": 1576921425082,
"used_pct": 2.09
}
}
#Enable Share Capability
Activate share-link creation for the authenticated user (call once per integration). After enabling, the /v1/share/* create endpoints become available.
#Endpoint
https://openapi.disk.top/v1/user/share-enable
#Method
POST
#Request Parameters
| Param | In | Required | Type | Description |
|---|---|---|---|---|
Authorization |
header | yes | string | Bearer {access_token}, scope share.create |
#Example Request
curl -X POST "https://openapi.disk.top/v1/user/share-enable" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
#Response Fields
| Field | Type | Description |
|---|---|---|
data.enabled |
bool | true = activated |
data.note |
string | Status note |
#Example Response
{
"errno": 0,
"errmsg": "ok",
"data": {
"enabled": true,
"note": "Share endpoints are now active."
}
}Files API
Files API
OAuth apps read and write user files. The default scope files.app_data constrains operations to the app's sandbox folder /{Localized My App Data}/{AppName}/; files.write_all grants full-disk access (requires explicit user consent).
Upload protocol:
precreate(get upload_id + endpoint) → upload chunks →complete. Client does not need to know how the backend stores files.
#List Directory
List sub-folders + files at a path (sandbox or full disk).
#Endpoint
https://openapi.disk.top/v1/files
#Method
GET
#Request Parameters
| Param | In | Required | Type | Description |
|---|---|---|---|---|
Authorization |
header | yes | string | Bearer {access_token} |
path |
query | no | string | Relative path, default /. Under files.app_data scope, / is the sandbox root |
page |
query | no | int | Page number, default 1 |
limit |
query | no | int | Per-page, default 50, max 200 |
#Example Request
curl -G "https://openapi.disk.top/v1/files" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
--data-urlencode "path=/" --data-urlencode "limit=20"
#Response Fields
| Field | Type | Description |
|---|---|---|
data.folders[].id |
int | Folder id |
data.folders[].name |
string | Folder name |
data.files[].id |
int | File id |
data.files[].name |
string | File name |
data.files[].size |
int | Bytes |
data.files[].md5 |
string | File md5 |
data.total |
int | Total entries at this path |
#Example Response
{
"errno":0,"errmsg":"ok",
"data":{
"path":"/","folders":[{"id":5911,"name":"GPTGet"}],
"files":[{"id":7280,"name":"chat-1.md","size":1024,"md5":"abc..."}],
"total":2
}
}
#Search Files
Search by name / extension within sandbox (or full disk with files.read_all).
#Endpoint
https://openapi.disk.top/v1/files/search
#Method
GET
#Request Parameters
| Param | In | Required | Type | Description |
|---|---|---|---|---|
Authorization |
header | yes | string | Bearer {access_token} |
q |
query | yes | string | Search keyword (matches origin_name) |
ext |
query | no | string | Extension filter (e.g. mp4) |
limit |
query | no | int | Max results, default 50 |
#Example Request
curl -G "https://openapi.disk.top/v1/files/search" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
--data-urlencode "q=chat"
#Example Response
{"errno":0,"data":{"files":[{"id":7280,"name":"chat-573.md","size":1024,"md5":"abc..."}],"total":1}}
#File Metadata
Get file details by id (path / md5 / size / upload time / mime).
#Endpoint
https://openapi.disk.top/v1/files/{id}
#Method
GET
#Request Parameters
| Param | In | Required | Description |
|---|---|---|---|
Authorization |
header | yes | Bearer |
id |
path | yes | File id |
#Example Response
{
"errno":0,
"data":{
"id":7280,"name":"chat-573.md","size":1024,
"md5":"abc...","ext":"md","mime":"text/markdown",
"path":"/My App Data/GPTGet/chat-573.md",
"parent_folder":5911,
"create_time":1779051234
}
}
#File Download
Get a signed download URL (valid 10 minutes, supports Range / resume).
#Endpoint
https://openapi.disk.top/v1/files/{id}/download
#Method
GET
#Request Parameters
| Param | In | Required | Description |
|---|---|---|---|
Authorization |
header | yes | Bearer |
id |
path | yes | File id |
#Response Fields
| Field | Type | Description |
|---|---|---|
data.url |
string | Temporary signed URL |
data.expires_in |
int | URL validity seconds (default 600) |
data.name, data.size, data.md5 |
- | File info |
#Example Response
{
"errno":0,
"data":{
"url":"https://dl.disk.top/abc/file.mp4?sig=...&exp=...",
"expires_in":600,
"name":"demo.mp4","size":8388608,"md5":"abc..."
}
}
#Video Streaming
For video files, returns HLS / DASH playlist URL for in-browser playback.
#Endpoint
https://openapi.disk.top/v1/files/{id}/stream
#Method
GET
#Example Response
{
"errno":0,
"data":{
"stream_url":"https://dl.disk.top/hls/abc/master.m3u8?sig=...",
"duration":1800,
"qualities":[{"name":"1080p","url":"..."}],
"expires_in":600
}
}
#Create Folder
Create a new folder under a parent path.
#Endpoint
https://openapi.disk.top/v1/files/folder
#Method
POST
#Request Parameters
| Param | In | Required | Description |
|---|---|---|---|
Authorization |
header | yes | Bearer, scope files.app_data or files.write_all |
parent_path |
body | no | Parent path, default / (sandbox root) |
name |
body | yes | New folder name |
#Example Request
curl -X POST "https://openapi.disk.top/v1/files/folder" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d "parent_path=/&name=Photos"
#Example Response
{"errno":0,"data":{"folder_id":5920,"name":"Photos","path":"/My App Data/GPTGet/Photos"}}
#Rename / Move / Copy / Delete
Batch operations (one request can affect multiple files / folders).
#Endpoint
https://openapi.disk.top/v1/files/manage
#Method
POST
#Request Parameters
| Param | In | Required | Description |
|---|---|---|---|
Authorization |
header | yes | Bearer, scope files.app_data / files.write_all |
action |
body | yes | rename / move / copy / delete |
file_ids |
body array | optional | File ids to operate on |
folder_ids |
body array | optional | Folder ids to operate on |
dest_path |
body | for move/copy | Destination parent path |
new_name |
body | for rename | New name |
#Example Requests
# Delete
curl -X POST "https://openapi.disk.top/v1/files/manage" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d "action=delete&file_ids[]=7280&file_ids[]=7281"
# Rename
curl -X POST "https://openapi.disk.top/v1/files/manage" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d "action=rename&file_ids[]=7280&new_name=updated.md"
#Example Response
{"errno":0,"data":{"affected":2}}
#Upload: precreate (dedup check + open upload session)
Step 1 of upload. Submit md5 + size; if dedup hits, returns file_id directly; otherwise returns upload_id and chunk parameters.
#Endpoint
https://openapi.disk.top/v1/files/upload/precreate
#Method
POST
#Request Parameters
| Param | In | Required | Description |
|---|---|---|---|
Authorization |
header | yes | Bearer, scope files.app_data / files.write_all |
parent_path |
body | no | Parent path, default / (sandbox root) |
name |
body | yes | File name |
size |
body | yes | Bytes |
md5 |
body | yes | Full-file md5 (lowercase 32-char hex) |
content_type |
body | no | MIME, default application/octet-stream |
#Example Request
curl -X POST "https://openapi.disk.top/v1/files/upload/precreate" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d "parent_path=/&name=movie.mp4&size=104857600&md5=5eb63bbbe01eeed093cb22bb8f5acdc3"
#Response Fields
| Field | Type | Description |
|---|---|---|
data.instant_upload |
bool | true = dedup hit, file_id returned directly; false = chunk upload |
data.file_id |
int | Returned on dedup hit |
data.upload_id |
string | Returned on non-dedup; client uses this id for chunk upload |
data.endpoint |
string | Chunk-upload service URL (e.g. https://openapi-upload.disk.top) |
data.chunk_size |
int | Bytes per chunk (client uses for slicing) |
data.total_parts |
int | Number of chunks to upload |
data.expires_in |
int | Upload session validity seconds (default 86400) |
#Example Response
{
"errno":0,
"data":{
"instant_upload":false,
"upload_id":"a747204b5517044b304fe07b649c6bdc",
"endpoint":"https://openapi-upload.disk.top",
"chunk_size":5242880,
"total_parts":20,
"expires_in":86400
}
}
Dedup hit:
{"errno":0,"data":{"instant_upload":true,"file_id":7266,"path":"/My App Data/GPTGet/movie.mp4","size":104857600}}
#Upload: chunk (upload a single chunk)
Slice by precreate's chunk_size, call this endpoint once per chunk (POST directly to endpoint).
#Endpoint
{endpoint}/u?upload_id={upload_id}&part_seq={N}
{endpoint} is from precreate response. {N} starts from 1.
#Method
POST
#Request Parameters
| Param | In | Required | Description |
|---|---|---|---|
upload_id |
query | yes | From precreate |
part_seq |
query | yes | Current chunk index (1-based) |
| body | raw | yes | Chunk bytes (Content-Type: application/octet-stream) |
#Example Request
# Chunk 1
dd if=movie.mp4 bs=5242880 count=1 skip=0 | \
curl -X POST "https://openapi-upload.disk.top/u?upload_id=a747...&part_seq=1" \
-H "Content-Type: application/octet-stream" --data-binary @-
# Repeat for N chunks
#Response Fields
| Field | Type | Description |
|---|---|---|
data.part_seq |
int | The chunk index received |
data.etag |
string | Chunk ETag (optional, may be empty for some backends) |
data.received_parts |
int | Cumulative chunks received |
data.total_parts |
int | Total expected |
#Example Response
{"errno":0,"data":{"part_seq":1,"etag":"abc123...","size":5242880,"received_parts":1,"total_parts":20}}
#Upload: query progress / received chunks (for resume)
Query which chunks have been received; client can skip them and resume.
#Endpoint
{endpoint}/u/{upload_id}/parts
#Method
GET
#Response Fields
| Field | Type | Description |
|---|---|---|
data.upload_id |
string | The upload_id |
data.total_parts |
int | Total expected |
data.received_parts |
int[] | List of received part_seq (ascending) |
data.progress |
float | Progress percent |
data.parts |
object | Detailed map: part_seq → {part_number, etag, size} |
#Example Response
{
"errno":0,
"data":{
"upload_id":"a747...",
"total_parts":20,
"received_parts":[1,2,3,5,6,7],
"progress":35.0,
"parts":{"1":{"part_number":1,"etag":"abc","size":5242880},"...":{}}
}
}
#Upload: complete (merge + finalize)
After all chunks are uploaded, call this endpoint. Server merges chunks and finalizes; returns file_id.
#Endpoint
{endpoint}/u/{upload_id}/complete
#Method
POST
#Response Fields
| Field | Type | Description |
|---|---|---|
data.file_id |
int | New file id |
data.path |
string | Full path |
data.size |
int | Bytes |
data.md5 |
string | File md5 |
#Example Response
{
"errno":0,
"data":{
"file_id":7280,
"path":"/My App Data/GPTGet/movie.mp4",
"size":104857600,
"md5":"5eb63bbbe01eeed093cb22bb8f5acdc3"
}
}
Errors:
425 incomplete: N/M— Some chunks missing; query/partsto find which ones to retry502 complete failed— Server-side error; retry or check status
#Upload: abort (cancel + cleanup)
Actively cancel the upload; server releases the chunk resources.
#Endpoint
{endpoint}/u/{upload_id}/abort
#Method
POST
#Example Response
{"errno":0,"data":{"ok":true}}