Public API
This page extends the OpenAPI UI with ready-to-use requests, example responses, and notes about stable image URLs.
Schnellstart
These four endpoints are enough for most integrations.
Liefert Profil, Limits und Nutzungswerte des Users.
Erstellt Upload-URL, Token und maximale Dateigröße.
Zeigt, ob die Verarbeitung abgeschlossen oder fehlgeschlagen ist.
Liefert die finalen Bild- und Varianten-URLs.
1) Authentifizierung
Erstelle zuerst in den Benutzereinstellungen einen API-Schlüssel und sende ihn pro Request im Header X-API-Key.
export BASE_URL="https://pixelfox.cc"
export API_KEY="DEIN_API_KEY"
curl -sS "$BASE_URL/api/v1/user/profile" \
-H "X-API-Key: $API_KEY" | jqAlternative Header-Variante: Authorization: Bearer DEIN_API_KEY.
2) Upload-Session erzeugen
Vor jedem Upload wird ein zeitlich begrenztes Token ausgestellt. Zusätzlich kannst du pro Upload festlegen, welche Derivate erzeugt werden sollen. Das Original bleibt immer erhalten. Mit album_id kannst du den Upload direkt in ein bestehendes eigenes Album einsortieren. Mit is_nsfw markierst du den Upload als sensiblen Inhalt. Mit is_ai_generated kennzeichnest du ihn als KI-generiert.
export FILE="./beispiel.jpg"
export FILE_SIZE=$(wc -c < "$FILE")
export ALBUM_ID=42
SESSION_JSON=$(curl -sS -X POST "$BASE_URL/api/v1/upload/sessions" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-d "{
\"file_size\": $FILE_SIZE,
\"album_id\": $ALBUM_ID,
\"is_nsfw\": true,
\"is_ai_generated\": true,
\"processing\": {
\"profile\": \"custom\",
\"derivatives\": [
{ \"family\": \"webp\", \"size\": \"small\" },
{ \"family\": \"avif\", \"size\": \"small\" }
]
}
}")
echo "$SESSION_JSON" | jq
UPLOAD_URL=$(echo "$SESSION_JSON" | jq -r '.upload_url')
UPLOAD_TOKEN=$(echo "$SESSION_JSON" | jq -r '.token')Lasse processing weg, wenn du die aktuellen User-Defaults verwenden willst. Mit profile=original_only wird nur das Original gespeichert. Lasse album_id weg, wenn der Upload keinem Album zugeordnet werden soll. Lasse is_nsfw weg, um den NSFW-Default aus deinen Einstellungen zu verwenden, oder setze es explizit auf false bzw. true für diesen Upload. is_ai_generated funktioniert genauso mit dem KI-Default.
Processing-Profile
| Profile | Verhalten |
|---|---|
| default | Uses the current user defaults from settings and freezes them for this exact upload session. |
| original_only | Stores only the uploaded original. No additional WebP, AVIF, or original thumbnails are generated. |
| custom | Erzeugt exakt die in derivatives angeforderten Derivate, sofern Plan und Admin-Settings sie erlauben. |
// Gleichbedeutend mit den aktuellen User-Defaults
{ "file_size": 1837421 }
// In ein bestehendes Album hochladen
{
"file_size": 1837421,
"album_id": 42,
"is_nsfw": true,
"is_ai_generated": true
}
// Nur das Original behalten
{
"file_size": 1837421,
"processing": {
"profile": "original_only"
}
}
// Exakt kleine WebP- und AVIF-Varianten anfordern
{
"file_size": 1837421,
"processing": {
"profile": "custom",
"derivatives": [
{ "family": "webp", "size": "small" },
{ "family": "avif", "size": "small" }
]
}
}In Antworten kann bei älteren Bildern zusätzlich profile=legacy auftauchen. Das ist nur ein Rückwärtskompatibilitätswert für Uploads vor der neuen per-Request-Policy.
3) Bild hochladen und Resource abrufen
Lade die Datei per Multipart-Form an die upload_url aus Schritt 2 hoch. Anschließend prüfst du den Status und holst dir die finale Resource.
UPLOAD_RESULT=$(curl -sS -X POST "$UPLOAD_URL" \
-H "Authorization: Bearer $UPLOAD_TOKEN" \
-F "file=@$FILE")
echo "$UPLOAD_RESULT" | jq
IMAGE_UUID=$(echo "$UPLOAD_RESULT" | jq -r '.image_uuid')
curl -sS "$BASE_URL/api/v1/images/$IMAGE_UUID/status" \
-H "X-API-Key: $API_KEY" | jq
curl -sS "$BASE_URL/api/v1/images/$IMAGE_UUID" \
-H "X-API-Key: $API_KEY" | jqWiederhole den Status-Request, bis complete=true und failed=false zurückkommt.
Immediately after upload, often only the original file and some variants are available. Additional derivatives are generated asynchronously.
Beispiel: GET /api/v1/user/profile
{
"id": 42,
"username": "pixelpete",
"email": "[email protected]",
"status": "active",
"plan": "premium",
"created_at": "2026-03-16T08:30:00Z",
"last_login_at": "2026-03-16T09:12:44Z",
"api_key_last_used_at": "2026-03-16T09:15:02Z",
"stats": {
"images": {
"count": 128,
"storage_used_bytes": 734003200,
"storage_remaining_bytes": 2415919104
},
"albums": {
"count": 7
}
},
"limits": {
"max_upload_bytes": 52428800,
"storage_quota_bytes": 3149926400,
"can_multi_upload": true,
"image_upload_enabled": true,
"direct_upload_enabled": true,
"allowed_thumbnail_formats": ["original", "webp", "avif"]
},
"preferences": {
"upload_nsfw_by_default": false,
"upload_ai_generated_by_default": false,
"thumbnail_original": true,
"thumbnail_webp": true,
"thumbnail_avif": true
}
}Account-Daten, Limits und aktuelle Nutzung des authentifizierten Users.
Beispiel: POST /api/v1/upload/sessions
{
"upload_url": "https://pixelfox.cc/api/v1/upload",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"pool_id": 2,
"album_id": 42,
"is_nsfw": true,
"is_ai_generated": true,
"expires_at": 1773655200,
"max_bytes": 52428800,
"processing": {
"profile": "custom",
"keep_original": true,
"derivatives": [
{ "family": "webp", "size": "small" },
{ "family": "avif", "size": "small" }
]
}
}Das Token ist nur kurz gültig, auf die Dateigröße begrenzt und trägt die konkrete Processing-Policy dieser Session. Wenn album_id zurückkommt, ist die Session an dieses Album gebunden. is_nsfw zeigt an, ob der Upload als sensibel markiert wurde. is_ai_generated zeigt die KI-Markierung.
Ist das Speicherkontingent voll, antworten Session und direkter Upload mit 413 und quota_exceeded. Gezählt werden Originaldateien und erzeugte Varianten. Die Antwort nennt freien Rest, benötigte Größe und das aktuelle Kontingent. Free sieht darin Premium mit 200 GB und Premium Max mit 1000 GB, Premium nur noch Premium Max.
Beispiel: Upload-Antwort
{
"image_uuid": "fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8",
"view_url": "/i/a1b2c3d4e5f6g7h8",
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/original/original.jpg",
"stable_url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/original/original.jpg",
"storage_url": "https://cdn.pixelfox.cc/uploads/original/2026/03/16/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8.jpg",
"is_nsfw": true,
"is_ai_generated": true,
"available_variants": ["original"],
"processing": {
"profile": "custom",
"keep_original": true,
"derivatives": [
{ "family": "webp", "size": "small" },
{ "family": "avif", "size": "small" }
]
},
"variants": {
"original": {
"original": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/original/original.jpg"
}
}
},
"stable_variants": {
"original": {
"original": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/original/original.jpg",
"ready": true
}
},
"webp": {
"small": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/webp/small.webp",
"ready": false
}
},
"avif": {
"small": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/avif/small.avif",
"ready": false
}
}
},
"planned_variants": ["original", "webp", "avif"],
"duplicate": false
}Direkt nach dem Upload ist die Resource bereits adressierbar. Fertige Varianten erscheinen schrittweise in variants.
Beispiel: Status und finale Image-Resource
// GET /api/v1/images/{uuid}/status
{
"complete": true,
"failed": false,
"view_url": "/i/a1b2c3d4e5f6g7h8"
}
// GET /api/v1/images/{uuid}
{
"image_uuid": "fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8",
"view_url": "/i/a1b2c3d4e5f6g7h8",
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/original/original.jpg",
"stable_url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/original/original.jpg",
"storage_url": "https://cdn.pixelfox.cc/uploads/original/2026/03/16/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8.jpg",
"is_nsfw": true,
"is_ai_generated": true,
"available_variants": ["original", "webp", "avif"],
"processing": {
"profile": "custom",
"keep_original": true,
"derivatives": [
{ "family": "webp", "size": "small" },
{ "family": "avif", "size": "small" }
]
},
"variants": {
"original": {
"original": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/original/original.jpg"
}
},
"webp": {
"small": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/webp/small.webp"
}
},
"avif": {
"small": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/avif/small.avif"
}
}
},
"stable_variants": {
"original": {
"original": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/original/original.jpg",
"ready": true
},
"medium": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/original/medium.jpg",
"ready": true
},
"small": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/original/small.jpg",
"ready": true
}
},
"webp": {
"original": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/webp/original.webp",
"ready": true
},
"medium": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/webp/medium.webp",
"ready": true
},
"small": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/webp/small.webp",
"ready": true
}
},
"avif": {
"medium": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/avif/medium.avif",
"ready": false
},
"small": {
"url": "https://pixelfox.cc/f/fd6b0a44-c4bb-4c95-8f48-31d5ec9cc4d8/avif/small.avif",
"ready": false
}
}
},
"planned_variants": ["original", "webp", "avif"]
}/status ist bewusst klein gehalten. Für alle fertigen URLs und Varianten verwendest du danach GET /api/v1/images/{uuid}.
PHP Beispiele
For simple server integrations, the PHP cURL extension is enough. The first example shows an authenticated JSON request, the second the full upload flow.
GET /api/v1/user/profile
<?php
$baseUrl = 'https://pixelfox.cc';
$apiKey = 'DEIN_API_KEY';
$ch = curl_init($baseUrl . '/api/v1/user/profile');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Accept: application/json',
'X-API-Key: ' . $apiKey,
],
]);
$raw = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($status !== 200) {
throw new RuntimeException('API request failed: ' . $raw);
}
$profile = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
echo $profile['username'] . PHP_EOL;
echo $profile['limits']['max_upload_bytes'] . PHP_EOL;Upload Flow mit Status-Polling
<?php
$baseUrl = 'https://pixelfox.cc';
$apiKey = 'DEIN_API_KEY';
$file = __DIR__ . '/beispiel.jpg';
function apiJson(string $method, string $url, string $apiKey, ?array $payload = null): array
{
$headers = [
'Accept: application/json',
'X-API-Key: ' . $apiKey,
];
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
]);
if ($payload !== null) {
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload, JSON_THROW_ON_ERROR));
}
$raw = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
return [
'status' => $status,
'body' => json_decode($raw, true, 512, JSON_THROW_ON_ERROR),
];
}
$session = apiJson('POST', $baseUrl . '/api/v1/upload/sessions', $apiKey, [
'file_size' => filesize($file),
'album_id' => 42,
'is_nsfw' => true,
'is_ai_generated' => true,
]);
$upload = curl_init($session['body']['upload_url']);
curl_setopt_array($upload, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $session['body']['token'],
],
CURLOPT_POSTFIELDS => [
'file' => new CURLFile($file),
],
]);
$uploadRaw = curl_exec($upload);
curl_close($upload);
$uploadResult = json_decode($uploadRaw, true, 512, JSON_THROW_ON_ERROR);
$imageUuid = $uploadResult['image_uuid'];
do {
sleep(1);
$status = apiJson('GET', $baseUrl . '/api/v1/images/' . $imageUuid . '/status', $apiKey);
} while (!$status['body']['complete'] && !$status['body']['failed']);
if ($status['body']['failed']) {
throw new RuntimeException('Image processing failed');
}
$image = apiJson('GET', $baseUrl . '/api/v1/images/' . $imageUuid, $apiKey);
echo $image['body']['url'] . PHP_EOL;Konsistente Bild-URLs verstehen
PIXELFOX.CC intentionally returns two URL types. You can use stable public links or directly access the current storage address.
| Feld | Bedeutung |
|---|---|
| view_url | Relative URL zur HTML-Ansicht der Bildseite, zum Beispiel /i/abc123.... |
| url | Primäre öffentliche Bild-URL. In der Regel identisch zu stable_url und für Embeds, Hotlinks und API-Consumer die beste Standardwahl. |
| stable_url | Stabile /f/{uuid}/...-Adresse. Diese URL bleibt konsistent, auch wenn sich die interne Storage-Struktur oder das Zielsystem später ändert. |
| variants | Only the currently ready variants with stable public URLs. |
| processing | Die effektive Processing-Policy dieses Uploads. Dort siehst du, ob der Upload mit default, original_only or custom erstellt wurde und welche Derivate konkret dazugehören. |
| stable_variants | Vorhersagbare stabile Variant-URLs inklusive ready-Flag. Damit kannst du feste URLs vorhalten und trotzdem erkennen, ob die Datei schon existiert. |
| storage_url | Direkte aktuelle Storage-URL der Originaldatei. Praktisch für Debugging oder interne Tools, aber weniger zukunftssicher als stable_url. |
| storage_variants | Direkte Storage-URLs aller bereits erzeugten Varianten. Gleiches Prinzip wie storage_url. |
| planned_variants | Which variant families are generally intended for this image according to the stored processing policy. |
Recommendation for integrations
Verwende standardmäßig url oder die Einträge aus variants. Wenn du mit noch nicht fertigen Derivaten planst, nimm stable_variants und prüfe das jeweilige ready-Flag.
Wichtiger Unterschied
/f/... ist eine stabile öffentliche Adresse, die auf die aktuelle Datei weiterleitet. /uploads/... oder CDN-Pfade können sich dagegen mit Storage-Pools, Migrationen oder künftigen Infrastruktur-Änderungen ändern.
