PyPI installation
Install the published package from PyPI, then let the client load credentials from .env by default.
SDK library
Python, TypeScript, and PHP are live now. Each route documents the same Dilnaka upload lifecycle in the conventions of its own runtime.
Environment-driven setup, direct-to-S3 uploads, and the current Python reference implementation.
Node 18+ uploads, typed file helpers, and fetch injection for tests or custom runtimes.
Composer installation, PHP 8.1+, Guzzle transport, and the same Dilnaka file lifecycle.
Documentation
Python SDK for uploading files through the Dilnaka Upload API. The SDK reads the API key from .env by default, asks your Dilnaka backend for a presigned S3 upload URL, uploads the file directly to S3, and then calls the completion endpoint.
Install the published package from PyPI, then let the client load credentials from .env by default.
Files go straight to S3 using a temporary presigned URL, while your backend remains the source of truth.
The SDK expects a small set of file-management endpoints from your Caspian backend.
Setup
Install the published Dilnaka Python SDK from PyPI. The package is available online now, so the old editable test install flow is no longer part of the docs.
Package: pypi.org/project/dilnaka
pip install dilnaka
Configuration
The SDK only needs your API key in .env. It is built specifically for Dilnaka Storage.
DILNAKA_API_KEY=dlk_dev_your_api_key_here
DILNAKA_TIMEOUT=60
DILNAKA_MULTIPART_THRESHOLD=104857600
DILNAKA_UPLOAD_TIMEOUT=300
Optional: set DILNAKA_TIMEOUT (default 60) for the JSON API request timeout in seconds.
Set DILNAKA_MULTIPART_THRESHOLD (default 104857600, i.e. 100 MB) to control the file size at which uploads switch to the multipart flow.
Set DILNAKA_UPLOAD_TIMEOUT (default 300) for the per-part transfer timeout in seconds. It is intentionally larger than the API timeout so large chunks over slow links do not time out.
Core flow
Instantiate the client with environment defaults and upload a file with a single method call.
from dilnaka import Dilnaka
client = Dilnaka()
uploaded = client.upload("./test-upload.txt")
print(uploaded.id)
print(uploaded.key)
print(uploaded.status)
Alternate setup
Pass values directly only when you want to avoid environment variables.
from dilnaka import Dilnaka
client = Dilnaka(
api_key="dlk_dev_your_api_key_here",
)
uploaded = client.upload("./avatar.png", folder="avatars")
print(uploaded)
Large files
The same upload() call handles files of any size. Small files use a single presigned PUT. Files at or above the multipart threshold (100 MB by default) automatically switch to a resumable S3 multipart upload that streams the file in chunks and retries a failed part instead of discarding the whole transfer.
from dilnaka import Dilnaka
client = Dilnaka()
# Large files (>= 100 MB) automatically use resumable multipart upload.
uploaded = client.upload("./course-bundle.zip")
# Tune per call: force multipart above 25 MB and allow 10 minutes per part.
uploaded = client.upload(
"./course-bundle.zip",
multipart_threshold=25 * 1024 * 1024,
upload_timeout=600,
)
print(uploaded.id, uploaded.status)
The multipart flow streams the file from disk one part at a time, so memory stays flat even for multi-gigabyte uploads. Each part is retried with a fresh presigned URL if it fails, and a transfer that cannot finish is aborted automatically so it never leaves a dangling upload on the bucket.
For direct control, the lower-level methods are also available:
create_multipart_upload(...) starts the upload and returns the part layout.presign_multipart_parts(file_id, part_numbers) returns presigned PUT URLs per part.complete_multipart_upload(file_id, parts) finalizes the upload from part ETags.abort_multipart_upload(file_id) cancels an in-progress upload.Quota model
Storage is the total size of the files you keep in Dilnaka. Bandwidth is the total amount of file data downloaded or served by users and applications during the current billing month.
Uploads do not count toward bandwidth. Reads and downloads do count because Dilnaka is authorizing delivery from your S3-backed file store.
Free accounts stop serving files after the included monthly bandwidth is exhausted. Paid plans can continue serving files with storage and bandwidth overage billing until the plan safety cap is reached.
Free
2 GB storage and 5 GB/month bandwidth. Best for testing and small prototypes. No overage. File serving pauses when the monthly bandwidth limit is reached.
Pro
100 GB storage and 50 GB/month bandwidth. Extra storage is billed at $0.08/GB and extra bandwidth at $0.12/GB. Service keeps running until the 500 GB monthly safety cap.
Usage-Based
250 GB storage and 150 GB/month bandwidth. Extra storage is billed at $0.08/GB and extra bandwidth at $0.12/GB. Service keeps running until the 1 TB monthly safety cap.
Backend contract
The SDK expects your Caspian backend to expose the following endpoints.
POST /v1/uploads/presign
POST /v1/uploads/complete
POST /v1/uploads/multipart/create
POST /v1/uploads/multipart/parts
POST /v1/uploads/multipart/complete
POST /v1/uploads/multipart/abort
GET /v1/files
GET /v1/files/__PP_ESCAPED_LEFT_BRACE__file_id__PP_ESCAPED_RIGHT_BRACE__
GET /v1/files/__PP_ESCAPED_LEFT_BRACE__file_id__PP_ESCAPED_RIGHT_BRACE__/access-url?expiresIn=1200
DELETE /v1/files/__PP_ESCAPED_LEFT_BRACE__file_id__PP_ESCAPED_RIGHT_BRACE__
Use the access-url endpoint when you need a temporary read URL for one file. Pass expiresIn in seconds to request a shorter or longer lifetime. When omitted, Dilnaka uses the app default signed URL TTL.
API payloads
__PP_ESCAPED_LEFT_BRACE__
"fileId": "clx_file_id",
"fileKey": "uploads/2026/05/clx_file_id-test.txt",
"uploadUrl": "https://s3-presigned-url",
"expiresIn": 300,
"method": "PUT",
"headers": __PP_ESCAPED_LEFT_BRACE__
"Content-Type": "text/plain"
__PP_ESCAPED_RIGHT_BRACE__
__PP_ESCAPED_RIGHT_BRACE__
__PP_ESCAPED_LEFT_BRACE__
"fileId": "clx_file_id",
"status": "uploaded",
"key": "uploads/2026/05/clx_file_id-test.txt",
"originalName": "test.txt",
"contentType": "text/plain",
"size": 94,
"publicUrl": null
__PP_ESCAPED_RIGHT_BRACE__
__PP_ESCAPED_LEFT_BRACE__
"fileId": "clx_file_id",
"url": "https://s3-presigned-url",
"expiresIn": 1200,
"isTemporary": true
__PP_ESCAPED_RIGHT_BRACE__
__PP_ESCAPED_LEFT_BRACE__
"success": false,
"error": "bandwidth_limit_exceeded",
"message": "Monthly bandwidth limit exceeded. Upgrade your plan or wait until the next billing cycle."
__PP_ESCAPED_RIGHT_BRACE__
__PP_ESCAPED_LEFT_BRACE__
"success": true,
"warning": "bandwidth_overage_active",
"message": "This account has exceeded included bandwidth. Extra usage will be billed."
__PP_ESCAPED_RIGHT_BRACE__
__PP_ESCAPED_LEFT_BRACE__
"success": false,
"error": "bandwidth_hard_cap_reached",
"message": "Monthly bandwidth hard cap reached. Contact Dilnaka support to continue serving files."
__PP_ESCAPED_RIGHT_BRACE__
Examples
from dilnaka import Dilnaka
client = Dilnaka()
access = client.get_file_access_url(
"maext0cfjsquw2mu9o597fb9",
expires_in=1200,
)
print(access.url)
print(access.expires_in)
from dilnaka import Dilnaka
client = Dilnaka()
file_id = "maext0cfjsquw2mu9o597fb9"
result = client.delete_file(file_id)
print(result)
from dilnaka import Dilnaka
client = Dilnaka()
uploaded = client.upload("./test-upload.txt", folder="uploads")
print("Uploaded file:")
print(f" id: __PP_ESCAPED_LEFT_BRACE__uploaded.id__PP_ESCAPED_RIGHT_BRACE__")
print(f" key: __PP_ESCAPED_LEFT_BRACE__uploaded.key__PP_ESCAPED_RIGHT_BRACE__")
print(f" status: __PP_ESCAPED_LEFT_BRACE__uploaded.status__PP_ESCAPED_RIGHT_BRACE__")
print(f" size: __PP_ESCAPED_LEFT_BRACE__uploaded.size__PP_ESCAPED_RIGHT_BRACE__")
print(f" content_type: __PP_ESCAPED_LEFT_BRACE__uploaded.content_type__PP_ESCAPED_RIGHT_BRACE__")
from dilnaka import Dilnaka
client = Dilnaka()
# Files >= 100 MB automatically use resumable multipart upload.
uploaded = client.upload(
"./course-bundle.zip",
folder="courses",
upload_timeout=600,
)
print(uploaded.id, uploaded.status, uploaded.size)
from dilnaka import Dilnaka
client = Dilnaka()
for file in client.list_files():
print(f"__PP_ESCAPED_LEFT_BRACE__file.id__PP_ESCAPED_RIGHT_BRACE__ | __PP_ESCAPED_LEFT_BRACE__file.status__PP_ESCAPED_RIGHT_BRACE__ | __PP_ESCAPED_LEFT_BRACE__file.key__PP_ESCAPED_RIGHT_BRACE__")
Pricing example
Pro plan example: you get 100 GB of storage and 50 GB/month of included bandwidth. If your app serves 70 GB in one month, the extra 20 GB is billed as bandwidth overage and service keeps running. Dilnaka only blocks delivery if the plan later reaches its 500 GB monthly safety cap.
Security
The SDK never receives AWS credentials. It only receives a temporary presigned upload URL from your Dilnaka backend.
Your backend remains responsible for API key validation, scope checking, file validation, S3 key generation, metadata persistence, upload completion verification, and temporary read URL expiration.