Dokumentacija za partnere

Sve što je potrebno za objavu vaših oglasa za prodaju i otkup na QuizzBuy te za obavještavanje o narudžbama pripisanim našem prometu.

1. Dobivanje API ključa

Kontaktirajte svog QuizzBuy kontakta (ili kontaktni obrazac). Za vas generiramo ključ u formatu zzb_live_… — dostavlja vam se samo jednom, čuvajte ga na sigurnom mjestu. Prosljeđujte ga u svakom zahtjevu u HTTP zaglavlju:

Authorization: Bearer zzb_live_VOTRE_CLE

2. Provjera vašeg ključa

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. Objava vaših oglasa

Oglas je ili ponuda otkupa (BUYBACK — vi preuzimate uređaj po zadanoj cijeni), ili ponuda prodaje (SALE — obnovljeni proizvod koji prodajete). Slanje je upsert: ponovno slanje istog externalId ažurira oglas.

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 ili GAMING.
  • condition : LIKE_NEW, EXCELLENT, GOOD, FAIR ili BROKEN.
  • priceCents : cijena u centima (52000 = 520 €).
  • Svaki novi oglas (ili izmjena) prolazi moderaciju prije objave.

Ažuriranje, popis ili deaktivacija:

# 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. Praćenje klikova

Kada posjetitelj QuizzBuy klikne na vašu stranicu, dolazni URL sadrži identifikator klika:

https://votre-site.fr/vendre?zzb_click=6f1e0c9a-3b2d-4e8f-9a10-abcdef123456

Pohranite tu vrijednost (kolačić ili sesija na vašoj strani, preporučeno trajanje: 45 dana). Upravo ona omogućuje pripisivanje narudžbe. Naziv parametra (zzb_click po zadanome) može se prilagoditi na zahtjev.

5. Obavještavanje o narudžbi (postback S2S)

Čim kupac naruči (kupnja ili potvrđeni zahtjev za otkup) i imate zzb_click, pozovite naš postback sa svog servera:

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 }
  • Prozor pripisivanja: 45 dana nakon klika; nakon toga, odgovor 422 attribution_window_expired.
  • order_ref mora biti jedinstven: duplikat vraća 409 duplicate_order_ref (idempotentnost — možete sigurno ponovno pokušati).
  • type : SALE za kupnju, BUYBACK za otkup.
  • currency : samo EUR — svaka druga valuta je odbijena (422 unsupported_currency).

6. Testiranje u sandboxu

Dodajte "test": true u postback: zahtjev se u potpunosti validira (ključ, click_id, prozor od 45 dana) ali nijedna konverzija se ne bilježi niti naplaćuje.

{ "click_id": "…", "type": "SALE", "amount_cents": 10000, "order_ref": "TEST-1", "test": true }
# → 200 { "test": true, "valid": true, "commission_cents": 500 }

7. Kodovi grešaka

KodGreškaObjašnjenje
400invalid_inputNevažeće tijelo zahtjeva (detalji u odgovoru).
401unauthorizedAPI ključ nedostaje, opozvan je ili je nevažeći.
404click_not_found / not_foundNepoznat click_id ili oglas (ili nije vaš).
409duplicate_order_refNarudžba je već prijavljena.
422attribution_window_expiredKlik stariji od 45 dana.
429rate_limitedPreviše zahtjeva — pokušajte ponovno za minutu.

8. Naplata

Svaka pripisana konverzija generira proviziju (ugovorena stopa, vidljiva putem /api/v1/me). QuizzBuy vam periodično šalje zbirni račun potvrđenih konverzija. Za sva pitanja: kontaktirajte nas.

9. Marketplace — prodaja na QuizzBuy

Oglasi tipa SALE s quantity > 0 prodaju se izravno na QuizzBuy (kupac plaća kod nas, isplaćujemo neto iznos umanjen za proviziju). Dodatna polja: quantity (zaliha), color, grade (A/B/C), batteryHealth (%), warrantyMonths. Oglas se automatski povezuje s odgovarajućim proizvodom (marka + model + kapacitet + boja).

# 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. Webhookovi — obavijesti o prodaji

Registrirajte HTTPS krajnju točku; obavještavamo vas o svakoj fazi narudžbe koja sadrži vaše proizvode (order.created, order.paid, order.cancelled). Tajni ključ vraća se samo prilikom kreiranja — pohranite ga.

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"

Svaka isporuka je potpisana. Provjerite zaglavlje 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 min

U slučaju neuspjeha (≠ 2xx), pokušavamo ponovno s odgodom: 1 min, 5 min, 30 min, 2 h, 12 h. Također primate e-mail obavijest o prodaji.

11. Obrada vaših narudžbi

Prikažite stavke narudžbe, potvrdite primitak i zatim pošaljite s brojem za praćenje (kupac se automatski obavještava). Adresa dostave vidljiva je tek nakon plaćanja.

