Get started
Quick Start
OAuth 2.0 flow in 4 steps — register, authorize, exchange, call.
My Applications
Create and manage your OAuth client credentials.
OAuth Scopes
Understand what each permission scope grants access to.
API Reference
Full endpoint reference for OAuth and file management.
MCP / AI Assistants
Connect Claude and other AI assistants to your storage. 20 tools for files, folders, search, and batch operations.
Base URLs
API https://patrins.com/api/
OAuth https://patrins.com/oauth/
MCP https://patrins.com/mcp
Loading applications…
Loading…
Loading…
Loading…
Add endpoint
1
Register your application
Go to My Applications and click New application. Enter your app name, redirect URIs, and the scopes you need. After saving, you'll receive a client_id and client_secret — the secret is shown only once.
2
Redirect users to authorization
Send users to this URL. They'll see a consent screen to approve your requested scopes.
http
GET https://patrins.com/oauth/authorize
  ?client_id=pclient_a1b2c3d4
  &redirect_uri=https://yourapp.com/callback
  &response_type=code
  &scope=profile:read files:read
  &state=random_csrf_token
  &code_challenge=BASE64URL(SHA256(code_verifier))
  &code_challenge_method=S256
After approval, Patrins redirects to your redirect_uri?code=...&state=.... Verify the state matches.
3
Exchange the code for tokens
POST to the token endpoint server-side with your code and PKCE verifier.
bash
curl -X POST https://patrins.com/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type":    "authorization_code",
    "code":          "<code_from_redirect>",
    "redirect_uri":  "https://yourapp.com/callback",
    "client_id":     "pclient_a1b2c3d4",
    "client_secret": "psecret_...",
    "code_verifier": "<your_pkce_verifier>"
  }'
response
{
  "access_token":  "pat_...",
  "refresh_token": "prt_...",
  "token_type":    "Bearer",
  "expires_in":    3600,
  "scope":         "profile:read files:read"
}
4
Make authenticated API calls
Pass the access token as a Bearer token in every request.
bash
# Get user profile
curl https://patrins.com/oauth/userinfo \
  -H "Authorization: Bearer pat_..."

# List files
curl https://patrins.com/api/files \
  -H "Authorization: Bearer pat_..."

# Refresh an expired token
curl -X POST https://patrins.com/oauth/token \
  -d '{"grant_type":"refresh_token","refresh_token":"prt_...","client_id":"pclient_..."}'
Scope Access What it allows Typical use case
profile:readReadUsername, email, plan, storage usageLogin with Patrins, identity verification
files:readReadList and download filesFile browsers, backups, media players
files:writeWriteRename and move files, toggle starredFile managers, sync clients
files:deleteDeleteMove files to trashCleanup tools, full-access managers
folders:readReadList and browse foldersFile browsers, navigators
folders:writeWriteCreate, rename, and move foldersFile managers, sync clients
folders:deleteDeleteMove folders and contents to trashCleanup tools, full-access managers
webdav:accessFullMount storage as a WebDAV driveDesktop apps, file system integrations
Scopes are space-separated: scope=profile:read files:read files:write
OAuth
GET /oauth/authorize Authorization endpoint — redirect users here
Auth: None (public)
ParameterTypeRequiredDescription
client_idstringrequiredYour registered client ID
redirect_uristringrequiredMust match a registered redirect URI
response_typestringrequiredMust be code
scopestringSpace-separated list of scopes
statestringCSRF protection — reflected back on redirect
code_challengestringPKCE: BASE64URL(SHA256(code_verifier))
code_challenge_methodstringMust be S256
POST /oauth/token Exchange code or refresh tokens
Auth: client_id + client_secret
Body: application/json
ParameterTypeRequiredDescription
grant_typestringrequiredauthorization_code | refresh_token | client_credentials
codestringRequired for authorization_code grant
refresh_tokenstringRequired for refresh_token grant
code_verifierstringPKCE verifier (if challenge was sent)
redirect_uristringMust match original authorization request
POST /oauth/revoke Revoke an access or refresh token
Auth: client_id + client_secret
ParameterTypeRequiredDescription
tokenstringrequiredThe pat_ or prt_ token to revoke
Always returns 200 per RFC 7009.
GET /oauth/userinfo Get authenticated user profile
Auth: Bearer pat_token
Scope: profile:read
response
{ "id": 42, "username": "alice", "email": "[email protected]", "plan": "pro" }
Files
GET /api/files List files for the authenticated user
Auth: Bearer pat_token
Scope: files:read
QueryTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page, max 100 (default: 50)
POST /api/tus Upload a file (tus resumable protocol)
Auth: Bearer pat_token or api_key
Scope: files:write
Protocol: tus 1.0
Patrins uses the tus resumable upload protocol. Use any tus 1.0 client — uploads can be paused and resumed, and support files of any size up to 1 TB.
Metadata keyTypeRequiredDescription
filenamestringrequiredOriginal filename with extension
filetypestringrequiredMIME type e.g. video/mp4
folderIdstringTarget folder ID — omit for root
isTempstringPass "true" for a temporary file (expires in 7 days, bypasses storage quota)
example — tus-js-client
import * as tus from 'tus-js-client';

