Documentation StorageHub

Intégrez le stockage sécurisé de fichiers dans n'importe quelle application — site web, app mobile ou backend — en quelques minutes.

Base URL : https://storagehub.aiforge.world · Toutes les requêtes passent en HTTPS — TLS 1.3 obligatoire.

Quickstart — 3 étapes

1
Créez votre compte

Rendez-vous sur le dashboard ou appelez POST /v1/accounts/register. Vous recevez instantanément api_key + hmac_secret — à conserver en lieu sûr.

2
Configurez vos variables
STORAGE_BASE_URL=https://storagehub.aiforge.world
STORAGE_API_KEY=shk_…
STORAGE_HMAC_SECRET=…
3
Uploadez votre premier fichier

Choisissez votre plateforme ci-dessous — chaque exemple inclut la signature HMAC complète.

Authentification — signature HMAC-SHA256

Toutes les requêtes /v1/ exigent ces headers. En production, la signature est obligatoire.

HeaderDescription
X-API-KeyVotre clé publique shk_…
X-TimestampTimestamp Unix actuel (tolérance ±30 s, anti-rejeu)
X-SignatureHMAC_SHA256(hmac_secret, api_key + ":" + timestamp + ":" + sha256(body))
X-User-IdID de l'utilisateur final dans votre système (propriétaire du fichier)
X-User-Roleuser · admin · kyc_agent
Multipart : pour les uploads multipart/form-data, signez avec un corps vide : sha256(b""). Le body multipart n'est pas inclus dans la signature.
Ne signez jamais côté navigateur public. Pour un site web ou une app mobile, faites le upload via votre propre backend qui détient le secret — ou utilisez la route publique avatars en lecture seule.

Site web / JavaScript

Le front-end ne doit jamais connaître votre hmac_secret. Pattern recommandé : votre backend génère les headers signés, le navigateur uploade.

Option A — via votre backend (recommandé)

// 1) Votre backend appelle l'API avec HMAC et retourne l'URL publique
// 2) Le navigateur n'a besoin d'aucun secret

const form = new FormData();
form.append("avatar", fileInput.files[0]);

const res = await fetch("/api/my-backend/upload-avatar", {
  method: "POST", body: form });
const { url } = await res.json();
img.src = url; // https://storagehub.aiforge.world/v1/public/avatars/…

Option B — lire les avatars publics (aucun secret requis)

// Les avatars sont publics — pas d'auth nécessaire
<img src="https://storagehub.aiforge.world/v1/public/avatars/{file_id}"
     alt="avatar" />

Application mobile

Même règle : le secret HMAC vit sur votre serveur, pas dans l'APK. L'app appelle votre backend, qui relaie vers StorageHub.

React Native — upload via votre backend

const data = new FormData();
data.append("file", {
  uri: photo.uri, // camera roll / camera
  name: "avatar.jpg",
  type: "image/jpeg",
});
data.append("category", "avatars");

await fetch("https://api.votreapp.com/storage/upload", {
  method: "POST", body: data,
  headers: { "Content-Type": "multipart/form-data" },
});

Flutter (Dart)

final req = http.MultipartRequest(
  'POST', Uri.parse('https://api.votreapp.com/storage/upload'));
req.files.add(await http.MultipartFile.fromPath('file', path));
req.fields['category'] = 'avatars';
final res = await req.send();
Accès aux fichiers privés depuis le mobile : demandez une URL signée à votre backend (GET /v1/files/{id}/signed), puis chargez directement le lien — il expire automatiquement.

Backend serveur

Python — signature + upload complet

import hashlib, hmac, time, requests

BASE   = "https://storagehub.aiforge.world"
API_KEY    = "shk_…"
HMAC_SECRET = "…"

def headers(user_id="user-1", role="user", body=b""):
    ts  = str(int(time.time()))
    msg = f"{API_KEY}:{ts}:" + hashlib.sha256(body).hexdigest()
    sig = hmac.new(HMAC_SECRET.encode(), msg.encode(), hashlib.sha256).hexdigest()
    return {"X-API-Key": API_KEY, "X-Timestamp": ts,
            "X-Signature": sig, "X-User-Id": user_id,
            "X-User-Role": role}

