Документация за партньори

Всичко необходимо, за да публикувате своите обяви за продажба и обратно изкупуване на QuizzBuy и да ни уведомявате за поръчките, приписани на нашия трафик.

1. Получаване на API ключ

Свържете се с вашия контакт в QuizzBuy (или формата за контакт). Генерираме за вас ключ във формат zzb_live_… — той ви се съобщава само веднъж, съхранявайте го на сигурно място. Подавайте го при всяка заявка в HTTP заглавието:

Authorization: Bearer zzb_live_VOTRE_CLE

2. Проверка на вашия ключ

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. Публикуване на вашите обяви

Обявата е или оферта за обратно изкупуване (BUYBACK — вие изкупувате устройство на дадена цена), или оферта за продажба (SALE — рециклиран продукт, който продавате). Изпращането е upsert: повторното изпращане на същия externalId актуализира обявата.

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 или GAMING.
  • condition: LIKE_NEW, EXCELLENT, GOOD, FAIR или BROKEN.
  • priceCents: цена в стотинки (52000 = 520 €).
  • Всяка нова обява (или изменение) преминава през модерация преди публикуване.

Актуализиране, извеждане на списък или деактивиране:

# 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. Проследяване на кликовете

Когато посетител на QuizzBuy кликне към вашия сайт, URL адресът на пристигане съдържа идентификатор на клика:

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

Съхранявайте тази стойност (бисквитка или сесия на вашия сайт, препоръчителна продължителност: 45 дни). Именно тя ще позволи приписването на поръчката. Името на параметъра (zzb_click по подразбиране) е конфигурируемо при поискване.

5. Уведомяване за поръчка (postback S2S)

Веднага щом клиент направи поръчка (покупка или потвърдена заявка за обратно изкупуване) и разполагате с zzb_click, извикайте нашия postback от вашия сървър:

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 }
  • Прозорец на приписване: 45 дни след клика; след това — отговор 422 attribution_window_expired.
  • order_ref трябва да е уникален: дубликат връща 409 duplicate_order_ref (идемпотентност — можете да опитате отново без риск).
  • type: SALE за покупка, BUYBACK за обратно изкупуване.
  • currency: само EUR — всяка друга валута се отхвърля (422 unsupported_currency).

6. Тестване в sandbox

Добавете "test": true към postback заявката: заявката се валидира изцяло (ключ, click_id, прозорец от 45 дни), но не се регистрира и не се фактурира никакво реализирано плащане.

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

7. Кодове за грешки

КодГрешкаОбяснение
400invalid_inputНевалидно тяло на заявката (подробности в отговора).
401unauthorizedЛипсващ, отменен или невалиден API ключ.
404click_not_found / not_foundНепознат click_id или обява (или не е ваша).
409duplicate_order_refПоръчката вече е уведомена.
422attribution_window_expiredКлик отпреди повече от 45 дни.
429rate_limitedТвърде много заявки — опитайте отново след минута.

8. Фактуриране

Всяко приписано реализирано плащане генерира комисиона (договорен процент, виден чрез /api/v1/me). QuizzBuy ви изпраща периодична обобщена фактура за потвърдените реализирани плащания. За всякакви въпроси: свържете се с нас.

9. Marketplace — продажба в QuizzBuy

Обявите SALE с quantity > 0 се продават директно в QuizzBuy (плащането на клиента е при нас, изплащане на нетната сума след комисионата). Допълнителни полета: quantity (наличност), color, grade (A/B/C), batteryHealth (%), warrantyMonths. Обявата се обвързва автоматично със съответния продукт (марка + модел + капацитет + цвят).

# 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. Webhooks — известяване за продажби

Регистрирайте HTTPS endpoint; уведомяваме ви на всеки етап от поръчка, съдържаща ваши продукти (order.created, order.paid, order.cancelled). Тайният ключ се връща само при създаването — съхранете го.

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"

Всяко доставяне е подписано. Проверете заглавието 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

При неуспех (≠ 2xx) правим повторни опити с отлагане: 1 мин, 5 мин, 30 мин, 2 ч, 12 ч. Получавате също имейл за уведомление за продажба.

11. Обработка на вашите поръчки

Извеждайте списък с редовете на поръчките си, потвърждавайте получаването и след това изпращайте с номер за проследяване (клиентът се уведомява автоматично). Адресът за доставка е видим едва след плащане.