const upload = new tus.Upload(file, {
  endpoint: 'https://patrins.com/api/tus',
  retryDelays: [0, 3000, 5000],
  headers: { Authorization: `Bearer ${apiKey}` },
  metadata: {
    filename: file.name,
    filetype: file.type,
    isTemp: 'false',   // 'true' for temp upload
  },
  onSuccess() { /* done */ },
});
upload.start();
POST /api/tus Upload a temporary file (expires in 7 days, no storage quota)
Auth: Bearer pat_token or api_key
Protocol: tus 1.0
Same as a regular upload but with isTemp: 'true' in metadata. Temp files expire after 7 days and bypass your plan storage quota (capped at 1.2 TB of active temp files per account). The file URL is shareable immediately — no account required to download.
example — tus-js-client
import * as tus from 'tus-js-client';

const upload = new tus.Upload(file, {
  endpoint: 'https://patrins.com/api/tus',
  retryDelays: [0, 3000, 5000],
  headers: { Authorization: `Bearer ${apiKey}` },
  metadata: {
    filename: file.name,
    filetype: file.type,
    isTemp: 'true',   // expires in 7 days
  },
  onSuccess() { /* done */ },
});
upload.start();
DELETE /api/files/:id Permanently delete a file (irreversible — use /trash for soft delete)
Auth: Bearer pat_token
Scope: files:delete
User
GET /api/auth/me Get current user profile and plan info
Auth: Bearer pat_token or api_key
Scope: profile:read
response
{
  "user": {
    "id": "6b1fed95-7f78-...",
    "email": "[email protected]",
    "username": "alice",
    "display_name": "Alice",
    "plan": "pro",
    "storage_used": 5368709120,
    "storage_limit": 107374182400,
    "plan_expires_at": null,
    "avatar": "https://..."
  }
}
Upload
POST /api/upload-direct/init Step 1 — initialize an upload session
Auth: Bearer api_key
Body: application/json
FieldTypeRequiredDescription
fileNamestringrequiredOriginal filename with extension
fileSizenumberrequiredFile size in bytes
mimeTypestringrequiredMIME type e.g. application/pdf
folderIdstringTarget folder ID — omit for root
response
{ "uploadId": "abc123", "uploadUrl": "/api/webdav-upload/abc123/file.pdf" }
PUT {uploadUrl} Step 2 — stream raw file bytes
Auth: Bearer api_key
Body: application/octet-stream
Use the full uploadUrl returned by init. Stream the raw file bytes as the request body.
POST /api/upload-finalize Step 3 — finalize and save the file
Auth: Bearer api_key
Body: application/json
FieldTypeRequiredDescription
uploadIdstringrequiredThe uploadId from the init step
response
{ "success": true, "file": { "id": "6b8b413bf05f", "name": "example.pdf", "size": 1024 } }
POST /api/remote-upload Upload a file from a remote URL
Auth: Bearer api_key
Body: application/json
FieldTypeRequiredDescription
urlstringrequiredRemote file URL to download
fileNamestringOverride the filename
folderIdstringTarget folder
response
{ "uploadId": "550e8400-...", "status": "starting" }
Poll GET /api/remote-upload/{uploadId}/status to track progress. Status values: queued | starting | downloading | storing | complete | error. Max 4 concurrent remote uploads server-wide.
File Operations
PATCH /api/files/:id/rename Rename a file
Auth: Bearer api_key
Scope: files:write
FieldTypeRequiredDescription
namestringrequiredNew filename (with extension)
PATCH /api/files/:id/move Move a file to a folder
Auth: Bearer api_key
Scope: files:write
FieldTypeRequiredDescription
folderIdstringDestination folder ID — pass null to move to root
POST /api/files/:id/trash Move a file to trash (soft delete)
Auth: Bearer api_key
Scope: files:delete
Recoverable via the Trash API. Use DELETE /api/files/:id for permanent deletion.
POST /api/files/:id/star Toggle star on a file
Auth: Bearer api_key
Scope: files:write
response
{ "success": true, "starred": true }
GET /api/starred Get all starred files and folders
Auth: Bearer api_key
Scope: files:read
response
{ "folders": [...], "files": [...] }
Folders
POST /api/folders Create a folder or subfolder
Auth: Bearer api_key
Scope: folders:write
FieldTypeRequiredDescription
namestringrequiredFolder name
parentIdstringParent folder ID — omit for root. No depth limit.
GET /api/folders List folders
Auth: Bearer api_key
Scope: folders:read
QueryTypeDescription
parentIdstringOmit for root folders; pass a folder ID for its children
GET /api/folders/:id Get folder details + breadcrumb path
Auth: Bearer api_key
Scope: folders:read
response
{ "folder": { ... }, "breadcrumbs": [{ "id": "...", "name": "..." }] }
GET /api/files/folder/:id List files inside a folder
Auth: Bearer api_key
Scope: files:read
Omit :id to list files at root (GET /api/files/folder).
PATCH /api/folders/:id Rename a folder
Auth: Bearer api_key
Scope: folders:write
FieldTypeRequiredDescription
namestringrequiredNew folder name
PATCH /api/folders/:id/move Move a folder to a different parent
Auth: Bearer api_key
Scope: folders:write
FieldTypeRequiredDescription
parentIdstringrequiredNew parent folder ID — pass null to move to root
POST /api/folders/:id/trash Trash a folder and its contents
Auth: Bearer api_key
Scope: folders:delete
Recursively moves the folder and all nested files/subfolders to trash. Recoverable via Trash API.
DELETE /api/folders/:id Permanently delete a folder and all contents
Auth: Bearer api_key
Scope: folders:delete
Irreversible. Deletes the folder and every file inside it permanently.
Folder Shares
POST /api/folders/:id/share Create a public share link for a folder
Auth: Bearer api_key
FieldTypeDescription
expiresInnumberSeconds until expiry — omit for permanent link
allowDownloadbooleanDefault true — set false for browse-only
passwordstringOptional password protection
response
{ "success": true, "share": { "url": "https://patrins.com/s/{token}", "token": "...", "expiresAt": null } }
GET /api/shared/:token/contents Browse a shared folder (no auth needed)
Auth: None (public)
QueryTypeDescription
folderIdstringNavigate into a subfolder within the share
response
{ "folders": [...], "files": [...], "breadcrumb": [...] }
Bulk Operations
POST /api/move-items Move multiple files and folders at once
Auth: Bearer api_key
Body: application/json
FieldTypeRequiredDescription
itemsarrayrequiredArray of { id, type: "file"|"folder" }
targetFolderIdstringDestination folder ID — null for root
Atomic — all items move in a single transaction. If any fail, the whole operation rolls back.
POST /api/download/bulk Download multiple files as a ZIP archive
Auth: Bearer api_key
Body: application/json
FieldTypeRequiredDescription
fileIdsstring[]requiredArray of file IDs to include in the ZIP
Response streams application/zip directly. Rate limit: 10/hour per user.
Trash
GET /api/trash List all trashed files
Auth: Bearer api_key
Scope: files:read
POST /api/trash/:id/restore Restore a file from trash
Auth: Bearer api_key
Scope: files:write
DELETE /api/trash/:id Permanently delete one trashed file
Auth: Bearer api_key
Scope: files:delete
DELETE /api/trash Empty trash — permanently delete everything
Auth: Bearer api_key
Scope: files:delete
Irreversible. Deletes all trashed files permanently.
Search
GET /api/search Search files and folders by name
Auth: Bearer api_key
Scope: files:read
QueryTypeDescription
qstring requiredSearch term matched against filename
sectionstringContext: starred | trash | temp — omit for normal files
response
{ "files": [...], "folders": [...] }  // max 50 results each
Rate limit: 60/min per user.
Access Token
pat_ prefix
Lifetime
1 hour
Usage
Pass in Authorization: Bearer header on every API call
Storage
SHA-256 hash stored server-side. Raw token shown once at issuance.
Revocation
POST /oauth/revoke or wait for expiry
Format
pat_ + 64 hex characters
Refresh Token
prt_ prefix
Lifetime
30 days
Usage
Exchange for a new access token via refresh_token grant. Never send to API endpoints.
Storage
Treat as a password. Store server-side only, never in localStorage.
Revocation
POST /oauth/revoke — also invalidates the paired access token
Format
prt_ + 64 hex characters
PKCE — Proof Key for Code Exchange
PKCE prevents authorization code interception attacks for public clients (SPAs, native apps). Generate a random code_verifier, hash it to produce the code_challenge, and send the challenge with the authorization request. Include the raw verifier during token exchange.
javascript
// 1. Generate code_verifier
const array = crypto.getRandomValues(new Uint8Array(32));
const verifier = btoa(String.fromCharCode(...array))
  .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');

