Developer API
A small public API for minting download links and reading file metadata.
All endpoints are under /v1, return JSON, and are open to cross-origin
browser calls (Access-Control-Allow-Origin: *).
Base URL: https://i.kernal.bid/v1
Rate limits
Requests are rate-limited per IP address. Download mints are limited to a
small number per minute; if you hit a limit you will receive 429.
Proof of work
Download links require a small proof of work so that minting is cheap for real users but expensive to automate at scale.
- Fetch a challenge.
- Find a
countersuch thatSHA-256(nonce + counter)starts with at leastbitsleading zero bits (nonceandcounterare hex strings, concatenated as ASCII, the hash is hex-encoded). - Submit the solution to
/v1/download.
A challenge can only be used once.
Endpoints
GET /v1/pow/challenge
Returns a fresh challenge.
{
"nonce": "0d4f6e5c1a9b3f0a2c8e6d7b4f1a9c0d",
"bits": 14
}
POST /v1/download
Body: application/json
{
"nonce": "0d4f6e5c1a9b3f0a2c8e6d7b4f1a9c0d",
"counter": "00000000000004d2",
"file_id": "f6uB4yi6"
}
Response 200:
{
"token": "eyJ...",
"download": "https://i.kernal.bid/d/f6uB4yi6?s=eyJ...",
"hotlink": "https://i.kernal.bid/h/f6uB4yi6?s=eyJ...",
"expires_at": "2026-08-16T12:00:00Z"
}
download is a standard download (attachment, with the original filename).
hotlink serves the raw file bytes for direct embedding. Both are valid
until expires_at.
Errors: 403 invalid or used proof of work, 404 file not found,
429 rate limited, 400 malformed request.
GET /v1/file/{id}
Public metadata for a file. No proof of work required.
{
"id": "f6uB4yi6",
"name": "document.pdf",
"size": 23749047,
"size_human": "22.6 MiB",
"sha256": "3f62...",
"mime": "application/pdf",
"uploaded_at": "January 2, 2026",
"downloads": 3,
"views": 12
}
Errors: 404 file not found.
Example
A minimal Python client:
import hashlib, json, urllib.request
BASE = "https://i.kernal.bid/v1"
def solve(nonce, bits):
target = 0
for _ in range(bits):
target = (target << 1) | 1
counter = 0
while True:
digest = int(hashlib.sha256((nonce + f"{counter:016x}").encode()).hexdigest(), 16)
if digest <= target:
return f"{counter:016x}"
counter += 1
challenge = json.load(urllib.request.urlopen(f"{BASE}/pow/challenge"))
counter = solve(challenge["nonce"], challenge["bits"])
req = urllib.request.Request(
f"{BASE}/download",
data=json.dumps({
"nonce": challenge["nonce"],
"counter": counter,
"file_id": "f6uB4yi6",
}).encode(),
headers={"Content-Type": "application/json"},
)
result = json.load(urllib.request.urlopen(req))
print(result["download"])
The download URL can be fetched directly, e.g. with curl -L -o out.bin.