API PixHub
API-ul PixHub vă permite să încărcați, listați, inspectați și ștergeți fișiere în mod programatic, și să verificați statisticile de utilizare ale contului. Este un API JSON/REST simplu — nu necesită SDK, doar un client HTTP și o cheie API.
- URL de bază:
https://pixhub.ro/api - Format: JSON la intrare, JSON la ieșire (încărcările sunt
multipart/form-data) - Autentificare: o cheie API la fiecare cerere
Notă: deși această documentație este disponibilă în română, toate mesajele efective returnate de API (erori, validare) sunt întotdeauna în engleză, indiferent de limba interfeței site-ului — vezi secțiunea Erori.
Obținerea unei chei API
- Autentificați-vă pe pixhub.ro.
- Accesați pagina Cheie API din contul dvs. (
/cont/cheie-api). - Apăsați Generează cheie API și confirmați cu parola.
- Copiați cheia imediat — este afișată complet o singură dată. Regenerarea invalidează imediat cheia anterioară.
Autentificare
Trimiteți cheia în unul din cele două moduri:
X-Api-Key: CHEIA_DVS_API
GET https://pixhub.ro/api/stats?api_key=CHEIA_DVS_API
Header-ul este verificat primul; parametrul de interogare api_key este folosit doar dacă
header-ul lipsește. Tratați cheia API ca pe o parolă — oricine o deține poate acționa în
numele contului dvs. Fiecare cerere, reușită sau nu, este înregistrată (endpoint, metodă,
cod de răspuns, IP, moment) și vizibilă în graficul de utilizare de pe pagina Cheie API.
Opțional, un cont poate fi restricționat la o listă albă de IP-uri (IP-uri sau interval CIDR),
configurată pe aceeași pagină — cererile de la orice alt IP primesc 403.
Endpoint-uri
POST /api/upload — Încarcă un fișier
Încarcă un singur fișier pentru utilizatorul autentificat. Costă 10 unități din limita de rată (vezi Limitare cereri mai jos).
multipart/form-data cu un singur câmp:
| Câmp | Obligatoriu | Descriere |
|---|---|---|
file | da | Fișierul de încărcat. |
Tipuri acceptate: imagini JPEG, PNG, GIF, WebP; video MP4, WebM, QuickTime (MOV).
Dimensiune maximă: 200 MB implicit (configurabil pe server).
Răspuns — 201 Created:
{
"upload": {
"slug": "aB3xY9",
"title": null,
"url": "https://pixhub.ro/i/aB3xY9",
"direct_url": "https://pixhub.ro/i/aB3xY9.jpg",
"thumb_url": "https://pixhub.ro/t/aB3xY9",
"mime_type": "image/jpeg",
"size": 245678,
"views": 0,
"likes": 0,
"created_at": "2026-07-20T10:32:00+00:00"
}
}
GET /api/uploads — Listează fișierele proprii
Returnează o listă paginată a fișierelor utilizatorului autentificat, cele mai noi primele, 50 pe pagină.
| Parametru | În | Obligatoriu | Descriere |
|---|---|---|---|
page | query | nu | Numărul paginii, implicit 1. |
Răspuns — 200 OK (formatul standard de paginare Laravel):
{
"current_page": 1,
"data": [ { "slug": "aB3xY9", "...": "..." } ],
"first_page_url": "https://pixhub.ro/api/uploads?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "https://pixhub.ro/api/uploads?page=1",
"links": [ { "url": null, "label": "« Previous", "active": false } ],
"next_page_url": null,
"path": "https://pixhub.ro/api/uploads",
"per_page": 50,
"prev_page_url": null,
"to": 1,
"total": 1
}
GET /api/uploads/{slug} — Obține un fișier individual
Returnează detaliile unui fișier al utilizatorului autentificat.
Răspuns — 200 OK:
{ "upload": { "slug": "aB3xY9", "...": "..." } }
404 dacă niciun fișier cu acel slug nu există în contul dvs. (vezi Erori mai jos — răspunsurile
404 au un format diferit față de majoritatea celorlalte erori).
DELETE /api/uploads/{slug} — Șterge un fișier
Șterge definitiv unul dintre fișierele utilizatorului autentificat, inclusiv fișierul stocat și miniatura. Costă 3 unități din limita de rată. Această acțiune nu poate fi anulată.
Răspuns — 200 OK:
{ "deleted": true }
GET /api/stats — Statistici de utilizare a contului
{
"uploads": 42,
"albums": 5,
"total_views": 1337,
"api_requests": 980
}
| Câmp | Descriere |
|---|---|
uploads | Total fișiere încărcate în cont. |
albums | Total albume în cont. |
total_views | Suma vizualizărilor din feed și a celor directe pentru toate fișierele. |
api_requests | Total cereri API înregistrate pentru acest cont până acum — nu include cererea curentă, în desfășurare. |
Obiectul fișier
| Câmp | Tip | Descriere |
|---|---|---|
slug | string | Identificator unic al fișierului. |
title | string | null | Titlu setat de utilizator. |
url | string | Pagina fișierului pe PixHub. |
direct_url | string | Link direct către fișierul brut. |
thumb_url | string | null | Link miniatură — null dacă miniatura nu a fost încă generată. |
mime_type | string | Tipul MIME al fișierului. |
size | integer | Dimensiunea fișierului în octeți. |
views | integer | Total vizualizări (pagină + direct + embed). |
likes | integer | Număr de aprecieri. |
created_at | string | Data încărcării, format ISO 8601. |
Limitare cereri
Fiecare cont are limite independente pe minut, pe oră și pe zi, plus o fereastră scurtă de rafală — aplicate per cheie API, nu per IP.
| Interval | Limită implicită |
|---|---|
| Pe minut | 60 unități |
| Pe oră | 1.000 unități |
| Pe zi | 10.000 unități |
| Rafală (10 secunde) | 20 unități |
Majoritatea cererilor costă 1 unitate. Două costă mai mult:
| Endpoint | Cost |
|---|---|
POST /api/upload | 10 unități |
DELETE /api/uploads/{slug} | 3 unități |
| Restul | 1 unitate |
Fiecare răspuns reușit include:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 55
X-RateLimit-Reset: 1784540916
X-RateLimit-Cost: 1
Pe măsură ce utilizarea se apropie de 80% din limita pe minut, răspunsurile pot fi întârziate
ușor (până la 2 secunde) ca avertisment înainte de un 429 strict. Citiți X-RateLimit-Remaining
și reduceți ritmul înainte să ajungă la 0, și respectați Retry-After pe răspunsurile 429/503.
| Status | Corp răspuns | Când |
|---|---|---|
| 429 | {"error": "Burst limit exceeded. Slow down."} | Peste 20 unități în 10 secunde. |
| 429 | {"error": "Rate limit exceeded (per minute)."} | Limita pe minut depășită. |
| 429 | {"error": "Rate limit exceeded (per hour)."} | Limita pe oră depășită. |
| 429 | {"error": "Rate limit exceeded (per day)."} | Limita pe zi depășită. |
| 403 | {"error": "Access suspended by administrator."} (sau un motiv personalizat) | Suspendare specifică API-ului, nu o limită de cotă. |
| 503 | {"error": "API temporarily disabled."} | Întregul API este dezactivat temporar pe server. |
Erori
API-ul folosește două formate JSON diferite, în funcție de originea erorii — verificați codul de status înainte să presupuneți ce format ați primit.
Erori standard — eșecuri de autentificare, autorizare și limitare de rată:
{ "error": "Invalid API key." }
| Status | Semnificație |
|---|---|
| 401 | Cheie API lipsă sau invalidă. |
| 403 | Cont suspendat, IP absent din lista albă, sau altfel interzis. |
| 429 | Limită de rată depășită. |
| 503 | API dezactivat temporar pe server. |
404 Not Found folosește în schimb formatul implicit de excepție Laravel — observați că nu
există cheia error aici, iar mesajul poate include numele intern al modelului Eloquent:
{ "message": "No query results for model [App\\Models\\Upload]." }
422 Unprocessable Entity (eșecuri de validare la POST /api/upload) folosește de asemenea
formatul implicit Laravel. Mesajele sunt întotdeauna în engleză, indiferent de limba implicită
a site-ului — API-ul forțează limba engleză la fiecare cerere:
{
"message": "The file field is required.",
"errors": { "file": ["The file field is required."] }
}
Exemple în limbaje comune
Exemplele de mai jos acoperă cele două operații cele mai comune - încărcarea unui fișier și
listarea fișierelor proprii. Înlocuiți YOUR_API_KEY cu cheia dvs. reală.
curl
# Încarcă un fișier
curl -H "X-Api-Key: YOUR_API_KEY" \
-F "file=@/path/to/photo.jpg" \
https://pixhub.ro/api/upload
# Listează fișierele
curl -H "X-Api-Key: YOUR_API_KEY" "https://pixhub.ro/api/uploads?page=1"
# Șterge un fișier
curl -X DELETE -H "X-Api-Key: YOUR_API_KEY" https://pixhub.ro/api/uploads/aB3xY9
JavaScript (fetch)
const API_KEY = 'YOUR_API_KEY';
// Încarcă un fișier (input browser sau Node cu un Blob/File)
async function uploadFile(file) {
const form = new FormData();
form.append('file', file);
const res = await fetch('https://pixhub.ro/api/upload', {
method: 'POST',
headers: { 'X-Api-Key': API_KEY },
body: form,
});
if (!res.ok) throw new Error((await res.json()).error ?? (await res.json()).message);
const { upload } = await res.json();
return upload;
}
// Listează fișierele
async function listUploads(page = 1) {
const res = await fetch(`https://pixhub.ro/api/uploads?page=${page}`, {
headers: { 'X-Api-Key': API_KEY },
});
return res.json();
}
Python (requests)
import requests
API_KEY = "YOUR_API_KEY"
HEADERS = {"X-Api-Key": API_KEY}
# Încarcă un fișier
with open("/path/to/photo.jpg", "rb") as f:
res = requests.post(
"https://pixhub.ro/api/upload",
headers=HEADERS,
files={"file": f},
)
res.raise_for_status()
upload = res.json()["upload"]
# Listează fișierele
res = requests.get(
"https://pixhub.ro/api/uploads",
headers=HEADERS,
params={"page": 1},
)
uploads = res.json()
PHP (curl)
<?php
$apiKey = 'YOUR_API_KEY';
// Încarcă un fișier
$curl = curl_init('https://pixhub.ro/api/upload');
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["X-Api-Key: $apiKey"],
CURLOPT_POSTFIELDS => ['file' => new CURLFile('/path/to/photo.jpg')],
CURLOPT_RETURNTRANSFER => true,
]);
$upload = json_decode(curl_exec($curl), true)['upload'];
curl_close($curl);
// Listează fișierele
$curl = curl_init('https://pixhub.ro/api/uploads?page=1');
curl_setopt_array($curl, [
CURLOPT_HTTPHEADER => ["X-Api-Key: $apiKey"],
CURLOPT_RETURNTRANSFER => true,
]);
$uploads = json_decode(curl_exec($curl), true);
curl_close($curl);
Go (net/http)
package main
import (
"bytes"
"encoding/json"
"io"
"mime/multipart"
"net/http"
"os"
)
const apiKey = "YOUR_API_KEY"
func uploadFile(path string) (map[string]any, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("file", path)
io.Copy(part, file)
writer.Close()
req, _ := http.NewRequest("POST", "https://pixhub.ro/api/upload", body)
req.Header.Set("X-Api-Key", apiKey)
req.Header.Set("Content-Type", writer.FormDataContentType())
res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
var result map[string]any
json.NewDecoder(res.Body).Decode(&result)
return result, nil
}
func listUploads() (map[string]any, error) {
req, _ := http.NewRequest("GET", "https://pixhub.ro/api/uploads?page=1", nil)
req.Header.Set("X-Api-Key", apiKey)
res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
var result map[string]any
json.NewDecoder(res.Body).Decode(&result)
return result, nil
}