Sendrio API v1
Programmatisch Dateien versenden und empfangen
Die Sendrio Developer API ermoeglicht es Ihnen, alle Funktionen von Sendrio in Ihre eigenen Anwendungen zu integrieren: Dateien hochladen, Download-Links erstellen, Transfers per E-Mail teilen und Filedrops verwalten.
Basis-URL: https://sendrio.app/api/v1/
Authentifizierung
Alle API-Requests erfordern einen API-Key als Bearer-Token im Authorization-Header:
Authorization: Bearer snd_live_a3f2b7c9e1d4f8a6b0c2d4e6f8a0b2c4d6e8f0a2b4c6d8e0f2a4b6c8
API-Keys beginnen immer mit snd_live_ und sind 73 Zeichen lang. Der Key wird bei der Erstellung einmalig angezeigt – speichern Sie ihn sicher ab.
Scopes
Optional koennen Keys auf bestimmte Berechtigungen eingeschraenkt werden:
| Scope | Beschreibung |
|---|---|
transfer.read | Transfers auflisten und Details laden |
transfer.write | Transfers erstellen, aendern, loeschen, hochladen |
download | Dateien direkt herunterladen |
filedrop.read | Filedrops auflisten und Details laden |
filedrop.write | Filedrops erstellen, aendern, loeschen |
comment | Kommentare lesen und schreiben |
account.read | Kontoinformationen und Quota lesen |
keys.manage | API-Keys erstellen und widerrufen |
Ein Key ohne Scopes hat Vollzugriff auf alle Bereiche.
Schnellstart
In 3 Schritten eine Datei versenden:
1. Transfer erstellen
curl -X POST https://sendrio.app/api/v1/transfers \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"files": [{"name": "report.pdf", "size": 1048576, "type": "application/pdf"}],
"expiry": "1w"
}'
Antwort: transfer_id, upload_token, chunk_size
2. Datei hochladen (Chunk fuer Chunk)
curl -X POST https://sendrio.app/api/v1/transfers/$TRANSFER_ID/upload \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/octet-stream" \
-H "X-Upload-Token: $UPLOAD_TOKEN" \
-H "X-File-Index: 0" \
-H "X-Chunk-Index: 0" \
-H "X-Total-Chunks: 1" \
--data-binary @report.pdf
3. Upload abschliessen
curl -X POST https://sendrio.app/api/v1/transfers/$TRANSFER_ID/complete \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"upload_token": "'$UPLOAD_TOKEN'"}'
Antwort: download_url – fertig!
Fehlerbehandlung
Erfolgreiche Antworten:
{
"success": true,
"data": { ... }
}
Fehler-Antworten:
{
"success": false,
"error": {
"code": "TRANSFER_NOT_FOUND",
"message": "Transfer nicht gefunden.",
"status": 404
}
}
Fehlercodes
| HTTP | Code | Beschreibung |
|---|---|---|
| 400 | VALIDATION_ERROR | Ungueltige Eingabedaten |
| 400 | EXTENSION_BLOCKED | Blockierte Dateiendung |
| 400 | PASSWORD_TOO_WEAK | Passwort auf Blocklist |
| 401 | UNAUTHORIZED | Fehlender/ungueltiger API-Key |
| 401 | KEY_REVOKED | API-Key widerrufen |
| 401 | KEY_EXPIRED | API-Key abgelaufen |
| 403 | FORBIDDEN | Keine Berechtigung |
| 403 | SUBSCRIPTION_REQUIRED | Bezahltes Abo erforderlich |
| 403 | SCOPE_INSUFFICIENT | Key hat nicht den benoetigten Scope |
| 404 | TRANSFER_NOT_FOUND | Transfer nicht gefunden |
| 404 | FILE_NOT_FOUND | Datei nicht gefunden |
| 404 | FILEDROP_NOT_FOUND | Filedrop nicht gefunden |
| 409 | SLUG_EXISTS | Filedrop-Slug bereits vergeben |
| 410 | TRANSFER_EXPIRED | Transfer abgelaufen |
| 429 | RATE_LIMIT_EXCEEDED | Rate-Limit ueberschritten |
| 429 | QUOTA_EXCEEDED | Volumen-/Transfer-Limit erreicht |
Rate-Limiting
Limits pro API-Key:
| Aktion | Limit |
|---|---|
| Allgemeine Requests | 60 / Minute |
| Transfer erstellen | 100 / Stunde |
| Chunk-Upload | 1000 / Stunde |
| E-Mail senden | 30 / Stunde |
| Filedrop-Operationen | 30 / Stunde |
Jede Antwort enthaelt Rate-Limit-Header:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1709734800
API Key erstellen
Scope: keys.manage (oder Session-Auth fuer den ersten Key)
Request Body
{
"name": "Meine Integration",
"scopes": ["transfer.read", "transfer.write", "download"],
"expires_at": "2027-12-31T23:59:59Z"
}
name string optional – Bezeichnung (1-100 Zeichen, Standard: "Standard")
scopes string[] optional – Berechtigungen (leer = Vollzugriff)
expires_at string optional – Ablaufdatum (ISO 8601, null = kein Ablauf)
Response (201)
{
"success": true,
"data": {
"id": 1,
"key": "snd_live_a3f2b7c9e1d4...",
"key_prefix": "snd_live_a3f2",
"name": "Meine Integration",
"scopes": ["transfer.read", "transfer.write", "download"],
"expires_at": "2027-12-31T23:59:59Z",
"created_at": "2026-03-06T12:00:00Z"
}
}
API Keys auflisten
Scope: keys.manage
Gibt alle eigenen Keys zurueck (ohne den Key-Wert, nur Prefix).
API Key widerrufen
Scope: keys.manage
Widerruft einen Key dauerhaft. Der Key bleibt fuer den Audit-Trail gespeichert.
Transfer erstellen
Scope: transfer.write
Request Body
{
"files": [
{"name": "report.pdf", "size": 1048576, "type": "application/pdf"},
{"name": "data.xlsx", "size": 524288, "type": "application/vnd.ms-excel"}
],
"expiry": "1w",
"password": "optional-passwort",
"notify_on_download": true
}
files array erforderlich – Datei-Metadaten (name, size, type)
expiry string optional – 1h, 6h, 1d, 3d, 1w, 2w, 4w, 8w, once (Standard: 1w)
password string optional – Passwortschutz fuer Download
notify_on_download boolean optional – E-Mail bei Download
Response (201)
{
"success": true,
"data": {
"transfer_id": "abc123XYZ9",
"upload_token": "ut_a1b2c3d4e5f6...",
"chunk_size": 5242880,
"files": [
{"index": 0, "total_chunks": 1, "file_id": 42}
]
}
}
Transfers auflisten
Scope: transfer.read
Query-Parameter: ?page=1&per_page=20&status=active|expired|all
Transfer laden
Scope: transfer.read
Gibt Transfer-Details inklusive Dateiliste zurueck.
Transfer aendern
Scope: transfer.write
Request Body
{
"expiry": "4w",
"password": "neues-passwort",
"notify_on_download": false
}
Setzen Sie password auf null, um den Passwortschutz zu entfernen.
Transfer loeschen
Scope: transfer.write
Loescht den Transfer und alle zugehoerigen Dateien.
Chunk hochladen
Scope: transfer.write
Headers
| Header | Beschreibung |
|---|---|
X-Upload-Token | Token aus der Transfer-Erstellung |
X-File-Index | Index der Datei (0-basiert) |
X-Chunk-Index | Index des Chunks (0-basiert) |
X-Total-Chunks | Gesamtanzahl der Chunks fuer diese Datei |
Content-Type | application/octet-stream |
Body: Raw Binary (Chunk-Daten)
Chunk-Groesse: Nutzen Sie den chunk_size-Wert aus der Transfer-Erstellung (Standard: 5 MB).
Upload abschliessen
Scope: transfer.write
Request Body
{"upload_token": "ut_a1b2c3d4e5f6..."}
Response (200)
{
"success": true,
"data": {
"transfer_id": "abc123XYZ9",
"download_url": "https://sendrio.app/d/abc123XYZ9",
"total_size": 1572864,
"virus_scan": {"enabled": true, "status": "pending"}
}
}
Download-URL
Scope: download
Gibt die oeffentliche Download-URL und Metadaten zurueck.
Datei herunterladen
Scope: download
Streamt die Datei direkt als Binary-Download. Nur eigene Transfers.
Datei-Vorschau (Bilder)
Scope: download
Gibt eine Bild-Datei inline zurueck (fuer Vorschau/Thumbnail). Nur Dateien mit MIME-Typ image/* werden unterstuetzt.
Authentifizierung
Neben dem Standard Authorization-Header kann der API-Key auch als Query-Parameter uebergeben werden – praktisch fuer <img>-Tags:
<img src="https://sendrio.app/api/v1/transfers/{id}/files/{fileId}/preview?key=snd_live_..." />
Response (200)
Binary-Bilddaten mit passendem Content-Type (z.B. image/png, image/jpeg).
| Header | Wert |
|---|---|
Content-Type | MIME-Typ der Datei |
Content-Disposition | inline |
Cache-Control | private, max-age=3600 |
Fehler
| HTTP | Code | Beschreibung |
|---|---|---|
| 400 | NOT_AN_IMAGE | Datei ist kein Bild |
| 404 | TRANSFER_NOT_FOUND | Transfer nicht gefunden |
| 404 | FILE_NOT_FOUND | Datei nicht gefunden |
Download-Verlauf
Scope: transfer.read
Gibt den Download-Verlauf eines Transfers zurueck: Anzahl Downloads, Zeitpunkte, heruntergeladene Dateien und die Liste der E-Mail-Empfaenger (falls per E-Mail geteilt).
Response
{
"success": true,
"data": {
"transfer_id": "abc123XYZ9",
"download_count": 3,
"is_expired": false,
"is_one_time": false,
"recipients": ["alice@example.com", "bob@example.com"],
"downloads": [
{
"downloaded_at": "2026-03-06T14:32:00",
"file_name": "report.pdf",
"file_id": 42
}
]
}
}
recipients-Liste zeigt alle Empfaenger, an die der Transfer geteilt wurde. Maximal 200 Download-Eintraege werden zurueckgegeben.
Per E-Mail teilen
Scope: transfer.write
Request Body
{
"recipients": ["alice@example.com", "bob@example.com"],
"message": "Hier sind die angeforderten Dateien.",
"notify_on_download": true
}
Maximal 3 Empfaenger pro Request.
Filedrop erstellen
Scope: filedrop.write
Request Body
{
"slug": "meine-firma",
"name": "Dateien fuer Meine Firma",
"description": "Laden Sie hier Ihre Unterlagen hoch.",
"max_file_size": 104857600,
"max_files": 10,
"password": "optional",
"hide_name": false
}
slug string erforderlich – URL-Slug (3-64 Zeichen, Kleinbuchstaben, muss mit Buchstabe beginnen)
name string erforderlich – Anzeigename
Filedrops auflisten
Scope: filedrop.read
Filedrop Details
Scope: filedrop.read
Filedrop aktualisieren
Scope: filedrop.write
Filedrop loeschen
Scope: filedrop.write
Filedrop-Uploads auflisten
Scope: filedrop.read
Query-Parameter: ?page=1&per_page=20
Kommentare auflisten
Scope: comment
Gibt Transfer- und Datei-Kommentare getrennt zurueck. Berechtigung: Absender oder Empfaenger.
Kommentar erstellen
Scope: comment
Request Body
{
"body": "Bitte Datei 2 nochmal pruefen.",
"file_id": 42
}
body string erforderlich – Kommentartext (max. 2000 Zeichen)
file_id integer optional – Datei-ID fuer Datei-Kommentare
Kontoinformationen
Scope: account.read
Response
{
"success": true,
"data": {
"email": "user@example.com",
"display_name": "Max Mustermann",
"plan": "business",
"is_registered": true,
"created_at": "2026-01-15T08:00:00Z"
}
}
Quota / Nutzung
Scope: account.read
Response
{
"success": true,
"data": {
"volume_used": 5368709120,
"volume_limit": 107374182400,
"volume_used_formatted": "5.00 GB",
"volume_limit_formatted": "100.00 GB",
"transfer_count": 15,
"transfer_limit": 0,
"period_start": "2026-03-01",
"period_end": "2026-03-31"
}
}
Magic Link senden
Scope: transfer.write
Generiert einen einmaligen Login-Link und sendet ihn per E-Mail an den Empfaenger. Beim Klick auf den Link wird der Benutzer automatisch bei Sendrio verifiziert und eingeloggt – ohne manuellen Code-Eingabe.
Request Body
{
"email": "empfaenger@example.com",
"redirect_url": "https://sendrio.app/profil"
}
email string erforderlich – E-Mail-Adresse des Empfaengers
redirect_url string optional – URL, zu der nach dem Login weitergeleitet wird (Standard: Startseite)
Response (201)
{
"success": true,
"data": {
"email": "empfaenger@example.com",
"magic_url": "https://sendrio.app/magic/a3f2b7c9e1d4f8...",
"expires_at": "2026-03-07T13:30:00",
"ttl_minutes": 30
}
}
Beispiel: Transfer + Magic Link
# 1. Datei hochladen und Download-Link erstellen (wie gewohnt)
# 2. Magic Link generieren und senden
curl -X POST https://sendrio.app/api/v1/magic-link \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "kunde@example.com",
"redirect_url": "https://sendrio.app/profil"
}'
Push-Token registrieren
Registriert ein Push-Notification-Token fuer den authentifizierten Benutzer (Mobile App).
Request Body
{
"token": "ExponentPushToken[a1b2c3d4e5f6...]",
"platform": "ios"
}
token string erforderlich – Push-Token (FCM oder APNs)
platform string optional – ios oder android (Standard: ios)
Response (200)
{
"registered": true,
"platform": "ios"
}
Push-Token entfernen
Entfernt ein zuvor registriertes Push-Notification-Token.
Request Body
{
"token": "ExponentPushToken[a1b2c3d4e5f6...]"
}
token string erforderlich – Das zu entfernende Push-Token
Response (200)
{
"unregistered": true
}
Mobile Authentifizierung
Verifiziert eine E-Mail-Adresse per Code und erstellt in einem Schritt einen API-Key. Gedacht fuer Mobile Apps, die keinen Session-basierten Login nutzen.
POST /api/verify/send einen Code anfordern, dann mit diesem Endpoint verifizieren und direkt einen API-Key erhalten.
Request Body
{
"email": "user@example.com",
"code": "123456",
"device_name": "Mein iPhone"
}
email string erforderlich – E-Mail-Adresse
code string erforderlich – 6-stelliger Verifizierungscode
device_name string optional – Geraetename fuer den API-Key (Standard: Mobile App)
Authentifizierung
Keine – oeffentlicher Endpoint. Rate-Limiting per IP (max. 10 Anfragen pro Zeitfenster).
Response (200)
{
"success": true,
"api_key": "snd_live_a3f2b7c9e1d4...",
"user": {
"email": "user@example.com",
"display_name": "Max Mustermann",
"is_registered": true
}
}
Code-Beispiele
JavaScript (fetch)
const API_KEY = 'snd_live_...';
const BASE = 'https://sendrio.app/api/v1';
// 1. Transfer erstellen
const res = await fetch(`${BASE}/transfers`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
files: [{ name: 'doc.pdf', size: file.size, type: 'application/pdf' }],
expiry: '1w',
}),
});
const { data } = await res.json();
// 2. Datei in Chunks hochladen
const chunkSize = data.chunk_size;
const totalChunks = Math.ceil(file.size / chunkSize);
for (let i = 0; i < totalChunks; i++) {
const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
await fetch(`${BASE}/transfers/${data.transfer_id}/upload`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/octet-stream',
'X-Upload-Token': data.upload_token,
'X-File-Index': '0',
'X-Chunk-Index': String(i),
'X-Total-Chunks': String(totalChunks),
},
body: chunk,
});
}
// 3. Abschliessen
const complete = await fetch(`${BASE}/transfers/${data.transfer_id}/complete`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ upload_token: data.upload_token }),
});
const result = await complete.json();
console.log('Download-URL:', result.data.download_url);
Python (requests)
import requests, os, math
API_KEY = 'snd_live_...'
BASE = 'https://sendrio.app/api/v1'
headers = {'Authorization': f'Bearer {API_KEY}'}
filepath = 'report.pdf'
filesize = os.path.getsize(filepath)
# 1. Transfer erstellen
r = requests.post(f'{BASE}/transfers', headers=headers, json={
'files': [{'name': 'report.pdf', 'size': filesize, 'type': 'application/pdf'}],
'expiry': '1w',
})
data = r.json()['data']
# 2. Chunks hochladen
chunk_size = data['chunk_size']
total_chunks = math.ceil(filesize / chunk_size)
with open(filepath, 'rb') as f:
for i in range(total_chunks):
chunk = f.read(chunk_size)
requests.post(
f'{BASE}/transfers/{data["transfer_id"]}/upload',
headers={
**headers,
'Content-Type': 'application/octet-stream',
'X-Upload-Token': data['upload_token'],
'X-File-Index': '0',
'X-Chunk-Index': str(i),
'X-Total-Chunks': str(total_chunks),
},
data=chunk,
)
# 3. Abschliessen
r = requests.post(f'{BASE}/transfers/{data["transfer_id"]}/complete',
headers=headers,
json={'upload_token': data['upload_token']},
)
print('Download-URL:', r.json()['data']['download_url'])
PHP
$apiKey = 'snd_live_...';
$base = 'https://sendrio.app/api/v1';
$filepath = 'report.pdf';
$filesize = filesize($filepath);
// 1. Transfer erstellen
$ch = curl_init("$base/transfers");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer $apiKey",
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'files' => [['name' => 'report.pdf', 'size' => $filesize, 'type' => 'application/pdf']],
'expiry' => '1w',
]),
]);
$data = json_decode(curl_exec($ch), true)['data'];
curl_close($ch);
// 2. Chunk hochladen (vereinfacht, 1 Chunk)
$ch = curl_init("$base/transfers/{$data['transfer_id']}/upload");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer $apiKey",
'Content-Type: application/octet-stream',
"X-Upload-Token: {$data['upload_token']}",
'X-File-Index: 0', 'X-Chunk-Index: 0', 'X-Total-Chunks: 1',
],
CURLOPT_POSTFIELDS => file_get_contents($filepath),
]);
curl_exec($ch);
curl_close($ch);
// 3. Abschliessen
$ch = curl_init("$base/transfers/{$data['transfer_id']}/complete");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer $apiKey",
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['upload_token' => $data['upload_token']]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
echo "Download-URL: " . $result['data']['download_url'];