// 2. Hash to produce code_challenge (S256)
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
const challenge = btoa(String.fromCharCode(...new Uint8Array(hash)))
  .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
What is MCP?
The Model Context Protocol (MCP) lets AI assistants like Claude connect to external services and call tools on your behalf. Patrins exposes an MCP server at https://patrins.com/mcp — once connected, the AI can list, search, move, and organize your files using natural language.
Access is always gated by OAuth. The AI only sees tools for scopes you explicitly approve — it cannot do anything you have not permitted.
Connecting Claude
In Claude, go to Settings → Integrations → Add Integration and paste the MCP URL. Claude auto-discovers the OAuth endpoints via the RFC 8414 discovery document, prompts you to sign in, and shows a consent screen to approve scopes.
url
https://patrins.com/mcp
Recommended scopes to request: profile:read files:read files:write files:delete folders:read folders:write folders:delete
OAuth Discovery
MCP clients that support RFC 8414 discovery will auto-configure using this endpoint.
bash
curl https://patrins.com/.well-known/oauth-authorization-server
response
{
  "issuer":                   "https://patrins.com",
  "authorization_endpoint":   "https://patrins.com/authorize",
  "token_endpoint":           "https://patrins.com/token",
  "grant_types_supported":    ["authorization_code", "refresh_token"],
  "code_challenge_methods_supported": ["S256"],
  "scopes_supported": [
    "profile:read", "files:read", "files:write",
    "files:delete", "folders:read", "folders:write",
    "folders:delete", "webdav:access"
  ]
}
Transport
The MCP server uses Streamable HTTP (JSON-RPC 2.0). Authenticate with a Bearer token obtained via OAuth.
bash
# List available tools
curl -X POST https://patrins.com/mcp   -H "Authorization: Bearer pat_..."   -H "Content-Type: application/json"   -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

