Warpbin API
Programmatic access to upload, retrieve, and manage files on Warpbin galleries.
drive_ prefix (e.g. drive_id, drive_url) for backwards compatibility. They refer to your gallery throughout this API.Base URL
All API requests use this base URL. Append the endpoint path to make your calls.
https://warpbin.com/api/v1
How to Use This API
Get an API Key
Reach out to contact@warpbin.com to request your API key. Keys are tied to your account and start with wb_live_.
Find your gallery identifiers
If you already have a gallery, you can find its identifiers in the URLs you already have:
drive_idthe unique identifier for your galleryadmin_idthe admin password for your gallery (only needed for certain operations)Create galleries programmatically
ProIf you have an active Pro subscription on the email associated with your API key, you can use the /createGallery endpoint to create new galleries via the API. The response includes the drive_id and admin_id for immediate use.
Authentication
Include your API key in every request using one of the following headers. You only need to pick one — they are interchangeable.
Pick one header
X-API-KeystringYour Warpbin API key as-is — wb_live_xxx
AuthorizationstringBearer token format — Bearer wb_live_xxx
Error responses
Missing API key
{
"error": "API key required",
"type": "MISSING_API_KEY"
}Invalid API key
{
"error": "Invalid API key",
"type": "INVALID_API_KEY"
}Code example
import requestsheaders = {'X-API-Key': 'wb_live_xxxxxxxxxxxx'}# Or use Bearer tokenheaders = {'Authorization': 'Bearer wb_live_xxxxxxxxxxxx'}
Upload File
/v1/uploadFileUpload a file to a gallery and get instant access URLs. Files are processed asynchronously after upload. The returned URLs will not display the uploaded photo or video until the file is done processing. This can take a couple seconds to minutes depending on the file size.
Form data parameters
file_contentsfilerequiredThe file to upload
filenamestringrequiredFilename including extension
drive_idstringrequiredTarget gallery identifier
consent_givenbooleanUser consent for processing (default: false)
user_idstringUser identifier for tracking
admin_idstringThe gallery's admin password. Required when public uploads are disabled on the gallery.
Response fields
filenameFinal filename after sanitizationfile_preview_urlURL to view the file (no API key required)file_download_urlDirect download URL (requires API key)Errors
Missing required fields
{
"error": "Missing required field: drive_id",
"type": "MISSING_FIELD"
}Invalid gallery ID
{
"error": "Invalid gallery ID",
"type": "INVALID_DRIVE_ID"
}Storage limit exceeded
{
"error": "Uploading this file would exceed the gallery's storage limit.",
"type": "STORAGE_SPACE"
}Code example
import requestswith open('photo.jpg', 'rb') as f:response = requests.post('https://warpbin.com/api/v1/uploadFile',headers={'X-API-Key': 'wb_live_xxxxxxxxxxxx'},files={'file_contents': f},data={'filename': 'photo.jpg','drive_id': 'abc123xyz'})result = response.json()print(result['file_preview_url'])
{"message": "File upload accepted for processing.","filename": "photo_2.jpg","file_preview_url": "https://warpbin.com/file?id=abc123xyz&file=photo_2.jpg","file_download_url": "https://warpbin.com/api/v1/getFile?id=abc123xyz&file=photo_2.jpg"}
Resumable Upload (TUS)
/v1/tus/v1/tus/{upload_id}/v1/tus/{upload_id}/v1/tus/{upload_id}Upload large files in chunks with per-byte resume, using the open TUS 1.0 protocol (extensions: creation, termination). Prefer this over /v1/uploadFile for videos and other large files, or on unreliable networks. Any standard TUS client library works — point it at the endpoint, add your API key header, and set the metadata below.
POST creates a session and returns its URL in the Location header. Send data with sequential PATCH requests. After an interruption, HEAD returns the confirmed Upload-Offset to resume from. The upload completes implicitly when the offset reaches Upload-Length; use DELETE to abandon a session you will not finish.HEAD returns 200 with Upload-Offset equal to Upload-Length and an Upload-Metadata header carrying the filename the file was stored under; replaying the last PATCH returns 204 without writing anything, and DELETE is a no-op. Standard TUS clients already treat offset == length as success, so a lost response never causes a re-upload or a duplicate. Only sessions that were never finished go away: expired ones answer 410, unknown ones 404 — restart those from byte 0 with a new POST.Upload-Metadata fields
Sent on the create request as the standard TUS Upload-Metadata header (comma-separated key base64(value) pairs — TUS client libraries encode this for you).
drive_idstringrequiredTarget gallery identifier
filenamestringrequiredFilename including extension. If the name already exists in the gallery, the stored name is made unique on completion (e.g. video_2.mp4), so prefer unique filenames to look files up afterwards.
session_idstringrequiredClient-generated identifier (e.g. a UUID) grouping uploads from one client session
consent_givenbooleanUser consent for processing (default: false)
user_idstringUser identifier for tracking
album_idstringAlbum to place the file in
admin_idstringThe gallery's admin password. Required when public uploads are disabled on the gallery.
Limits and session lifetime
Max file size50 GB, advertised via Tus-Max-Size on OPTIONS /v1/tusChunk sizeAny size per PATCH (empty chunks rejected). 1–10 MiB is a good default; use smaller chunks on unreliable networks.Session retentionUnfinished sessions live up to 24 hours and may be cleaned up earlier when the server is under storage pressure. A finished upload stays addressable at its session URL for as long as the file exists in the gallery.Lost sessionsUnfinished sessions do not survive server restarts or deploys. If HEAD on a known session returns 404 or 410, nothing was committed — restart that file with a new POST from byte 0./v1/uploadFile. The final PATCH returns 204 with no body — poll /v1/fileInfo with your drive_id and filename to get the preview and download URLs once processing finishes. The session itself stays addressable: HEAD reports Upload-Offset equal to Upload-Length and a retried final PATCH returns 204 without writing anything — never a duplicate.Errors
Missing required metadata
{
"error": "Missing required field: session_id",
"type": "MISSING_FIELD"
}Unknown session, or an unfinished one that was lost — restart the file with a new POST
{
"error": "Upload not found"
}Offset mismatch — resync with HEAD, then resume from server_offset (on a finished upload the body also carries completed: true and the stored filename)
{
"error": "Offset mismatch - client and server out of sync",
"type": "OFFSET_MISMATCH",
"server_offset": 106954752,
"client_offset": 107003904
}Session expired — restart the file with a new POST
{
"error": "Upload has expired"
}File exceeds maximum size
{
"error": "File size exceeds maximum allowed size",
"type": "FILE_TOO_LARGE",
"max_size": 53687091200
}Upload not allowed (gallery expired, uploads disabled, or plan limit) — do not retry
{
"error": "Upload not allowed",
"type": "PLAN_LIMIT_EXCEEDED"
}Server storage temporarily critical — back off and retry later
{
"error": "Server storage critical. Uploads temporarily disabled to prevent system crash.",
"type": "DISK_SPACE_CRITICAL"
}Code example
# pip install tuspyimport uuidfrom tusclient import clienttus_client = client.TusClient('https://warpbin.com/api/v1/tus',headers={'X-API-Key': 'wb_live_xxxxxxxxxxxx'},)uploader = tus_client.uploader('video.mp4',chunk_size=5 * 1024 * 1024,metadata={'drive_id': 'abc123xyz','filename': 'video.mp4','session_id': str(uuid.uuid4()),},)# Sends chunks and transparently resumes from the# server-confirmed offset after an interruptionuploader.upload()
# POST /v1/tus — session createdHTTP/1.1 201 CreatedTus-Resumable: 1.0.0Location: /api/v1/tus/3f2a9c1e-...# PATCH /v1/tus/{upload_id} — chunk acceptedHTTP/1.1 204 No ContentTus-Resumable: 1.0.0Upload-Offset: 5242880# HEAD /v1/tus/{upload_id} — where to resumeHTTP/1.1 200 OKTus-Resumable: 1.0.0Upload-Offset: 106954752Upload-Length: 296201395# HEAD /v1/tus/{upload_id} — upload already finished# (Upload-Metadata carries the stored filename, here "video_2.mp4")HTTP/1.1 200 OKTus-Resumable: 1.0.0Upload-Offset: 296201395Upload-Length: 296201395Upload-Metadata: filename dmlkZW9fMi5tcDQ=
Retrieve File
/v1/getFile?id={drive_id}&file={filename}Download a file from a gallery. Returns the raw file data with appropriate content-type headers for direct download or display.
id is your drive_id and file is the filename.Query parameters
idstringrequiredYour drive_id — the gallery to retrieve from
filestringrequiredThe filename to retrieve (same as filename in other endpoints)
Errors
Missing drive ID
{
"error": "Missing 'id' parameter",
"type": "MISSING_PARAMETER"
}Invalid gallery ID
{
"error": "Invalid gallery ID",
"type": "INVALID_DRIVE_ID"
}Missing filename
{
"error": "Missing 'file' parameter",
"type": "MISSING_PARAMETER"
}Invalid filename
{
"error": "Invalid filename format",
"type": "INVALID_FILENAME"
}Access denied
{
"error": "File not found or access denied",
"type": "ACCESS_DENIED"
}File not found
{
"error": "File not found in storage",
"type": "NOT_FOUND"
}Code example
import requestsresponse = requests.get('https://warpbin.com/api/v1/getFile',headers={'X-API-Key': 'wb_live_xxxxxxxxxxxx'},params={'id': 'abc123xyz', 'file': 'photo.jpg'})with open('photo.jpg', 'wb') as f:f.write(response.content)
Response
Returns raw file data with appropriate Content-Type headers.
File Info
/v1/fileInfo?drive_id={drive_id}&filename={filename}Get the preview and download URLs for a file without downloading its content.
Query parameters
drive_idstringrequiredGallery identifier
filenamestringrequiredFilename to look up
Response fields
filenameFilename as stored on the galleryfile_preview_urlURL to view in Warpbin (no API key required)file_download_urlDirect download URL (requires API key)Errors
Missing parameters
{
"error": "Missing 'drive_id' parameter",
"type": "MISSING_PARAMETER"
}Invalid gallery ID
{
"error": "Invalid gallery ID",
"type": "INVALID_DRIVE_ID"
}Missing filename
{
"error": "Missing 'filename' parameter",
"type": "MISSING_PARAMETER"
}File not found
{
"error": "File not found",
"type": "NOT_FOUND"
}Code example
import requestsresponse = requests.get('https://warpbin.com/api/v1/fileInfo',headers={'X-API-Key': 'wb_live_xxxxxxxxxxxx'},params={'drive_id': 'abc123xyz', 'filename': 'photo.jpg'})info = response.json()print(info['file_preview_url'])
{"filename": "photo.jpg","file_preview_url": "https://warpbin.com/file?id=abc123xyz&file=photo.jpg","file_download_url": "https://warpbin.com/api/v1/getFile?id=abc123xyz&file=photo.jpg"}
Create Gallery
/v1/createGalleryCreate a new Warpbin gallery linked to your account. Returns the gallery credentials and URL for immediate use.
/v1/createDrive continues to work and is fully equivalent — both names hit the same handler.Request body
alt_tenant_urlstringCustom gallery URL slug that helps you identify it in your dashboard (e.g. "brazil-trip")
Response fields
drive_idUnique drive identifier for API callsadmin_idAdmin password for drive management (the pd value in your manage URL)drive_urlPublic URL to access the drivemanage_urlManagement panel URL for drive settingsdrive_id and admin_id (admin password) are returned at creation time — save them for future API calls. You can also find them later in your manage URL (/manage/{drive_id}?pd={admin_id}) or view all your galleries on your dashboard.Errors
No active subscription
{
"success": false,
"drive_id": null,
"admin_id": null,
"drive_url": null,
"manage_url": null,
"message": "Active Pro subscription required"
}Server error
{
"success": false,
"drive_id": null,
"admin_id": null,
"drive_url": null,
"manage_url": null,
"message": "Failed to create gallery"
}Code example
import requestsresponse = requests.post('https://warpbin.com/api/v1/createGallery',headers={'X-API-Key': 'wb_live_xxxxxxxxxxxx'},json={'alt_tenant_url': 'my-project'})gallery = response.json()print(gallery['drive_url'])
{"success": true,"drive_id": "abc123xyz","admin_id": "UxCIkRbY","drive_url": "https://warpbin.com/abc123xyz","manage_url": "https://warpbin.com/manage/abc123xyz?pd=UxCIkRbY","message": "Gallery created successfully"}