# 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. Управлявана реприза (trade-in)

Управляваната реприза отива по-далеч от обикновеното обратно изкупуване чрез пренасочване: частното лице подава своето устройство от QuizzBuy, а вие управлявате целия процес чрез API (приемане, получаване, насрещна оферта, плащане). Показаната на клиента цена е заключена при подаването според вашата ценова таблица за обратно изкупуване (вж. §14); можете да я преразгледате надолу само след получаване, чрез мотивирана насрещна оферта.

Всички endpoint-и се удостоверяват с вашия API ключ (Authorization: Bearer zzb_live_…) и връщат само вашите случаи.

Жизнен цикъл

SUBMITTEDACCEPTEDSHIPPEDRECEIVEDPAID. Две разклонения: REJECTED (отказ преди изпращане) и COUNTER_OFFER (насрещна оферта след инспекция, която частното лице приема — след което PAID — или отказва — връщане на устройството, CANCELLED).

СтатусЗначение
SUBMITTEDЗаявка, създадена от частното лице, в очакване на вашето решение.
ACCEPTEDПотвърдили сте обратното изкупуване; клиентът трябва да изпрати устройството.
SHIPPEDЧастното лице е въвело своя номер за проследяване.
RECEIVEDПолучили сте устройството; инспекцията е в ход.
COUNTER_OFFERСлед инспекция предлагате преразгледана (по-ниска) сума.
PAIDИзвършено плащане на частното лице — случаят е приключен.
REJECTEDЗаявка, отказана преди изпращане (неотговаряща на условията, измама…).
CANCELLEDОтменена (отказ на насрещна оферта, връщане на устройството).

Извеждане на списък и преглед

# 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 (незадължителен филтър): стойност от таблицата по-горе — иначе 400 invalid_status.
  • limit: макс. 200 (по подразбиране 50); offset за пагинация.
  • customer (контакт на частното лице) е видим само чрез този партньорски API, никога в webhooks.

Преходи

Всяко действие е POST и връща { "ok": true, "trade_in": { … } }. Преход от несъвместим статус връща 409 invalid_status (с реалния current). Частното лице се уведомява по имейл на всеки етап.

# 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: само от SUBMITTED. shippingLabelUrl незадължителен (URL, ≤ 500 знака).
  • receive: от SHIPPED или ACCEPTED (депозит/изпращане, необявено от клиента).
  • counter: от RECEIVED. amountCents трябва да бъде строго по-малко от offer_cents, иначе 400 counter_not_lower; reason е задължителен (1–500 знака). След това частното лице приема или отказва от своята страница за проследяване.
  • pay: от RECEIVED. payoutRef е задължителен (референция на превода, 1–120 знака).
  • reject: само от SUBMITTED — не се изисква тяло.

13. Webhooks за репризата (trade_in.*)

Същите webhooks (§10, идентичен подпис X-ZZbuy-Signature) покриват управляваната реприза. Абонирайте се за всички или част от събитията trade_in.* при създаването на 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"]
  }'
СъбитиеТригер
trade_in.createdНова заявка, подадена от частно лице (статус SUBMITTED).
trade_in.shippedЧастното лице е въвело своето проследяване на изпращането.
trade_in.counter_acceptedЧастното лице е приело вашата насрещна оферта.
trade_in.counter_declinedЧастното лице е отказало вашата насрещна оферта (връщане на устройството).
trade_in.cancelledРепризата е отменена.

Тяло на доставката (контактът на частното лице не фигурира в него — вземете го чрез 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. Изпращане на вашата ценова таблица за обратно изкупуване

Алтернатива тип „push“ на CSV потока, изтеглян от нас: изпращайте директно вашата ценова таблица за обратно изкупуване. Всеки ред носи 4-те суми според състоянието на устройството. Цените захранват същата таблица като автоматичната синхронизация — те се появяват незабавно в сравнителния инструмент и служат като заключена цена за управляваната реприза (§12). Операцията е upsert по (марка, категория, модел, капацитет).

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 до 2000 реда на заявка.
  • category: SMARTPHONE, TABLET, LAPTOP, SMARTWATCH, AUDIO или GAMING.
  • priceNewCents (нов), priceGoodCents (добър), priceFairCents (маркиран), priceBrokenCents (счупен) — в стотинки, ≥ 0.
  • storage и url незадължителни; капацитетът се нормализира автоматично (напр. „256go“ → „256 GB“).