İçeriğe geç
kalfagen

Geliştirici rehberi

Talepleri, teklifleri ve anlaşmaları kendi uygulamanızdan yönetebilmeniz için REST API ve webhook desteği sunuyoruz.

Etkileşimli Swagger dokümanı

Başlarken

Tüm istekler JSON konuşur ve aşağıdaki taban adrese gider. Yanıt alanları camelCase, tutarlar TL cinsinden sayıdır.

https://pazaryeri.kalfagen.com/api/v1
  1. Hesabınıza girin, Hesabım → Geliştirici bölümünden bir API anahtarı oluşturun. Anahtarın tamamı yalnızca bir kez gösterilir.
  2. İhtiyacınız olan kapsamları (scope) seçin, anahtarı sunucu tarafında saklayın. Mobil uygulama veya tarayıcı koduna gömmeyin.
  3. İsteklerde Authorization: Bearer pzk_... veya X-API-Key başlığını gönderin.

Kimlik doğrulama

API anahtarı: sunucudan sunucuya erişim için. Yalnızca seçtiğiniz kapsamlara izin verir; anahtar yönetimi ve yönetici uçları anahtarla çağrılamaz. Varsayılan sınır dakikada 120 istektir, aşılırsa 429 döner.

Kullanıcı jetonu (JWT): kendi mobil uygulamanızda kullanıcıyı giriş yaptırmak için. POST /auth/login ile access (15 dk) ve refresh jetonu alırsınız; süre dolunca POST /auth/refresh ile yenilersiniz. Refresh jetonu her yenilemede değişir.

# Herkese açık: açık talepleri listele
curl "https://pazaryeri.kalfagen.com/api/v1/demands?status=COLLECTING&pageSize=5"

# API anahtarıyla: kendi profilim ve aboneliğim
curl -H "Authorization: Bearer pzk_xxxxxxxxxxxx" https://pazaryeri.kalfagen.com/api/v1/me

# Alıcı olarak talebe katıl (demands:write kapsamı gerekir)
curl -X POST https://pazaryeri.kalfagen.com/api/v1/demands/DEMAND_ID/join \
  -H "Authorization: Bearer pzk_xxxxxxxxxxxx" -H "Content-Type: application/json" \
  -d '{"quantity": 300, "deliveryCity": "Ankara", "paymentPref": "CHEQUE"}'

API anahtarı kapsamları

Kapsamİzin verdiği işlem
catalog:readSektörleri, kategorileri ve ürünleri okur (anahtarsız da açıktır).
demands:readTalepleri ve kendi katılım/teklif durumunuzu okur.
demands:writeAlıcı: talep başlatır, talebe katılır veya katılımı geri çeker.
bids:readTedarikçi: verdiği teklifleri okur.
bids:writeTedarikçi: teklif verir, düşürür, geri çeker; kazanılan ihaleyi onaylar veya reddeder.
deals:readAnlaşmaları ve (abonelik aktifse) karşı tarafın iletişim bilgilerini okur.
deals:writeAnlaşma durumunu günceller, puan verir.
profile:readProfil, abonelik ve kullanım bilgisini okur.
notifications:readBildirimleri okur.

Hata biçimi ve sayfalama

Başarısız isteklerde HTTP durum kodu ile birlikte makinece okunabilir bir code ve Türkçe message döner.

{ "statusCode": 402, "code": "SUBSCRIPTION_REQUIRED",
  "message": "Bu işlem için aktif bir aboneliğiniz olmalı. ..." }

Sık görülen kodlar: VALIDATION_ERROR (400), UNAUTHORIZED (401), SUBSCRIPTION_REQUIRED ve PLAN_LIMIT (402), MISSING_SCOPE (403), RATE_LIMITED (429). Liste uçları page ve pageSize (en fazla 100) alır, { items, total, page, pageSize } döner.

Webhook'lar

Olayları sürekli sorgulamak yerine adresinize POST olarak alın. Adresi Hesabım → Geliştirici bölümünden ekleyin; imza sırrı yalnızca bir kez gösterilir. Adres https:// olmalı ve herkese açık bir sunucuya çıkmalıdır. Başarısız teslimatlar 1, 5, 30 dakika, 2 ve 6 saat sonra yeniden denenir. Aynı olay birden fazla gelebilir; id alanıyla tekilleştirin.

OlayNe zaman
demand.bidding_startedTalep dolup ihaleye çıktı (alıcılara ve ilgili tedarikçilere).
demand.awardedİhale sonuçlandı, kazanan tedarikçinin onayı bekleniyor.
demand.completedKazanan onayladı, anlaşmalar açıldı.
demand.cancelledTalep iptal oldu (minimum miktara ulaşılamadı, teklif gelmedi vb.).
bid.wonTeklifiniz kazandı veya yedekten kazanana yükseldi (tedarikçi).
deal.createdYeni anlaşma oluştu.
deal.status_changedAnlaşma durumu değişti.
subscription.activatedAbonelik aktif edildi.
subscription.expiringAbonelik 3 gün içinde bitiyor.
subscription.expiredAbonelik sona erdi.

İmzayı doğrulama

Her istek X-Pazaryeri-Signature: t=ZAMAN,v1=İMZA başlığı taşır. İmza, ZAMAN.GÖVDE metninin sırrınızla HMAC-SHA256 değeridir. 5 dakikadan eski zaman damgalarını reddedin.

import { createHmac, timingSafeEqual } from 'crypto';

export function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
  const expected = createHmac('sha256', secret).update(parts.t + '.' + rawBody).digest('hex');
  return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

// Gövde örneği
// { "id": "…", "type": "demand.awarded", "createdAt": "2026-10-07T12:00:00Z",
//   "data": { "demandId": "…", "finalUnitPrice": 3.5 } }

Önemli kurallar

  • Platform firmalar arasında ödeme almaz; API'de ödeme uçları yoktur. Ödeme koşulları (peşin, çek, taksit, vade) teklifte bilgi olarak taşınır.
  • Karşı tarafın iletişim bilgileri yalnızca anlaşma açıldıktan sonra ve aboneliği aktif kullanıcılara döner.
  • Tedarikçilerin teklifleri birbirine gösterilmez; yalnızca kendi teklifinizin önde olup olmadığını görürsünüz.