# Call a tool
curl -X POST https://patrins.com/mcp   -H "Authorization: Bearer pat_..."   -H "Content-Type: application/json"   -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_files","arguments":{"limit":10}}}'
Available Tools
20 tools across 6 scope groups. The AI only sees tools for scopes it was granted.
Profile — profile:read
ToolDescription
get_user_infoUsername, email, plan
get_storage_infoBytes used / limit / %, total file count
Files — files:read
ToolDescriptionParameters
list_filesList files, filter by folder or starredfolder_id, limit, offset, starred
get_file_infoFull details + public download URLfile_id required
search_filesSearch by filename, optional MIME filter, paginatedquery required, folder_id, mime_type, limit, offset
Files — files:write
ToolDescriptionParameters
rename_fileRename a filefile_id, new_name
move_fileMove to a folder or rootfile_id, folder_id
star_fileStar or unstar a filefile_id, starred
batch_move_filesMove up to 200 files in one callfile_ids[] required, folder_id
Files — files:delete
ToolDescriptionParameters
delete_fileMove a file to trash (soft delete)file_id required
batch_delete_filesTrash up to 200 files in one callfile_ids[] required
Folders — folders:read
ToolDescriptionParameters
list_foldersList child folders of a parentparent_id, starred
get_folder_infoDetails, file count, subfolder count, sizefolder_id required
get_folder_treeNested tree up to 6 levels deep with file countsparent_id, depth (default 3, max 6)
Folders — folders:write
ToolDescriptionParameters
create_folderCreate a new foldername required, parent_id
rename_folderRename a folderfolder_id, new_name
move_folderMove to a new parent or top-levelfolder_id, new_parent_id
star_folderStar or unstar a folderfolder_id, starred
batch_move_foldersMove up to 50 folders in one callfolder_ids[] required, new_parent_id
Folders — folders:delete
ToolDescriptionParameters
delete_folderMove folder and all contents to trash (recursive)folder_id required
How it works
Create a widget below, copy its embed snippet, paste into any webpage. Visitors upload files — they land in your drive.
html
<!-- Drop anywhere on your site -->
<div data-patrins-widget></div>
<script src="https://patrins.com/widget.js" data-widget="YOUR_WIDGET_ID"></script>

