Documentazione partner
Tutto ciò che serve per pubblicare i tuoi annunci di vendita e ritiro su QuizzBuy e per notificarci gli ordini attribuiti al nostro traffico.
1. Ottenere una chiave API
Contatta il tuo referente QuizzBuy (o il modulo di contatto). Generiamo per te una chiave nel formato zzb_live_… — ti viene comunicata una sola volta, conservala in un luogo sicuro. Includila in ogni richiesta nell'header HTTP:
Authorization: Bearer zzb_live_VOTRE_CLE2. Verificare la tua chiave
curl https://quizzbuy.com/api/v1/me \
-H "Authorization: Bearer zzb_live_VOTRE_CLE"
# Réponse
{
"company": { "id": "…", "name": "Votre société", "slug": "votre-societe" },
"commission_rate": 0.05,
"click_param": "zzb_click"
}3. Pubblicare i tuoi annunci
Un annuncio è un'offerta di ritiro (BUYBACK — ritiri un dispositivo a un prezzo dato) oppure un'offerta di vendita (SALE — un prodotto ricondizionato che vendi). L'invio è un upsert: reinviare lo stesso externalId aggiorna l'annuncio.
curl -X POST https://quizzbuy.com/api/v1/listings \
-H "Authorization: Bearer zzb_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{
"externalId": "ref-interne-123",
"type": "BUYBACK",
"title": "Reprise iPhone 15 Pro 256 Go",
"brand": "Apple",
"model": "iPhone 15 Pro",
"category": "SMARTPHONE",
"storage": "256 GB",
"condition": "GOOD",
"priceCents": 52000,
"currency": "EUR",
"url": "https://votre-site.fr/reprise/iphone-15-pro",
"country": "FR"
}'category: SMARTPHONE, LAPTOP, SMARTWATCH, AUDIO o GAMING.condition: LIKE_NEW, EXCELLENT, GOOD, FAIR o BROKEN.priceCents: prezzo in centesimi (52000 = 520 €).- Ogni nuovo annuncio (o modifica) passa in moderazione prima della pubblicazione.
Aggiornare, elencare o disattivare:
# Lister vos annonces
curl "https://quizzbuy.com/api/v1/listings?type=BUYBACK&status=APPROVED" \
-H "Authorization: Bearer zzb_live_VOTRE_CLE"
# Mise à jour partielle
curl -X PATCH https://quizzbuy.com/api/v1/listings/ID_ANNONCE \
-H "Authorization: Bearer zzb_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "priceCents": 49000 }'
# Désactiver (soft delete)
curl -X DELETE https://quizzbuy.com/api/v1/listings/ID_ANNONCE \
-H "Authorization: Bearer zzb_live_VOTRE_CLE"4. Tracking dei clic
Quando un visitatore QuizzBuy clicca verso il tuo sito, l'URL di arrivo contiene un identificatore di clic:
https://votre-site.fr/vendre?zzb_click=6f1e0c9a-3b2d-4e8f-9a10-abcdef123456Memorizza questo valore (cookie o sessione lato tuo sito, durata consigliata: 45 giorni). È questo valore che consentirà di attribuire l'ordine. Il nome del parametro (zzb_click di default) è configurabile su richiesta.
5. Notificare un ordine (postback S2S)
Non appena un cliente effettua un ordine (acquisto o richiesta di ritiro convalidata) e disponi di uno zzb_click, chiama il nostro postback dal tuo server:
curl -X POST https://quizzbuy.com/api/v1/postback \
-H "Authorization: Bearer zzb_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{
"click_id": "6f1e0c9a-3b2d-4e8f-9a10-abcdef123456",
"type": "BUYBACK",
"amount_cents": 52000,
"currency": "EUR",
"order_ref": "CMD-2026-000123"
}'
# Réponse 201
{ "conversion_id": "…", "status": "TO_INVOICE", "commission_cents": 2600 }- Finestra di attribuzione: 45 giorni dopo il clic; oltre, risposta
422 attribution_window_expired. order_refdeve essere univoco: un duplicato restituisce409 duplicate_order_ref(idempotenza — puoi riprovare senza rischi).type:SALEper un acquisto,BUYBACKper un ritiro.currency: solo EUR — qualsiasi altra valuta viene rifiutata (422 unsupported_currency).
6. Testare in sandbox
Aggiungi "test": true al postback: la richiesta viene interamente validata (chiave, click_id, finestra di 45 giorni) ma nessuna conversione viene registrata o fatturata.
{ "click_id": "…", "type": "SALE", "amount_cents": 10000, "order_ref": "TEST-1", "test": true }
# → 200 { "test": true, "valid": true, "commission_cents": 500 }7. Codici di errore
| Codice | Errore | Spiegazione |
|---|---|---|
| 400 | invalid_input | Corpo della richiesta non valido (dettagli nella risposta). |
| 401 | unauthorized | Chiave API assente, revocata o non valida. |
| 404 | click_not_found / not_found | click_id o annuncio sconosciuto (o non tuo). |
| 409 | duplicate_order_ref | Ordine già notificato. |
| 422 | attribution_window_expired | Clic risalente a più di 45 giorni fa. |
| 429 | rate_limited | Troppe richieste — riprova tra un minuto. |
8. Fatturazione
Ogni conversione attribuita genera una commissione (tasso contrattuale, visibile tramite /api/v1/me). QuizzBuy ti invia una fattura riepilogativa periodica delle conversioni convalidate. Per qualsiasi domanda: contattaci.
9. Marketplace — vendere su QuizzBuy
Gli annunci SALE con una quantity > 0 vengono venduti direttamente su QuizzBuy (pagamento del cliente presso di noi, riversamento del netto di commissione). Campi aggiuntivi: quantity (stock), color, grade (A/B/C), batteryHealth (%), warrantyMonths. L'annuncio viene collegato automaticamente alla scheda prodotto corrispondente (marca + modello + capacità + colore).
# Mettre à jour le stock (sans re-modération)
curl -X PATCH https://quizzbuy.com/api/v1/listings/ID_ANNONCE/stock \
-H "Authorization: Bearer zzb_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "quantity": 12 }'
# Ajouter une photo (multipart, max 5 × 5 Mo, jpeg/png/webp)
curl -X POST https://quizzbuy.com/api/v1/listings/ID_ANNONCE/images \
-H "Authorization: Bearer zzb_live_VOTRE_CLE" \
-F "file=@photo.jpg"10. Webhook — essere avvisati delle vendite
Registra un endpoint HTTPS; ti notifichiamo a ogni fase di un ordine contenente i tuoi prodotti (order.created, order.paid, order.cancelled). Il secret viene restituito solo alla creazione — memorizzalo.
curl -X POST https://quizzbuy.com/api/v1/webhooks \
-H "Authorization: Bearer zzb_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "url": "https://votre-site.fr/webhooks/quizzbuy", "events": ["order.paid"] }'
# Réponse (secret affiché une seule fois)
{ "webhook": { "id": "…", "secret": "whsec_…", "events": ["order.paid"] } }
# Tester
curl -X POST https://quizzbuy.com/api/v1/webhooks/ID_WEBHOOK/test \
-H "Authorization: Bearer zzb_live_VOTRE_CLE"Ogni consegna è firmata. Verifica l'header X-ZZbuy-Signature (t=timestamp,v1=hex):
// Node.js
const [t, v1] = signature.split(",").map((p) => p.split("=")[1]);
const expected = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(`${t}.${rawBody}`)
.digest("hex");
const valid =
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1)) &&
Math.abs(Date.now() / 1000 - Number(t)) < 300; // anti-replay 5 minIn caso di errore (≠ 2xx), riproviamo con backoff: 1 min, 5 min, 30 min, 2 h, 12 h. Ricevi anche un'email di notifica di vendita.
11. Gestire i tuoi ordini
Elenca le righe dei tuoi ordini, conferma la ricezione e poi spedisci con un numero di tracking (il cliente viene notificato automaticamente). L'indirizzo di consegna è visibile solo dopo il pagamento.
# Lister les commandes à traiter
curl "https://quizzbuy.com/api/v1/orders?status=PENDING" \
-H "Authorization: Bearer zzb_live_VOTRE_CLE"
# Accuser réception
curl -X POST https://quizzbuy.com/api/v1/orders/ID_LIGNE/ack \
-H "Authorization: Bearer zzb_live_VOTRE_CLE"
# Expédier
curl -X POST https://quizzbuy.com/api/v1/orders/ID_LIGNE/ship \
-H "Authorization: Bearer zzb_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "carrier": "Colissimo", "trackingNumber": "6A123456789FR" }'12. Reprise gestita (trade-in)
La reprise gestita va oltre il semplice ritiro tramite reindirizzamento: il privato invia il proprio dispositivo da QuizzBuy, e tu gestisci l'intera pratica tramite l'API (accettazione, ricezione, controproposta, pagamento). Il prezzo mostrato al cliente è bloccato al momento dell'invio in base alla tua griglia di ritiro (vedi §14); puoi rivederlo al ribasso solo dopo la ricezione tramite una controproposta motivata.
Tutti gli endpoint si autenticano con la tua chiave API (Authorization: Bearer zzb_live_…) e restituiscono solo le tue pratiche.
Ciclo di vita
SUBMITTED → ACCEPTED → SHIPPED → RECEIVED → PAID. Due diramazioni: REJECTED (rifiuto prima dell'invio) e COUNTER_OFFER (controproposta dopo l'ispezione, che il privato accetta — poi PAID — o rifiuta — restituzione del dispositivo, CANCELLED).
| Stato | Significato |
|---|---|
| SUBMITTED | Richiesta creata dal privato, in attesa della tua decisione. |
| ACCEPTED | Hai confermato il ritiro; il cliente deve spedire il dispositivo. |
| SHIPPED | Il privato ha inserito il proprio numero di tracking. |
| RECEIVED | Hai ricevuto il dispositivo; ispezione in corso. |
| COUNTER_OFFER | Dopo l'ispezione, proponi un importo rivisto (inferiore). |
| PAID | Pagamento effettuato al privato — pratica chiusa. |
| REJECTED | Richiesta rifiutata prima dell'invio (non idoneo, frode…). |
| CANCELLED | Annullata (rifiuto di una controproposta, restituzione del dispositivo). |
Elencare e consultare
# Lister vos reprises (plus récentes d'abord)
curl "https://quizzbuy.com/api/v1/trade-ins?status=SUBMITTED&limit=50&offset=0" \
-H "Authorization: Bearer zzb_live_VOTRE_CLE"
# Réponse
{
"total": 3,
"trade_ins": [
{
"trade_in_id": "…",
"reference": "TI-2026-000042",
"status": "SUBMITTED",
"device": {
"brand": "Apple", "category": "SMARTPHONE", "model": "iPhone 15 Pro",
"storage": "256 GB", "condition": "GOOD",
"functional_status": "FULLY_WORKING", "battery_health": 92, "imei": "…"
},
"offer_cents": 52000,
"currency": "EUR",
"price_locked_until": "2026-08-05T12:00:00.000Z",
"country": "FR",
"customer": { "email": "…", "first_name": "…", "last_name": "…", "locale": "fr" },
"comment": null,
"counter_offer_cents": null, "counter_reason": null,
"tracking_carrier": null, "tracking_number": null,
"shipping_label_url": null, "payout_ref": null,
"accepted_at": null, "shipped_at": null, "received_at": null,
"paid_at": null, "cancelled_at": null,
"created_at": "2026-07-21T12:00:00.000Z"
}
]
}
# Détail d'une reprise
curl https://quizzbuy.com/api/v1/trade-ins/ID_REPRISE \
-H "Authorization: Bearer zzb_live_VOTRE_CLE"
# → { "trade_in": { … } }status(filtro facoltativo): un valore della tabella qui sopra — altrimenti400 invalid_status.limit: max 200 (default 50);offsetper la paginazione.- Il
customer(contatto del privato) è visibile solo tramite questa API partner, mai nei webhook.
Transizioni
Ogni azione è un POST e restituisce { "ok": true, "trade_in": { … } }. Una transizione da uno stato incompatibile restituisce 409 invalid_status (con lo stato current reale). Il privato viene notificato via email a ogni fase.
# 1. Accepter (depuis SUBMITTED) — shippingLabelUrl facultatif (étiquette prépayée)
curl -X POST https://quizzbuy.com/api/v1/trade-ins/ID_REPRISE/accept \
-H "Authorization: Bearer zzb_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "shippingLabelUrl": "https://votre-site.fr/labels/ti-42.pdf" }'
# 2. Réceptionner l'appareil (depuis SHIPPED ou ACCEPTED)
curl -X POST https://quizzbuy.com/api/v1/trade-ins/ID_REPRISE/receive \
-H "Authorization: Bearer zzb_live_VOTRE_CLE"
# 3a. Payer le montant garanti (depuis RECEIVED) — clôt la reprise
curl -X POST https://quizzbuy.com/api/v1/trade-ins/ID_REPRISE/pay \
-H "Authorization: Bearer zzb_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "payoutRef": "VIR-2026-000123" }'
# 3b. …ou contre-offrer après inspection (depuis RECEIVED) — montant < offre garantie
curl -X POST https://quizzbuy.com/api/v1/trade-ins/ID_REPRISE/counter \
-H "Authorization: Bearer zzb_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "amountCents": 42000, "reason": "Rayures écran non déclarées" }'
# Refuser avant envoi (depuis SUBMITTED uniquement)
curl -X POST https://quizzbuy.com/api/v1/trade-ins/ID_REPRISE/reject \
-H "Authorization: Bearer zzb_live_VOTRE_CLE"- accept: solo da
SUBMITTED.shippingLabelUrlfacoltativo (URL, ≤ 500 car.). - receive: da
SHIPPEDoACCEPTED(deposito/invio non dichiarato dal cliente). - counter: da
RECEIVED.amountCentsdeve essere rigorosamente inferiore aoffer_cents, altrimenti400 counter_not_lower;reasonobbligatorio (1–500 car.). È poi il privato che accetta o rifiuta dalla propria pagina di tracking. - pay: da
RECEIVED.payoutRefobbligatorio (riferimento del bonifico, 1–120 car.). - reject: solo da
SUBMITTED— nessun corpo richiesto.
13. Webhook reprise (trade_in.*)
Gli stessi webhook (§10, firma X-ZZbuy-Signature identica) coprono la reprise gestita. Iscriviti a tutti o parte degli eventi trade_in.* alla creazione di un endpoint:
curl -X POST https://quizzbuy.com/api/v1/webhooks \
-H "Authorization: Bearer zzb_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{
"url": "https://votre-site.fr/webhooks/quizzbuy",
"events": ["trade_in.created", "trade_in.shipped", "trade_in.counter_accepted"]
}'| Evento | Trigger |
|---|---|
| trade_in.created | Nuova richiesta inviata da un privato (stato SUBMITTED). |
| trade_in.shipped | Il privato ha inserito il proprio tracking di spedizione. |
| trade_in.counter_accepted | Il privato ha accettato la tua controproposta. |
| trade_in.counter_declined | Il privato ha rifiutato la tua controproposta (restituzione del dispositivo). |
| trade_in.cancelled | Reprise annullata. |
Corpo della consegna (il contatto del privato non vi figura — recuperalo tramite GET /api/v1/trade-ins/:id):
{
"trade_in_id": "…",
"reference": "TI-2026-000042",
"status": "SHIPPED",
"device": {
"brand": "Apple", "category": "SMARTPHONE", "model": "iPhone 15 Pro",
"storage": "256 GB", "condition": "GOOD",
"functional_status": "FULLY_WORKING", "battery_health": 92, "imei": "…"
},
"offer_cents": 52000,
"currency": "EUR",
"price_locked_until": "2026-08-05T12:00:00.000Z",
"country": "FR"
}14. Inviare la tua griglia di ritiro
Alternativa «push» al flusso CSV importato da noi: invia direttamente la tua griglia di prezzi di ritiro. Ogni riga riporta i 4 importi in base allo stato del dispositivo. I prezzi alimentano la stessa tabella della sincronizzazione automatica — quindi appaiono immediatamente nel comparatore e fungono da prezzo bloccato per la reprise gestita (§12). L'operazione è un upsert per (marca, categoria, modello, capacità).
curl -X PUT https://quizzbuy.com/api/v1/buyback/prices \
-H "Authorization: Bearer zzb_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{
"prices": [
{
"brand": "Apple",
"category": "SMARTPHONE",
"model": "iPhone 15 Pro",
"storage": "256 GB",
"priceNewCents": 60000,
"priceGoodCents": 52000,
"priceFairCents": 40000,
"priceBrokenCents": 15000,
"currency": "EUR",
"url": "https://votre-site.fr/reprise/iphone-15-pro"
}
]
}'
# Réponse
{ "ok": true, "upserted": 1 }prices: da 1 a 2000 righe per richiesta.category: SMARTPHONE, TABLET, LAPTOP, SMARTWATCH, AUDIO o GAMING.priceNewCents(nuovo),priceGoodCents(buono),priceFairCents(segnato),priceBrokenCents(rotto) — in centesimi, ≥ 0.storageeurlfacoltativi; la capacità viene normalizzata automaticamente (es. «256go» → «256 GB»).