# 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. Upravljani otkup (trade-in)

Upravljani otkup ide dalje od jednostavnog otkupa putem preusmjeravanja: pojedinac šalje svoj uređaj putem QuizzBuy, a vi upravljate cijelim slučajem putem API-ja (prihvaćanje, primitak, protuponuda, isplata). Cijena prikazana kupcu zaključana je pri podnošenju zahtjeva prema vašoj tablici otkupa (vidi §14); možete je revidirati naniže tek nakon primitka, putem obrazložene protuponude.

Sve krajnje točke autenticiraju se vašim API ključem (Authorization: Bearer zzb_live_…) i vraćaju samo vaše slučajeve.

Životni ciklus

SUBMITTEDACCEPTEDSHIPPEDRECEIVEDPAID. Dvije grane: REJECTED (odbijeno prije slanja) i COUNTER_OFFER (protuponuda nakon inspekcije, koju pojedinac prihvaća — zatim PAID — ili odbija — vraćanje uređaja, CANCELLED).

StatusZnačenje
SUBMITTEDZahtjev kreiran od strane pojedinca, čeka vašu odluku.
ACCEPTEDPotvrdili ste otkup; kupac treba poslati uređaj.
SHIPPEDPojedinac je unio broj za praćenje pošiljke.
RECEIVEDPrimili ste uređaj; inspekcija u tijeku.
COUNTER_OFFERNakon inspekcije predlažete revidirani iznos (niži).
PAIDIsplata izvršena pojedincu — slučaj zatvoren.
REJECTEDZahtjev odbijen prije slanja (nije prihvatljivo, prijevara…).
CANCELLEDOtkazano (odbijanje protuponude, vraćanje uređaja).

Popis i pregled

# 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 (neobavezni filtar): jedna od vrijednosti iz gornje tablice — inače 400 invalid_status.
  • limit : maks. 200 (zadano 50); offset za paginaciju.
  • customer (kontakt pojedinca) vidljiv je samo putem ovog partnerskog API-ja, nikada u webhookovima.

Prijelazi

Svaka radnja je POST i vraća { "ok": true, "trade_in": { … } }. Prijelaz iz nekompatibilnog statusa vraća 409 invalid_status (sa stvarnim current). Pojedinac se obavještava e-mailom u svakoj fazi.

# 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: samo iz SUBMITTED. shippingLabelUrl neobavezno (URL, ≤ 500 znakova).
  • receive: iz SHIPPED ili ACCEPTED (slanje neprijavljeno od strane kupca).
  • counter: iz RECEIVED. amountCents mora biti strogo niži od offer_cents, inače 400 counter_not_lower; reason obavezno (1–500 znakova). Zatim pojedinac prihvaća ili odbija sa svoje stranice za praćenje.
  • pay: iz RECEIVED. payoutRef obavezno (referenca uplate, 1–120 znakova).
  • reject: samo iz SUBMITTED — nije potrebno tijelo zahtjeva.

13. Webhookovi za otkup (trade_in.*)

Isti webhookovi (§10, identičan potpis X-ZZbuy-Signature) pokrivaju upravljani otkup. Pretplatite se na sve ili dio događaja trade_in.* prilikom kreiranja krajnje točke:

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"]
  }'
DogađajOkidač
trade_in.createdNovi zahtjev podnesen od strane pojedinca (status SUBMITTED).
trade_in.shippedPojedinac je unio podatke o praćenju pošiljke.
trade_in.counter_acceptedPojedinac je prihvatio vašu protuponudu.
trade_in.counter_declinedPojedinac je odbio vašu protuponudu (vraćanje uređaja).
trade_in.cancelledOtkup otkazan.

Tijelo isporuke (kontakt pojedinca se ne nalazi u njemu — dohvatite ga putem 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. Slanje vaše tablice otkupa

Alternativa „push” tipa u odnosu na CSV tok koji mi povlačimo: izravno pošaljite svoju tablicu cijena otkupa. Svaki redak sadrži 4 iznosa prema stanju uređaja. Cijene se pune u istu tablicu kao i automatska sinkronizacija — stoga se odmah pojavljuju u usporedniku i služe kao zaključana cijena za upravljani otkup (§12). Operacija je upsert prema (marka, kategorija, model, kapacitet).

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 : 1 do 2000 redaka po zahtjevu.
  • category : SMARTPHONE, TABLET, LAPTOP, SMARTWATCH, AUDIO ili GAMING.
  • priceNewCents (novo), priceGoodCents (dobro), priceFairCents (označeno), priceBrokenCents (razbijeno) — u centima, ≥ 0.
  • storage i url neobavezni; kapacitet se automatski normalizira (npr. « 256go » → « 256 GB »).