<!-- Or floating button (no div needed) -->
<script src="https://patrins.com/widget.js" data-widget="YOUR_WIDGET_ID"></script>
Loading widgets…
New Widget
Leave empty to allow all domains. Recommended: set this to prevent misuse.
Leave empty to allow all types.
Visitors must enter this before uploading.
We'll POST a JSON payload to this URL on every upload.
Your Template
Upload Template

Upload an HTML file to use as your custom download page. All visitors who open your /f/ links will see your page instead of the default Patrins one.

Drop your HTML file here
or click to browse — max 100 KB
Available Variables

These placeholders are automatically replaced with actual file data when a visitor opens your /f/ link.

File Information
VariableDescriptionExample
{{FILE_NAME}}Original filenamevideo.mp4
{{FILE_SIZE}}Human-readable size157.3 MB
{{FILE_SIZE_BYTES}}Raw size in bytes164956160
{{FILE_TYPE}}MIME typevideo/mp4
{{FILE_ID}}Unique file identifiera3b4c5d6e7f8
{{DOWNLOAD_URL}}Direct download linkhttps://patrins.com/api/download/…
{{UPLOAD_DATE}}Upload dateMay 14, 2026
{{DOWNLOAD_COUNT}}Number of downloads42
{{EXPIRES_AT}}Expiry date or "Never"Never
{{IS_ENCRYPTED}}Client-side encryptionNo
{{SHA256}}SHA-256 hasha3b4c5d6…
Uploader & Branding
VariableDescriptionExample
{{UPLOADER_NAME}}Display nameVeel Studios
{{UPLOADER_USERNAME}}Patrins usernameveelstudios
{{SOCIAL_INSTAGRAM}}Instagram handle (no @)veelstudios
{{SOCIAL_TWITTER}}Twitter/X handleveelstudios
{{SOCIAL_DISCORD}}Discord invite codeabc123
{{SOCIAL_TIKTOK}}TikTok handleveelstudios
{{SOCIAL_YOUTUBE}}YouTube channel handleveelstudios
{{SOCIAL_WEBSITE}}Website URLhttps://veelstudios.com
{{SOCIAL_GITHUB}}GitHub usernameveelstudios
Rules & Limits
HTML only — must be a valid .html file
Maximum size: 100 KB — inline CSS and SVG are fine
No JavaScript<script> tags and on* event attributes are automatically stripped on upload
No external resources — external src= attributes are stripped. Embed images as base64 or use CSS-only styling
Sample Template

