Guida Integrazione Skuno per Sviluppatori E-commerce
Guida pratica per integrare il sistema di arricchimento prodotti Skuno nel tuo e-commerce.
🚀 Setup Rapido
1) Credenziali
Richiedi le credenziali di accesso:
- API Key: per autenticazione
- Tenant ID: identificativo del tuo account
- Base URL: endpoint del servizio
2) Autenticazione
Tutte le richieste richiedono header di autenticazione.
X-API-Key: YOUR_API_KEY
X-Tenant-ID: YOUR_TENANT_ID # Opzionale con API Key
Nota:
X-Tenant-IDè opzionale quando si usa l'autenticazione tramite API Key. Se non fornito, verrà usato automaticamente il tenant associato alla tua API Key.
📦 Inserimento Prodotti
Campi di Controllo Schema
Nello schema_override puoi utilizzare questi campi di controllo:
language(obbligatorio): Lingua per l'arricchimento (it,en,fr,de,es)require_images(opzionale):trueper richiedere ricerca automatica immaginiforce_enrichment(opzionale):trueper forzare l'arricchimento anche con barcode non validi
Prodotto Singolo
const response = await fetch(
"https://your-project-id.supabase.co/functions/v1/enrich-products",
{
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"X-Tenant-ID": "YOUR_TENANT_ID",
"Content-Type": "application/json",
},
body: JSON.stringify({
products: [{
barcode: "8001234567890",
callback_url: "https://your-domain.com/webhook/skuno",
schema_override: {
type: "object",
properties: {
language: "it",
require_images: false,
force_enrichment: false,
nome: { type: "string", description: "Nome completo del prodotto" },
marca: { type: "string", description: "Marca del prodotto" },
categoria: { type: "string", description: "Categoria del prodotto" },
materiale: { type: "string", description: "Materiale principale" },
colore: { type: "string", description: "Colore del prodotto" }
},
required: ["nome", "marca", "categoria"],
},
fields_to_create: ["nome", "marca", "categoria", "materiale", "colore"],
fields_to_enhance: ["descrizione", "prezzo"],
existing_data: { descrizione: "Scarpe da running", prezzo: "120.00 EUR" },
}],
}),
},
);
const result = await response.json();
console.log("Prodotti in coda:", result.queued_products);
Batch di Prodotti
Per inserire fino a 100 prodotti contemporaneamente, usa lo stesso endpoint enrich-products con un array:
const batchResponse = await fetch(
"https://your-project-id.supabase.co/functions/v1/enrich-products",
{
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"X-Tenant-ID": "YOUR_TENANT_ID",
"Content-Type": "application/json",
},
body: JSON.stringify({
products: [
{
barcode: "3017620422003",
callback_url: "https://your-domain.com/webhook/skuno",
schema_override: {
type: "object",
properties: {
language: "it",
require_images: true,
force_enrichment: false,
nome: { type: "string", description: "Nome completo del prodotto di make-up" },
marca: { type: "string", description: "Marca del prodotto" },
categoria: {
type: "string",
enum: ["fondotinta", "rossetto", "mascara", "ombretto", "blush", "correttore"],
description: "Categoria specifica del prodotto make-up",
},
tonalita: { type: "string", description: "Tonalità o colore del prodotto" },
formato: { type: "string", description: "Formato o dimensione del prodotto (es. 30ml, 15g)" },
},
required: ["language", "nome", "marca", "categoria"],
},
fields_to_create: ["nome", "marca", "categoria", "tonalita", "formato"],
fields_to_enhance: ["descrizione", "prezzo"],
existing_data: { descrizione: "Prodotto di make-up", prezzo: "Da verificare" },
},
{
barcode: "8001234567891",
callback_url: "https://your-domain.com/webhook/skuno",
schema_override: {
type: "object",
properties: {
language: "it",
nome: { type: "string", description: "Nome del prodotto alimentare" },
marca: { type: "string", description: "Marca del prodotto" },
categoria: { type: "string", description: "Categoria alimentare" },
ingredienti: { type: "array", items: { type: "string" }, description: "Lista ingredienti" },
},
required: ["language", "nome", "marca"],
},
fields_to_create: ["nome", "marca", "categoria", "ingredienti"],
fields_to_enhance: ["descrizione"],
existing_data: { descrizione: "Prodotto alimentare" },
},
],
}),
},
);
const batchResult = await batchResponse.json();
console.log("Prodotti in coda:", batchResult.queued_products);
📡 Webhook e Callback
Configurazione Webhook
Per ricevere notifiche quando i prodotti sono stati arricchiti:
app.post("/webhook/your-ecommerce-endpoint", (req, res) => {
const { event, product_id, enriched_data, batch_id } = req.body;
switch (event) {
case "product.enriched":
console.log(`Prodotto ${product_id} arricchito:`, enriched_data);
updateProductInDatabase(product_id, enriched_data);
break;
case "batch.completed":
console.log(`Batch ${batch_id} completato`);
break;
}
res.status(200).send("OK");
});
Verifica Firma Webhook
const crypto = require("crypto");
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return signature === expectedSignature;
}
app.post("/webhook/skuno", (req, res) => {
const signature = req.headers["x-webhook-signature"];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, YOUR_WEBHOOK_SECRET)) {
return res.status(401).send("Unauthorized");
}
});
📊 Monitoraggio
Stato Prodotti
const statusResponse = await fetch(
`https://your-project-id.supabase.co/functions/v1/product-status?product_id=${productId}`,
{
headers: {
"X-API-Key": "YOUR_API_KEY",
"X-Tenant-ID": "YOUR_TENANT_ID",
},
},
);
const status = await statusResponse.json();
console.log("Stato arricchimento:", status.enrichment_status);
Dashboard Statistiche
const dashboardResponse = await fetch(
"https://your-project-id.supabase.co/functions/v1/dashboard",
{
headers: {
"X-API-Key": "YOUR_API_KEY",
"X-Tenant-ID": "YOUR_TENANT_ID",
},
},
);
const stats = await dashboardResponse.json();
console.log("Prodotti totali:", stats.total_products);
console.log("Arricchimenti completati:", stats.enriched_products);
⚠️ Gestione Errori
Codici di Risposta
- 200: Successo
- 202: Richiesta accettata (processamento asincrono)
- 400: Dati non validi
- 401: Non autorizzato
- 404: Risorsa non trovata
- 429: Troppi tentativi
- 500: Errore del server
🔧 Configurazione Avanzata
Campi Personalizzati
Puoi specificare quali campi creare e arricchire:
{
"barcode": "PROD123",
"schema_override": {
"type": "object",
"properties": {
"nome": { "type": "string", "description": "Nome del prodotto" },
"materiale": { "type": "string", "description": "Materiale principale" },
"colore": { "type": "string", "description": "Colore del prodotto" },
"guida_taglie": { "type": "string", "description": "Guida alle taglie" }
},
"required": ["nome"]
},
"fields_to_create": ["nome", "materiale", "colore", "guida_taglie"],
"fields_to_enhance": ["descrizione"],
"existing_data": { "descrizione": "Scarpe da running" }
}
Rate Limiting
- Prodotti singoli: 100 richieste/minuto
- Batch: 10 richieste/minuto
- Sincronizzazione: 5 richieste/minuto
⚙️ Campi di Controllo
Callback URL
Il campo callback_url specifica l'endpoint dove ricevere le notifiche di completamento:
{
"barcode": "8001234567890",
"callback_url": "https://your-domain.com/webhook/skuno",
"schema_override": { /* ... */ }
}
Campi di Controllo Schema
All'interno dello schema_override, puoi utilizzare questi campi di controllo:
language: Lingua per l'arricchimento (es. "it", "en", "fr")require_images:trueper richiedere anche l'arricchimento delle immaginiforce_enrichment:trueper forzare l'arricchimento anche se già presente
🖼️ Gestione Immagini
Richiesta Immagini
Per richiedere anche l'arricchimento delle immagini, aggiungi require_images: true nello schema:
const response = await fetch(
"https://your-project-id.supabase.co/functions/v1/enrich-products",
{
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"X-Tenant-ID": "YOUR_TENANT_ID",
"Content-Type": "application/json",
},
body: JSON.stringify({
products: [{
barcode: "8001234567890",
schema_override: {
type: "object",
properties: {
language: "it",
require_images: true,
nome: { type: "string", description: "Nome completo del prodotto" },
immagini: {
type: "array",
items: {
type: "object",
properties: {
url: { type: "string" },
alt_text: { type: "string" },
tipo: { type: "string", enum: ["principale", "dettaglio", "lifestyle"] }
}
},
description: "Array di immagini del prodotto",
}
},
required: ["nome"],
},
fields_to_create: ["nome", "immagini"],
}],
}),
},
);
Webhook con Immagini
Quando le immagini sono pronte, riceverai una notifica separata:
app.post("/webhook/your-ecommerce-endpoint", (req, res) => {
const { event, product_id, enriched_data } = req.body;
switch (event) {
case "product.enriched":
console.log(`Prodotto ${product_id} arricchito:`, enriched_data);
break;
case "images.ready":
console.log(`Immagini per ${product_id} pronte:`, enriched_data.immagini);
// Scarica e salva le immagini nel tuo sistema
downloadAndSaveImages(product_id, enriched_data.immagini);
break;
}
res.status(200).send("OK");
});
Download Immagini
async function downloadAndSaveImages(productId, images) {
for (const image of images) {
try {
const response = await fetch(image.url);
const buffer = await response.arrayBuffer();
const filename = `${productId}_${image.tipo}_${Date.now()}.jpg`;
await saveImageToStorage(filename, Buffer.from(buffer));
await updateProductImage(productId, image.tipo, filename);
} catch (error) {
console.error(`Errore download immagine ${image.url}:`, error);
}
}
}
