PixHub
API PixHub

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

  1. Autentificați-vă pe pixhub.ro.
  2. Accesați pagina Cheie API din contul dvs. (/cont/cheie-api).
  3. Apăsați Generează cheie API și confirmați cu parola.
  4. 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âmpObligatoriuDescriere
filedaFiș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ÎnObligatoriuDescriere
pagequerynuNumă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âmpDescriere
uploadsTotal fișiere încărcate în cont.
albumsTotal albume în cont.
total_viewsSuma vizualizărilor din feed și a celor directe pentru toate fișierele.
api_requestsTotal cereri API înregistrate pentru acest cont până acum — nu include cererea curentă, în desfășurare.

Obiectul fișier

CâmpTipDescriere
slugstringIdentificator unic al fișierului.
titlestring | nullTitlu setat de utilizator.
urlstringPagina fișierului pe PixHub.
direct_urlstringLink direct către fișierul brut.
thumb_urlstring | nullLink miniatură — null dacă miniatura nu a fost încă generată.
mime_typestringTipul MIME al fișierului.
sizeintegerDimensiunea fișierului în octeți.
viewsintegerTotal vizualizări (pagină + direct + embed).
likesintegerNumăr de aprecieri.
created_atstringData î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.

IntervalLimită implicită
Pe minut60 unități
Pe oră1.000 unități
Pe zi10.000 unități
Rafală (10 secunde)20 unități

Majoritatea cererilor costă 1 unitate. Două costă mai mult:

EndpointCost
POST /api/upload10 unități
DELETE /api/uploads/{slug}3 unități
Restul1 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.

StatusCorp răspunsCâ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." }
StatusSemnificație
401Cheie API lipsă sau invalidă.
403Cont suspendat, IP absent din lista albă, sau altfel interzis.
429Limită de rată depășită.
503API 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
}