Copy this as a starting point. Variables in {{…}} are filled automatically.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{FILE_NAME}} — {{UPLOADER_NAME}}</title>
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: system-ui, sans-serif; background: #0f0f0e; color: #e8e6e1; min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; }
    .card { background: #1a1a18; border: 1px solid #2a2a27; border-radius: 16px; padding: 32px; max-width: 480px; width: 100%; }
    .file-name { font-size: 20px; font-weight: 600; margin-bottom: 6px; word-break: break-word; }
    .meta { font-size: 13px; color: #8a8880; margin-bottom: 24px; }
    .download-btn { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; padding: 14px; background: #e8e6e1; color: #111110; border-radius: 10px; text-decoration: none; font-weight: 600; font-size: 15px; }
    .stats { display: flex; gap: 20px; margin-top: 20px; padding-top: 20px; border-top: 1px solid #2a2a27; }
    .stat { flex: 1; }
    .stat-value { font-size: 18px; font-weight: 600; }
    .stat-label { font-size: 11px; color: #8a8880; text-transform: uppercase; letter-spacing: .05em; }
    .uploader { margin-top: 20px; padding-top: 20px; border-top: 1px solid #2a2a27; font-size: 13px; color: #8a8880; }
  </style>
</head>
<body>
  <div class="card">
    <div class="file-name">{{FILE_NAME}}</div>
    <div class="meta">{{FILE_TYPE}} &middot; {{FILE_SIZE}}</div>
    <a href="{{DOWNLOAD_URL}}" class="download-btn">Download</a>
    <div class="stats">
      <div class="stat">
        <div class="stat-value">{{DOWNLOAD_COUNT}}</div>
        <div class="stat-label">Downloads</div>
      </div>
      <div class="stat">
        <div class="stat-value">{{EXPIRES_AT}}</div>
        <div class="stat-label">Expires</div>
      </div>
    </div>
    <div class="uploader">Shared by <strong style="color:#e8e6e1">{{UPLOADER_NAME}}</strong></div>
  </div>
</body>
</html>
How it works

When a visitor opens a link like https://files.yourbrand.com/f/abc123, Patrins detects your domain, finds your account, and serves your custom download page — or the default Patrins one if you haven't set one up.

1
Add your domain in Dashboard Settings
Go to Dashboard → Settings → Profile and enter your domain under Custom Domain.
2
Add an A record
At your DNS provider (Cloudflare, Namecheap, GoDaddy, etc.), add an A record pointing directly to the Patrins server:
DNS
Type  Name                    Value
A     files                   159.69.64.77
Important: use an A record, not a CNAME. A CNAME pointing to patrins.com routes through Cloudflare and will fail DNS verification. If you use Cloudflare DNS, set the record to DNS only (grey cloud icon, not orange).
DNS propagation typically takes a few minutes but can take up to 24 hours.
3
Click "Check DNS & Activate"
Once DNS is propagated, click the verify button in Settings. Patrins will automatically issue an SSL certificate via Let's Encrypt and activate your domain. This takes about 30 seconds.
4
Your domain is live
All your /f/ links now work on your custom domain. Share files.yourbrand.com/f/abc123 instead of patrins.com/f/abc123.
What it serves

Only /f/ download pages are served on your custom domain — and only files belonging to your account. Your Patrins dashboard and other users' files are not accessible through your domain.

files.yourbrand.com/f/abc123 — serves the download page for your file
Uses your Custom HTML template if you have one set up
Files from other Patrins users return 404 on your domain
The Patrins dashboard is not accessible through your domain
SSL & Security

Patrins automatically provisions and renews a free Let's Encrypt SSL certificate for your domain. HTTPS is enforced — HTTP requests redirect to HTTPS automatically.

If you remove your custom domain, the certificate is revoked and the domain stops serving Patrins content immediately.

Limits
1 custom domain per account
Unlimited plan only
Wildcard domains (*.yourdomain.com) are not supported
IP addresses are not supported as custom domains
Install
macOS / Linux
sh
curl -fsSL https://patrins.com/install.sh | sh
Windows (PowerShell)
powershell
irm https://patrins.com/install.ps1 | iex
Requires Node.js 18+. No extra npm dependencies.
Authentication
sh
# Browser-based login — opens patrins.com and saves your API key
patrins login

# Or supply an API key directly (Dashboard → Settings → API Keys)
patrins login --key patrins_abc123
Config is stored in ~/.patrins/config.json. Run patrins logout to clear it.
Uploading
sh
# Upload one or more files
patrins upload video.mp4
patrins upload *.mp4

# Temporary file (expires in 7 days)
patrins upload report.pdf --temp

# Upload from stdin
cat file.bin | patrins upload -

# Remote transfer — download a URL directly to your Patrins drive
patrins remote https://example.com/file.zip
Uploads use chunked multipart (15 MB chunks, 4 concurrent) so any file size works.
Commands
CommandAliasesWhat it does
upload <file>upUpload one or more files. Pass - for stdin. Flags: --temp
lslistList your files. Flags: --starred --temp --json --limit N
search <query>findSearch files by name
info <id|url>statFull details for a file
share <id|url>Print the public file URL
url <id|url>Copy URL to clipboard
open <id|url>Open file page in browser
rename <id> <name>mvRename a file
star <id>Toggle starred on a file
rm <id>delete, trashMove a file to trash
remote <url>Remote-transfer a URL to your drive with live progress
whoamiShow logged-in user and storage
loginAuthenticate (browser or --key)
logoutClear saved credentials
help [command]General help or per-command usage
All ID arguments also accept full patrins.com/f/… URLs — the CLI extracts the ID automatically.
Getting started
1
Open the bot
Search @patrins_bot on Telegram or go to t.me/patrins_bot and tap Start.
2
Link your account
Go to Dashboard → Settings → Integrations → Connect Telegram. Copy the one-time code and send it to the bot:
telegram
/link YOUR_CODE
3
Start using it
Send any file to upload it instantly. Send a URL to remote-transfer it. Use commands to browse and manage your drive.
Commands
CommandWhat it does
Account
/link CODEConnect your Patrins account
/unlinkDisconnect this Telegram from your account
/meProfile, plan, and storage usage
/settingsToggle storage warnings
Browse
/files [page]Paginated file list with inline star / delete buttons
/starredStarred files
/search querySearch by filename
/tempTemporary files with expiry dates
/trashTrashed files
/foldersYour folders (tap to browse contents)
/statsBreakdown by type: videos, images, audio, PDFs + download count
/storageStorage bar with used / free / total
File actions
/info IDFull file details
/share IDGet public file link
/download IDReceive the file back in Telegram (≤ 50 MB)
/rename ID nameRename a file
/star IDToggle starred
/move ID folder_idMove to a folder
/delete IDMove to trash (with confirmation)
/restore IDRestore from trash
/empty_trashPermanently delete all trash
Upload links
/linksYour upload links
/newlink nameCreate an upload link
Uploads
Just send any file to the bot — no command needed. It lands directly in your drive.
File sizeHow it works
≤ 50 MBUploaded instantly via Bot API — fastest path
> 50 MB (up to 4 GB)Downloaded via MTProto and streamed to your drive. Shows a live progress bar with transfer speed and ETA.
Per-user queue If you send multiple files at once, they are queued and processed one at a time. The bot tells you how many transfers are ahead when it queues yours.
Cancel button A ❌ Cancel inline button appears on the progress message during any upload. Tapping it stops the transfer immediately, even mid-download.
Inline search
Type @patrins_bot in any Telegram chat to search your files inline and share a link without leaving the conversation.
telegram — any chat
@patrins_bot video.mp4
Enable via BotFather /setinline. Results show file name, size, upload date, and download count.
Notifications
The bot sends you a message when your storage hits 80% or 95% after an upload.
Mute with /settings.
New Application
PNG, JPG, WebP · max 2 MB · Recommended 256×256
One URI per line.