API Reference 📚
Panoramica
L'API di Skuno fornisce endpoints RESTful per l'arricchimento e l'ottimizzazione dei dati dei prodotti. Tutte le richieste devono essere autenticate utilizzando una API Key.
Autenticazione
Il sistema utilizza l'autenticazione tramite API Key.
Header richiesti:
apikey: your_api_key_here
X-Tenant-ID: your_tenant_id # Opzionale
Nota: l'header X-Tenant-ID è opzionale. Se non fornito, verrà utilizzato automaticamente il tenant associato alla tua API Key.
Endpoints
Batch Processing di Prodotti
POST /functions/v1/products-batch
Nuovo endpoint principale per l'arricchimento di più prodotti contemporaneamente con sistema di callback.
Request Headers
Content-Type: application/json
apikey: your_api_key_here
Request Body
{
"callback_url": "https://your-domain.com/webhook/skuno",
"products": [
{
"barcode": "8001234567890",
"brand": "Nike",
"current_description": "Scarpe da running Air Max",
"schema_override": {
"type": "object",
"properties": {
"language": "it",
"product_name": {"type": "string"},
"description": {"type": "string"},
"brand": {"type": "string"}
},
"required": ["product_name", "brand"]
}
},
{
"barcode": "8001234567891",
"brand": "Adidas",
"current_description": "Maglietta sportiva Climacool",
"schema_override": {
"type": "object",
"properties": {
"language": "it",
"product_name": {"type": "string"},
"description": {"type": "string"},
"brand": {"type": "string"}
},
"required": ["product_name", "brand"]
}
}
]
}
Response
{
"success": true,
"batch_id": "b324448f-e99b-44c5-a9c6-566f880e1aa1",
"total_products": 2,
"created": 2,
"failed": 0,
"errors": [],
"message": "Batch processing completed. Created: 2, Failed: 0"
}
Importante: Riceverai una callback separata per ogni prodotto processato al callback_url specificato.
Callback Response
Quando l'arricchimento è completato, viene inviata una richiesta POST al callback_url specificato:
{
"status": "completed",
"batch_id": "batch_123",
"tenant_id": "tenant_456",
"processed_at": "2024-01-15T10:30:00Z",
"results": [
{
"barcode": "1234567890123",
"status": "success",
"enriched_data": {
"name": "Nome Prodotto Arricchito",
"description": "Descrizione dettagliata...",
"features": ["Feature 1", "Feature 2"],
"category": "Categoria",
"brand": "Brand"
},
"images": [
{
"image_url": "https://example.com/image1.jpg",
"thumbnail_url": "https://example.com/thumb1.jpg",
"title": "Titolo immagine",
"source_url": "https://source.com/page",
"width": 800,
"height": 600,
"is_primary": true,
"relevance_score": 8.5,
"quality_score": 9.0
}
],
"image_status": "completed",
"images_found": 3
}
]
}
Campi Immagini nel Callback
images: array delle immagini trovate per il prodottoimage_status: stato della ricerca immagini (completed,failed,no_images_found)images_found: numero totale di immagini trovate
Struttura oggetto immagine:
image_url: URL dell'immagine originalethumbnail_url: URL della miniatura (se disponibile)title: Titolo/descrizione dell'immaginesource_url: URL della pagina sorgentewidth/height: Dimensioni in pixelis_primary: indica se è l'immagine principalerelevance_score: Punteggio di rilevanza (0-10)quality_score: Punteggio di qualità (0-10)
Campo Language Obbligatorio
A partire da questa versione, il campo language è obbligatorio nello schema_override di ogni prodotto. Questo campo specifica la lingua in cui l'AI deve arricchire il prodotto.
Lingue supportate:
en- Inglesefr- Franceseit- Italianoes- Spagnolo
Esempio di utilizzo:
{
"schema_override": {
"type": "object",
"properties": {
"language": "fr",
"product_name": {"type": "string"},
"description": {"type": "string"},
"brand": {"type": "string"}
},
"required": ["language", "product_name", "brand"]
}
}
Nota: Se il campo language non viene specificato o contiene un valore non supportato, la richiesta verrà rifiutata con un errore di validazione.
Schema Override
Il campo schema_override permette di personalizzare lo schema di arricchimento per prodotto specifico:
{
"language": "it",
"require_images": true,
"fields": {
"description": {
"max_length": 500,
"style": "marketing"
},
"features": {
"format": "bullet_points",
"max_items": 5
}
}
}
Campi disponibili:
language(obbligatorio): Lingua per l'arricchimento (it,en,fr,de,es)require_images(opzionale): richiede ricerca automatica di immagini per il prodottofields: configurazione specifica per ogni campostyle: stile di scrittura (professional,marketing,technical)max_length: lunghezza massima del testo generatoformat: formato di output (paragraph,bullet_points,list)
Gestione Immagini
La ricerca di immagini viene attivata automaticamente quando:
- Esplicitamente richiesto:
require_images: true - Logica predefinita: il prodotto ha brand E descrizione
- Mai richiesto:
require_images: false
Le immagini trovate vengono salvate automaticamente e incluse nella risposta o nel callback.
Formato Oggetto Immagine
Ogni immagine restituita segue questa struttura:
| Campo | Tipo | Descrizione |
|-------|------|-------------|
| image_url | string | URL dell'immagine a risoluzione originale |
| thumbnail_url | string | URL della miniatura (se disponibile) |
| title | string | Titolo o descrizione dell'immagine |
| is_primary | boolean | true se l'immagine è considerata la principale |
| relevance_score | number | Punteggio (0-10) di attinenza al prodotto |
{
"image_url": "https://storage.skuno.xyz/images/prod_123.jpg",
"thumbnail_url": "https://storage.skuno.xyz/thumbs/prod_123.jpg",
"title": "Immagine Prodotto",
"is_primary": true,
"relevance_score": 9.5
}
Arricchimento Prodotto Singolo (Legacy)
POST /functions/v1/enrich-products
Request Body
{
"product": {
"id": "string",
"name": "string",
"description": "string",
"category": "string",
"attributes": {
"additional": "properties"
}
}
}
Response
{
"enriched_product": {
"id": "string",
"name": "string",
"enhanced_description": "string",
"tags": ["string"],
"marketing_suggestions": {
"title_suggestions": ["string"],
"description_suggestions": ["string"],
"keywords": ["string"]
},
"metadata": {
"confidence_score": 0.95,
"processing_time": "string"
}
}
}
Gestione Prodotti
Recupera Prodotto
GET /rest/v1/products?id=eq.{product_id}
Response
{
"id": "string",
"name": "string",
"description": "string",
"enriched_data": {
"enhanced_description": "string",
"tags": ["string"],
"marketing_suggestions": {}
},
"created_at": "timestamp",
"updated_at": "timestamp"
}
Lista Prodotti
GET /rest/v1/products?select=*
Parametri di Query:
limit: numero massimo di risultatioffset: offset per la paginazioneorder: campo e direzione dell'ordinamento
Gestione Tag
Genera Tag
POST /functions/v1/generate-tags
Request Body
{
"description": "string"
}
Response
{
"tags": ["string"],
"confidence_scores": {
"tag1": 0.95,
"tag2": 0.85
}
}
Gestione Errori
Codici di Stato
- 200: Successo
- 400: Richiesta non valida
- 401: Non autorizzato
- 403: Accesso negato
- 404: Risorsa non trovata
- 429: Troppe richieste
- 500: Errore interno del server
Formato Errori
{
"error": {
"code": "string",
"message": "string",
"details": {}
}
}
Rate Limiting
Le richieste sono limitate a:
- 100 richieste/minuto per utente autenticato
- 10 richieste/minuto per utente anonimo
Headers di risposta:
X-RateLimit-Limit: 100X-RateLimit-Remaining: 95X-RateLimit-Reset: 1620000000
Endpoint di Stato
Controllo Stato Prodotto
GET /functions/v1/product-status/{product_id}
Recupera lo stato di arricchimento di un prodotto specifico.
Headers
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
Response
{
"product_id": "uuid",
"enrichment_status": "completed",
"created_at": "2023-01-01T12:00:00Z",
"updated_at": "2023-01-01T12:30:00Z",
"enriched_fields": {
"description": "Descrizione arricchita",
"tags": ["tag1", "tag2"]
},
"progress": {
"total_fields": 10,
"enriched_fields": 8,
"percentage": 80
}
}
Lista Prodotti con Stato
GET /functions/v1/product-status
Recupera la lista dei prodotti con filtri di stato.
Parametri Query:
status: Filtra per stato di arricchimentolimit: Numero massimo di risultati (default: 50)offset: Offset per paginazione (default: 0)
Response
{
"products": [
{
"id": "uuid",
"name": "Nome Prodotto",
"enrichment_status": "completed",
"created_at": "2023-01-01T12:00:00Z",
"updated_at": "2023-01-01T12:30:00Z"
}
],
"pagination": {
"total": 100,
"limit": 50,
"offset": 0,
"has_more": true
}
}
Sistema di Notifiche
Invio Notifica
POST /functions/v1/notifications
Invia una notifica immediata o programmata.
Payload
{
"type": "email",
"recipient": "user@example.com",
"subject": "Arricchimento Completato",
"message": "Il tuo prodotto è stato arricchito con successo",
"tenant_id": "uuid",
"priority": "normal",
"scheduled_at": "2023-01-01T15:00:00Z",
"data": {
"product_id": "uuid",
"enrichment_details": {}
}
}
Tipi di Notifica
email: notifica via emailwebhook: chiamata webhook
Recupero Notifiche
GET /functions/v1/notifications
Recupera le notifiche inviate.
Parametri Query:
tenant_id: ID del tenant (obbligatorio)status: Filtra per stato (sent,failed,pending)type: Filtra per tipo di notificalimit: Numero massimo di risultatioffset: Offset per paginazione
Processamento Notifiche
POST /functions/v1/process-notifications- Processa le notifiche in coda (per uso interno/cron)
GET /functions/v1/process-notifications/stats- Recupera statistiche delle notifiche delle ultime 24 ore
Webhooks
Eventi Disponibili
product.enriched: quando un prodotto è stato arricchito (evento principale)product.failed: quando l'arricchimento di un prodotto fallisceerror.processing: quando si verifica un errore durante l'elaborazione
Nota: al momento non esiste un evento batch.completed. Ogni prodotto in un batch genera una callback product.enriched separata.
Formato Payload Webhook
{
"event": "product.enriched",
"batch_id": "b324448f-e99b-44c5-a9c6-566f880e1aa1",
"product_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2025-01-25T14:30:00.000Z",
"product": {
"barcode": "8001234567890",
"brand": "Nike",
"original_description": "Scarpe da running Air Max",
"enriched_description": "Scarpe da running Nike Air Max con tecnologia di ammortizzazione avanzata...",
"enriched_data": {
"tags": ["running", "sport", "scarpe", "nike", "air-max"],
"category": "Calzature Sportive",
"features": ["Ammortizzazione Air Max", "Tomaia traspirante"],
"confidence_score": 0.95
}
},
"processing_info": {
"started_at": "2025-01-25T14:29:45.000Z",
"completed_at": "2025-01-25T14:30:00.000Z",
"processing_time_ms": 15000
},
"data": {
"product_id": "string",
"status": "success",
"enriched_fields": {
"description": "Nuova descrizione",
"tags": ["tag1", "tag2"]
},
"details": {}
}
}
Sicurezza Webhook
Tutti i webhook includono un header X-Skuno-Signature con firma HMAC-SHA256 per verificare l'autenticità .
// Verifica della firma
import crypto from 'crypto'
const signature = request.headers['x-skuno-signature'] as string
const payload = JSON.stringify(request.body)
// Esempio: recupero del secret specifico per connessione
const { data: connection } = await supabase
.from('ecommerce_connections')
.select('webhook_secret')
.eq('id', connectionId)
.single()
const secret = connection?.webhook_secret
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex')
const isValid = signature === expectedSignature
Dashboard API
Ottieni Statistiche Dashboard
GET /dashboard
Headers:
Authorization: Bearer <token>
Response
{
"products": {
"total": 1000,
"enriched": 850,
"pending": 100,
"failed": 50,
"enrichment_rate": 85.0
},
"notifications": {
"total_sent": 500,
"pending": 10,
"failed": 5,
"success_rate": 97.0,
"by_type": {
"email": 300,
"webhook": 150
}
},
"queue": {
"pending_jobs": 25,
"processing_jobs": 5,
"failed_jobs": 2,
"avg_processing_time": 1500
},
"webhooks": {
"total_sent": 200,
"successful": 190,
"failed": 10,
"success_rate": 95.0
},
"system": {
"uptime": "5h 30m",
"active_connections": 15,
"last_updated": "2025-01-20T10:00:00Z"
}
}
Ottieni Log di Sistema
GET /dashboard/logs?limit=50
Headers:
Authorization: Bearer <token>
Parametri Query:
limit(opzionale): numero massimo di log da restituire (default: 50)
Response
{
"logs": [
{
"id": "uuid",
"level": "info",
"message": "Product enrichment completed",
"component": "enrichment",
"context": {
"product_id": "uuid",
"processing_time_ms": 1500
},
"created_at": "2025-01-20T10:00:00Z"
}
]
}
Ottieni Attività Recenti
GET /dashboard/activity?limit=20
Headers:
Authorization: Bearer <token>
Parametri Query:
limit(opzionale): numero massimo di attività da restituire (default: 20)
Response
{
"activities": [
{
"id": "uuid",
"action": "product_created",
"resource_type": "product",
"resource_id": "uuid",
"details": {
"product_name": "iPhone 15",
"category": "Electronics"
},
"user_id": "uuid",
"created_at": "2025-01-20T10:00:00Z"
}
]
}
Health Check
GET /dashboard/health
Response
{
"status": "healthy",
"timestamp": "2025-01-20T10:00:00Z",
"services": {
"database": "healthy",
"queue": "healthy",
"notifications": "healthy"
}
}
Best Practices
Gestione degli Errori
- Implementare retry con backoff esponenziale
- Gestire gracefully i timeout
- Loggare gli errori per il debugging
Performance
- Utilizzare la paginazione per grandi dataset
- Implementare caching lato client
- Minimizzare il payload delle richieste
Sicurezza
- Utilizzare sempre HTTPS
- Validare tutti gli input
- Implementare timeout appropriati
