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.

Voraussetzung: Ein bezahltes Sendrio-Abo (Basis oder Business). API-Keys koennen im Profil unter sendrio.app/profil erstellt werden.

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:

ScopeBeschreibung
transfer.readTransfers auflisten und Details laden
transfer.writeTransfers erstellen, aendern, loeschen, hochladen
downloadDateien direkt herunterladen
filedrop.readFiledrops auflisten und Details laden
filedrop.writeFiledrops erstellen, aendern, loeschen
commentKommentare lesen und schreiben
account.readKontoinformationen und Quota lesen
keys.manageAPI-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

HTTPCodeBeschreibung
400VALIDATION_ERRORUngueltige Eingabedaten
400EXTENSION_BLOCKEDBlockierte Dateiendung
400PASSWORD_TOO_WEAKPasswort auf Blocklist
401UNAUTHORIZEDFehlender/ungueltiger API-Key
401KEY_REVOKEDAPI-Key widerrufen
401KEY_EXPIREDAPI-Key abgelaufen
403FORBIDDENKeine Berechtigung
403SUBSCRIPTION_REQUIREDBezahltes Abo erforderlich
403SCOPE_INSUFFICIENTKey hat nicht den benoetigten Scope
404TRANSFER_NOT_FOUNDTransfer nicht gefunden
404FILE_NOT_FOUNDDatei nicht gefunden
404FILEDROP_NOT_FOUNDFiledrop nicht gefunden
409SLUG_EXISTSFiledrop-Slug bereits vergeben
410TRANSFER_EXPIREDTransfer abgelaufen
429RATE_LIMIT_EXCEEDEDRate-Limit ueberschritten
429QUOTA_EXCEEDEDVolumen-/Transfer-Limit erreicht

Rate-Limiting

Limits pro API-Key:

AktionLimit
Allgemeine Requests60 / Minute
Transfer erstellen100 / Stunde
Chunk-Upload1000 / Stunde
E-Mail senden30 / Stunde
Filedrop-Operationen30 / Stunde

Jede Antwort enthaelt Rate-Limit-Header:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1709734800

API Key erstellen

POST /api/v1/keys

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"
  }
}
Wichtig: Der vollstaendige Key wird nur einmalig in dieser Antwort zurueckgegeben. Speichern Sie ihn sicher!

API Keys auflisten

GET /api/v1/keys

Scope: keys.manage

Gibt alle eigenen Keys zurueck (ohne den Key-Wert, nur Prefix).

API Key widerrufen

DELETE /api/v1/keys/{id}

Scope: keys.manage

Widerruft einen Key dauerhaft. Der Key bleibt fuer den Audit-Trail gespeichert.

Transfer erstellen

POST /api/v1/transfers

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 optional1h, 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

GET /api/v1/transfers

Scope: transfer.read

Query-Parameter: ?page=1&per_page=20&status=active|expired|all

Transfer laden

GET /api/v1/transfers/{id}

Scope: transfer.read

Gibt Transfer-Details inklusive Dateiliste zurueck.

Transfer aendern

PUT /api/v1/transfers/{id}

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

DELETE /api/v1/transfers/{id}

Scope: transfer.write

Loescht den Transfer und alle zugehoerigen Dateien.

Chunk hochladen

POST /api/v1/transfers/{id}/upload

Scope: transfer.write

Headers

HeaderBeschreibung
X-Upload-TokenToken aus der Transfer-Erstellung
X-File-IndexIndex der Datei (0-basiert)
X-Chunk-IndexIndex des Chunks (0-basiert)
X-Total-ChunksGesamtanzahl der Chunks fuer diese Datei
Content-Typeapplication/octet-stream

Body: Raw Binary (Chunk-Daten)

Chunk-Groesse: Nutzen Sie den chunk_size-Wert aus der Transfer-Erstellung (Standard: 5 MB).

Upload abschliessen

POST /api/v1/transfers/{id}/complete

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

GET /api/v1/transfers/{id}/download-url

Scope: download

Gibt die oeffentliche Download-URL und Metadaten zurueck.

Datei herunterladen

GET /api/v1/transfers/{id}/files/{fileId}/download

Scope: download

Streamt die Datei direkt als Binary-Download. Nur eigene Transfers.

Datei-Vorschau (Bilder)

GET /api/v1/transfers/{id}/files/{fileId}/preview

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).

HeaderWert
Content-TypeMIME-Typ der Datei
Content-Dispositioninline
Cache-Controlprivate, max-age=3600

Fehler

HTTPCodeBeschreibung
400NOT_AN_IMAGEDatei ist kein Bild
404TRANSFER_NOT_FOUNDTransfer nicht gefunden
404FILE_NOT_FOUNDDatei nicht gefunden

Download-Verlauf

GET /api/v1/transfers/{id}/downloads

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
      }
    ]
  }
}
Hinweis: Downloads werden nicht einzelnen Empfaengern zugeordnet (DSGVO – nur gehashte IPs gespeichert). Die recipients-Liste zeigt alle Empfaenger, an die der Transfer geteilt wurde. Maximal 200 Download-Eintraege werden zurueckgegeben.

Per E-Mail teilen

POST /api/v1/transfers/{id}/share

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

POST /api/v1/filedrops

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

GET /api/v1/filedrops

Scope: filedrop.read

Filedrop Details

GET /api/v1/filedrops/{id}

Scope: filedrop.read

Filedrop aktualisieren

PUT /api/v1/filedrops/{id}

Scope: filedrop.write

Filedrop loeschen

DELETE /api/v1/filedrops/{id}

Scope: filedrop.write

Filedrop-Uploads auflisten

GET /api/v1/filedrops/{id}/uploads

Scope: filedrop.read

Query-Parameter: ?page=1&per_page=20

Kommentare auflisten

GET /api/v1/transfers/{id}/comments

Scope: comment

Gibt Transfer- und Datei-Kommentare getrennt zurueck. Berechtigung: Absender oder Empfaenger.

Kommentar erstellen

POST /api/v1/transfers/{id}/comments

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

GET /api/v1/account

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

GET /api/v1/quota

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"
  }
}
POST /api/v1/magic-link

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.

Anwendungsfall: Ideal fuer Integrationen, bei denen Sie Ihren Nutzern einen nahtlosen Zugang zu Sendrio ermoeglichen wollen – z.B. nach einem Datei-Upload direkt einen Login-Link mitsenden.

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"
  }'
Limits: Max. 5 Magic Links pro E-Mail-Adresse pro Stunde. Links sind standardmaessig 30 Minuten gueltig und koennen nur einmal verwendet werden.

Push-Token registrieren

POST /api/v1/push/register

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 optionalios oder android (Standard: ios)

Response (200)

{
  "registered": true,
  "platform": "ios"
}

Push-Token entfernen

DELETE /api/v1/push/unregister

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

POST /api/v1/auth/mobile

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.

Ablauf: Zuerst per 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
  }
}
Limits: Max. 5 Fehlversuche pro Code (danach neuen Code anfordern). Max. 10 Anfragen pro IP.

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'];