UploadCenter

Per iniziare

Da un account vuoto al tuo primo file caricato, in cinque passaggi.

Installa l'SDK
SDK ufficiali e completamente tipizzati per TypeScript/JavaScript (Node.js e browser) e Python. Ogni passaggio riportato di seguito mostra anche la richiesta cURL equivalente, nel caso in cui si preferisca richiamare direttamente l'API.
bash
npm install @uploadcenter/sdk-js
typescript
import { createClient } from "@uploadcenter/sdk-js";

const client = createClient({
  baseUrl: "https://api.uploadscenter.com",
  token: process.env.UPLOADCENTER_API_KEY, // an API key from your project settings
});

Ogni metodo viene generato dallo schema OpenAPI di UploadCenter, pertanto la funzione di completamento automatico copre l'intera superficie dell'API — visualizza il pacchetto JS su npm oppure il pacchetto Python su PyPI.

1
Crea un account
Al momento della registrazione, ti viene creato automaticamente uno spazio di lavoro (organizzazione).
2
Crea un progetto e una chiave API
Dalla tua dashboard: crea un progetto, quindi genera una chiave API associata a esso — la chiave completa viene visualizzata una sola volta, quindi copiala immediatamente.
3
Pre-firmare un caricamento
Richiedi all'API un URL pre-firmato: i file non passano mai attraverso il tuo backend.
bash
curl -X POST https://api.uploadscenter.com/v1/uploads/presign \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "project_...",
    "filename": "photo.jpg",
    "size_bytes": 128000,
    "mime_type": "image/jpeg",
    "visibility": "private"
  }'
4
Carica il file
SALVA il file direttamente all'indirizzo `upload_url` restituito: è proprio questo che rende veloci i caricamenti, indipendentemente dalle dimensioni.
bash
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: image/jpeg" \
  --data-binary @photo.jpg
5
Conferma il caricamento
È questo che avvia la scansione e l'elaborazione da parte dell'antivirus: il file non viene contrassegnato come pronto finché non supera il controllo.
bash
curl -X POST https://api.uploadscenter.com/v1/uploads/complete \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"file_id": "file_..."}'

Rilettura di un file — GET /v1/files/{file_id}/url — richiede sempre una chiave API o una sessione valida per i file privati. I file pubblici funzionano in modo diverso — vedi sotto.

URL pubblici
Carica con visibilità: "pubblica" e, una volta che il file è pronto, il campo URL corrisponde a un link permanente e non autenticato — sicuro da incorporare direttamente, memorizzato nella cache periferica, senza scadenza.
json
GET /v1/files/{file_id}

{
  "id": "file_...",
  "visibility": "public",
  "status": "ready",
  "url": "https://cdn.uploadscenter.com/o/…/photo.jpg"
}

I file privati (impostazione predefinita) non dispongono di un campo URL: utilizzare invece la chiamata GET /v1/files/{id}/url, che restituisce un nuovo link firmato valido per un periodo di tempo limitato.

Reagire agli eventi
Aggiungi un webhook dalle impostazioni del tuo progetto per ricevere notifiche in caso di caricamento, elaborazione ed eventi relativi alla quota. Ogni consegna è firmata: verifica la firma prima di considerare attendibile il contenuto.
http
POST <your webhook URL>
Content-Type: application/json
X-Signature: sha256=<hex-encoded HMAC-SHA256>
X-Timestamp: <unix timestamp, seconds>

{"event":"file.processed","created_at":"2026-01-01T12:00:00Z","data":{"id":"file_...","project_id":"project_...","status":"ready", ...}}

Eventi: file.uploaded, file.processed, file.failed, file.quarantined, file.flagged, storage.limit_reached. Sono previsti fino a 3 tentativi di consegna (con intervalli di 30 secondi, 2 minuti e 10 minuti) prima che una consegna venga contrassegnata come non riuscita.

typescript
import crypto from "node:crypto";

// Sign over "${timestamp}.${rawBody}" — rawBody must be the exact bytes
// received, not a re-serialized JSON.stringify(JSON.parse(rawBody)).
function verifyWebhook(rawBody: string, timestamp: string, signatureHeader: string, secret: string): boolean {
  const expected = crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
  const provided = signatureHeader.replace(/^sha256=/, "");
  return crypto.timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(provided, "hex"));
}

// signatureHeader = req.headers["x-signature"]
// timestamp       = req.headers["x-timestamp"]
Trasforma le immagini al volo
Ridimensiona, ritaglia e converti il formato tramite parametri di query: il risultato viene memorizzato nella cache dopo la prima richiesta e non viene ricalcolato ad ogni accesso.
http
GET /v1/files/{file_id}/transform?w=480&h=320&format=auto&fit=cover

