API & Webhooks
Retrieve your transfers and statistics programmatically, and get a notification the moment someone downloads your files. Read-only REST + HMAC-signed webhooks.
1. Getting started
Create an API key on your account page (part of every paid plan). The key is shown only once — keep it safe. Send it with every request:
Authorization: Bearer dlk_live_xxxxxxxxxxxxxxxxxxxx
2. Endpoints
Base URL: https://downloadlink.nl/api/v1. All responses are JSON and limited to your own account.
GET /api/v1/me
Account + storage usage.
curl -H "Authorization: Bearer dlk_live_xxx" \
https://downloadlink.nl/api/v1/me
{
"email": "jij@bedrijf.nl",
"is_trial": false,
"plan": "100 GB",
"storage": { "used_bytes": 5242880, "quota_bytes": 107374182400, "percent": 0 }
}
GET /api/v1/transfers
Your transfers (newest first). Parameter ?limit= (1–200, default 50).
{
"count": 1,
"transfers": [
{
"token": "a1b2c3d4e5f6a7b8",
"title": "Quote Q3",
"created_at": "2026-06-17T09:12:00+00:00",
"expires_at": "2026-06-24T09:12:00+00:00",
"unlimited": false,
"revoked": false,
"files": 3,
"size_bytes": 8412300,
"downloads": 2,
"recipients": 1,
"url": "https://downloadlink.nl/p/a1b2c3d4e5f6a7b8"
}
]
}
GET /api/v1/transfers/<token>
A single transfer: metadata, the files, and recent download activity (who/when/which file).
{
"token": "a1b2c3d4e5f6a7b8",
"title": "Quote Q3",
"created_at": "2026-06-17T09:12:00+00:00",
"expires_at": "2026-06-24T09:12:00+00:00",
"unlimited": false,
"revoked": false,
"max_downloads": null,
"downloads_used": 0,
"size_bytes": 8412300,
"files": [
{ "name": "quote.pdf", "size_bytes": 412300 }
],
"downloads": 2,
"url": "https://downloadlink.nl/p/a1b2c3d4e5f6a7b8",
"activity": [
{
"downloaded_at": "2026-06-17T10:30:00+00:00",
"type": "zip",
"file": "(whole package / zip)",
"ip": "203.0.113.7"
},
{
"downloaded_at": "2026-06-17T09:58:00+00:00",
"type": "file",
"file": "quote.pdf",
"ip": "198.51.100.24"
}
]
}
Note: ip is the full IP address of the person who downloaded — personal data of your recipient, not an anonymised figure. You receive it in full, just as in the activity overview, the downloads CSV and the proof of delivery (PDF); it is there so you can demonstrate that a package has been retrieved. If you process or store it in your own system, include it in your own privacy statement. We return the 100 most recent records; downloads counts those records. We keep them for a maximum of 12 months — after that, they can no longer be retrieved, not even via the API. downloads_used is the counter for the download limit and remains 0 as long as max_downloads is empty.
Rate limit: 120 requests per minute per key (HTTP 429 when exceeded).
2b. Creating a transfer (write)
Deliver a file via your own branded download page, straight from your system — a generated report or invoice, for example:
curl -X POST https://downloadlink.nl/api/v1/transfers \ -H "Authorization: Bearer <sleutel>" \ -F "file=@rapport.pdf" \ -F "title=Rapport week 30" \ -F "expiry_days=30" # of 'never' voor onbeperkt geldig # optioneel: -F "password=geheim" voor een wachtwoord op de downloadpagina
HTTP 201
{
"ok": true,
"token": "a1b2c3d4e5f6a7b8",
"url": "https://downloadlink.nl/p/a1b2c3d4e5f6a7b8",
"expires_at": "2026-08-22T10:30:00+00:00",
"unlimited": false
}
Error paths: 402 payment_required (the write API is part of the paid plans), 402 quota_exceeded (storage full), 413 (file larger than the API limit — use the upload page for that). The download page branding follows the account the key belongs to.
3. Webhooks
Register an https-URL on your account page (the "Test" button immediately sends a ping-event so you can check your integration). As soon as someone downloads your transfer, we send a POST with this event:
POST https://jouw-server.nl/webhooks/downloadlink
X-Downloadlink-Event: transfer.downloaded
X-Downloadlink-Signature: sha256=<hmac>
Content-Type: application/json
{
"event": "transfer.downloaded",
"delivered_at": "2026-06-17T10:30:00+00:00",
"data": {
"token": "a1b2c3d4e5f6a7b8",
"title": "Quote Q3",
"url": "https://downloadlink.nl/p/a1b2c3d4e5f6a7b8",
"download_type": "zip",
"downloaded_at": "2026-06-17T10:30:00+00:00"
}
}
Verifying the signature
Compute HMAC-SHA256 over the raw request body with your webhook secret and compare it constant-time against the header. Ignore messages that do not match.
Python
import hmac, hashlib
def is_valid(secret: str, raw_body: bytes, header: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header or "")
Node.js
const crypto = require('crypto');
function isValid(secret, rawBody, header) {
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(expected), b = Buffer.from(header || '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Reply with HTTP 2xx to confirm delivery. After 15 failed attempts we switch the webhook off; a successful test (button on your account page) turns it back on. Only public https URLs are allowed.