# Upload (body signé = sha256(b"") pour multipart)
r = requests.post(BASE + "/v1/files", headers=headers(),
    files={"file": ("cni.pdf", open("cni.pdf", "rb"))},
    data={"category": "kyc"})
file_id = r.json()["file_id"]

# URL signée temporaire
r = requests.get(BASE + f"/v1/files/{file_id}/signed",
                 headers=headers(role="admin"))
signed_url = r.json()["signed_url"]  # expire selon le plan

Node.js

const crypto = require("crypto");
const BASE = "https://storagehub.aiforge.world";

function headers(userId, role = "user", body = Buffer.alloc(0)) {
  const ts = Math.floor(Date.now()/1000).toString();
  const bodyHash = crypto.createHash("sha256").update(body).digest("hex");
  const sig = crypto.createHmac("sha256", process.env.STORAGE_HMAC_SECRET)
    .update(`${process.env.STORAGE_API_KEY}:${ts}:${bodyHash}`).digest("hex");
  return { "X-API-Key": process.env.STORAGE_API_KEY,
    "X-Timestamp": ts, "X-Signature": sig,
    "X-User-Id": userId, "X-User-Role": role };
}

cURL — test rapide

# calculez sig = HMAC(secret, "KEY:TS:sha256(body)")
curl -X POST https://storagehub.aiforge.world/v1/files \
  -H "X-API-Key: shk_…" -H "X-Timestamp: $TS" \
  -H "X-Signature: $SIG" -H "X-User-Id: user-1" \
  -F "file=@avatar.png" -F "category=avatars"

SDK Django clé-en-main

Le module django_integration/storage_client.py gère la signature automatiquement :

from django_integration.storage_client import StorageClient

client = StorageClient(
    base_url="https://storagehub.aiforge.world",
    api_key=settings.STORAGE_API_KEY,
    hmac_secret=settings.STORAGE_HMAC_SECRET,
)

# Dans une vue
res = client.upload_avatar(request.FILES["avatar"],
                           owner_user_id=str(request.user.id))
profile.avatar_url = res["url"]

# Document sensible → lien temporaire
url = client.get_file_url(file_id, user_id=str(request.user.id), ttl=60)

Codes d'erreur

HTTPCasSolution
400Fichier vide, MIME non autorisé, exécutable, catégorie invalideVérifiez format et catégorie
401Header X-API-Key manquantAjoutez la clé
403Clé invalide/révoquée, signature HMAC incorrecte, accès refuséVérifiez signature & propriété du fichier
404Fichier introuvable ou suppriméVérifiez le file_id
413Fichier trop grand ou quota plan dépasséRéduisez la taille ou changez de plan
422Validation du formulaireChamps file + category requis

Référence des endpoints

MéthodeRouteDescription
POST/v1/accounts/registerCréer un compte → credentials API
POST/v1/accounts/loginSession JWT dashboard
GET/v1/accounts/meProfil + usage + clés
POST/v1/accounts/keysNouvelle clé API
DELETE/v1/accounts/keys/{id}Révoquer une clé
POST/v1/filesUpload (multipart: file, category, owner_user_id?)
GET/v1/filesLister les fichiers
GET/v1/files/{id}Stream authentifié
GET/v1/files/{id}/metaMétadonnées JSON
GET/v1/files/{id}/signedGénérer une URL signée
GET/v1/files/{id}/downloadDownload via URL signée
DELETE/v1/files/{id}Suppression logique
GET/v1/public/avatars/{id}Avatar public (sans auth)
GET/health · /v1/metricsMonitoring

Limites par plan

PlanStockageClés APITTL URL signée max
Gratuit500 MB160 s
Pro — 19€/mois50 GB35 min
Business — 79€/mois500 GB101 h
Quotas appliqués côté serveur à chaque upload. Changez de plan via POST /v1/accounts/plan ou le dashboard.