# fit: "cover" (crop to fill) or "inside" (contain)
# format: auto (default) | webp | jpeg | png
# quality: auto (default) | 1-100
#
# format=auto picks WebP or JPEG based on the request's Accept header —
# no more branching client-side for older browsers. quality=auto applies
# a sensible per-format default (80 for WebP, 82 for JPEG). Pass explicit
# values any time you want full control instead.
Aggiungi una filigrana alle tue immagini
Sovrapponi il logo del tuo progetto a qualsiasi trasformazione: posizione, opacità e dimensioni sono completamente configurabili e il risultato viene memorizzato nella cache come qualsiasi altra trasformazione.
http
PUT /v1/projects/{project_id}/watermark
{"file_id": "file_..."}   # any image already uploaded to the project

GET /v1/files/{file_id}/transform?w=1200&watermark=true&gravity=south_east&opacity=60&overlay_scale=0.2

# gravity: north_west | north_east | south_west | south_east | center
# opacity: 1-100 (default 60)
# overlay_scale: 0.05-1.0 (default 0.2, fraction of the output image's width)
Domini personalizzati
Una volta verificata la titolarità tramite DNS, pubblica i file pubblici dal tuo dominio anziché dal CDN condiviso.
http
POST /v1/domains
{"project_id": "project_...", "hostname": "cdn.yourapp.com"}

# Add the returned TXT record at your DNS provider, then:
POST /v1/domains/{domain_id}/verify

# Once verified, point cdn.yourapp.com at UploadCenter (A/CNAME — shown in
# the dashboard) and a TLS certificate is issued automatically. From then
# on, every public file's url uses your domain instead of the shared CDN.
Moderazione dei contenuti
Le immagini caricate vengono automaticamente sottoposte a un controllo per individuare eventuali contenuti espliciti: si tratta solo di un rilevamento; nulla viene mai bloccato o eliminato per conto dell'utente.
json
GET /v1/files/{file_id}

{
  "id": "file_...",
  "status": "ready",
  "moderation_status": "flagged",  // null (not evaluated) | "clean" | "flagged" | "error"
  "moderation_score": 0.87
}

Un file contrassegnato rimane esattamente come è stato caricato: spetta alla tua app decidere cosa significhi "contrassegnato" per il tuo prodotto. Disponibile nei piani a pagamento; consulta la pagina delle funzionalità.

Miniature dei video e file derivati
Ogni video caricato riceve automaticamente una miniatura in formato JPEG; i video di dimensioni più ridotte vengono inoltre transcodificati in formato MP4 a 720p. L'URL specifico di ciascuna variante è pronto per l'uso immediato, senza bisogno di ulteriori passaggi di autenticazione.
json
GET /v1/files/{file_id}/variants

[
  { "variant": "thumbnail", "format": "jpg", "width": 640, "height": 360, "url": "https://…" },
  { "variant": "720p", "format": "mp4", "width": 1280, "height": 720, "url": "https://…" }
]
Generazione di immagini e video tramite intelligenza artificiale
Genera, modifica, rimuovi gli sfondi, ingrandisci o crea varianti di un'immagine; genera un video da un testo o da un'immagine esistente. Ogni chiamata è asincrona: invia un codice 202 con un ID di generazione, quindi esegui un poll o ascolta il webhook ai.generation.completed / ai.generation.failed.
typescript
const generation = await client.ai.generateImageEndpointV1AiImagesGeneratePost({
  project_id: projectId,
  prompt: "a minimalist logo of a fox, flat vector style",
  use_brand_kit: true, // pulls in this org's brand kit colors/fonts
});

// 202 Accepted — poll until it settles (or listen for the webhook below).
const result = await client.ai.getGenerationEndpointV1AiGenerationsGenerationIdGet(
  generation.id,
  projectId,
);
// result.file_ids — the new file(s), same shape as anything you upload

Il risultato è un file normale — denominato "file_ids" una volta completata la generazione — con le proprie impostazioni di visibilità, distribuzione e ciclo di vita, esattamente come qualsiasi altro file caricato direttamente.

Affidabilità, onestamente
UploadCenter è una piattaforma giovane e in fase di sviluppo attivo: non abbiamo anni di dati sulla disponibilità a cui fare riferimento e non inventeremo una cifra. Ecco cosa offriamo oggi: ogni file viene sottoposto a scansione antivirus prima ancora di essere reso disponibile, i caricamenti vengono elaborati in modo atomico (non rimane nulla a metà se un passaggio fallisce) e la distribuzione avviene sulla rete di Cloudflare. Non esiste ancora uno SLA formale: se il tuo caso d’uso richiede garanzie contrattuali, contattaci e discuteremo insieme di ciò che è realisticamente fattibile.

Vuoi avere un quadro completo della situazione?

Scopri tutte le funzionalità — gestione delle versioni, domini personalizzati, ruoli del team e altro ancora — nella pagina dedicata alle funzionalità.