1. Kimlik Dogrulama
Tum API istekleri kimlik dogrulama gerektirir. API anahtarinizi Rafplan dashboard'undan olusturabilirsiniz:
- Rafplan Dashboard'a giris yapin
- Ayarlar > API Anahtarlari sayfasina gidin
- "Yeni Anahtar Olustur" butonuna tiklayin
- Anahtarinizi guvenli bir yerde saklayin (tekrar gosterilemez)
API anahtarinizi iki sekilde gonderebilirsiniz:
2. Ilk Istek
API'yi test etmek icin basit bir urun listesi istegi gonderelim:
curl -s -H "X-API-Key: rfp_live_xxxxxxxxxxxx" \
"https://rafplan.com/api/v1/products?page=1&limit=5" | jq .bashResponse:
{
"data": [
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"name": "Ulker Cikolatali Gofret 40g",
"barcode": "8690504012345",
"platformCode": "PLT-001234",
"brandId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"brand": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Ulker",
"logoUrl": null,
"status": "active"
},
"width": 12.5,
"height": 8.0,
"depth": 3.2,
"weight": 0.04,
"imageUrl": "https://storage.rafplan.com/products/img_001234.jpg",
"createdAt": "2026-01-15T10:30:00.000Z",
"updatedAt": "2026-03-20T14:45:00.000Z"
}
],
"meta": {
"requestId": "req_a1b2c3d4-e5f6-7890",
"timestamp": "2026-04-04T12:00:00.000Z",
"page": 1,
"limit": 5,
"total": 150,
"totalPages": 30
}
}json3. Sayfalama (Pagination)
Liste endpoint'leri sayfalama destekler. `page` ve `limit` query parametreleri kullanilir.
| Parameter | Aciklama |
|---|---|
| page | Sayfa numarasi (1'den baslar, varsayilan: 1) |
| limit | Sayfa basi kayit sayisi (varsayilan: 20, maksimum: 100) |
Response'daki `meta` objesi sayfalama bilgilerini icerir:
{
"meta": {
"requestId": "req_a1b2c3d4-e5f6-7890",
"timestamp": "2026-04-04T12:00:00.000Z",
"page": 2,
"limit": 20,
"total": 150,
"totalPages": 8
}
}json4. Hata Yonetimi
API hatalari tutarli bir formatta doner:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Gecersiz parametre degeri",
"details": {
"field": "limit",
"issue": "Deger 1 ile 100 arasinda olmali"
}
}
}json| HTTP Status | Ad | Aciklama |
|---|---|---|
| 400 | Bad Request | Gecersiz istek parametreleri |
| 401 | Unauthorized | Gecersiz veya eksik API anahtari |
| 403 | Forbidden | Yetki yetersiz |
| 404 | Not Found | Kaynak bulunamadi |
| 429 | Too Many Requests | Rate limit asildi |
| 500 | Internal Server Error | Sunucu hatasi |
5. Rate Limiting
API istekleri tier bazli rate limit ile sinirlandirilir:
| Tier | Limit |
|---|---|
| Starter | 60 istek/dk |
| Professional | 300 istek/dk |
| Enterprise | 1000 istek/dk |
Response headers:
| Header | Aciklama |
|---|---|
| X-RateLimit-Limit | Dakikadaki maksimum istek sayisi |
| X-RateLimit-Remaining | Kalan istek sayisi |
| X-RateLimit-Reset | Limit sifirlama zamani (Unix timestamp) |
6. Webhook'lar
Webhook'lar ile planogram ve urun degisikliklerinden anlik haberdar olun.
| Event | Aciklama |
|---|---|
| product.created | Yeni urun olusturuldu |
| product.updated | Urun guncellendi |
| planogram.published | Planogram yayinlandi |
| planogram.assigned | Planogram subeye atandi |
Webhook isteklerinin gercekligini dogrulamak icin HMAC-SHA256 imza kullanilir. `X-Webhook-Signature` header'indaki imza, paylasilan secret ile dogrulanir.
const crypto = require('crypto')
function verifyWebhookSignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(`sha256=${expected}`),
Buffer.from(signature)
)
}
// Express.js middleware ornegi
app.post('/webhooks/rafplan', (req, res) => {
const signature = req.headers['x-webhook-signature']
const isValid = verifyWebhookSignature(
JSON.stringify(req.body),
signature,
process.env.WEBHOOK_SECRET
)
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' })
}
const event = req.body
console.log(`Event: ${event.type}`, event.data)
res.status(200).json({ received: true })
})javascript7. Ornek Kodlar
Farkli dillerde API kullanim ornekleri:
cURL
# Urun listesi
curl -s -H "X-API-Key: rfp_live_xxxxxxxxxxxx" \
"https://rafplan.com/api/v1/products?page=1&limit=10"
# Urun detayi
curl -s -H "X-API-Key: rfp_live_xxxxxxxxxxxx" \
"https://rafplan.com/api/v1/products/f47ac10b-58cc-4372-a567-0e02b2c3d479"
# Sube listesi (sehir filtresi)
curl -s -H "X-API-Key: rfp_live_xxxxxxxxxxxx" \
"https://rafplan.com/api/v1/branches?city=Istanbul&page=1&limit=20"
# Planogram detayi (raflar ve urunler dahil)
curl -s -H "X-API-Key: rfp_live_xxxxxxxxxxxx" \
"https://rafplan.com/api/v1/planograms/c3d4e5f6-7890-1234-abcd-ef4567890123"bashTypeScript / JavaScript
const API_KEY = 'rfp_live_xxxxxxxxxxxx'
const BASE_URL = 'https://rafplan.com/api/v1'
// --- Tip Tanimlari ---
interface PaginationMeta {
requestId: string
timestamp: string
page: number
limit: number
total: number
totalPages: number
}
interface Product {
id: string
name: string
barcode: string
platformCode: string
brandId: string | null
width: number
height: number
depth: number
weight: number | null
imageUrl: string | null
createdAt: string
updatedAt: string
}
interface ApiResponse<T> {
data: T
meta: PaginationMeta
}
interface ApiError {
error: { code: string; message: string; details?: Record<string, unknown> }
}
// --- API Client ---
async function apiRequest<T>(path: string): Promise<T> {
const response = await fetch(`${BASE_URL}${path}`, {
headers: { 'X-API-Key': API_KEY },
})
if (!response.ok) {
const err: ApiError = await response.json()
throw new Error(`[${err.error.code}] ${err.error.message}`)
}
return response.json()
}
// --- Kullanim ---
// Urun listesi
const products = await apiRequest<ApiResponse<Product[]>>(
'/products?page=1&limit=10'
)
console.log(`Toplam ${products.meta.total} urun, sayfa ${products.meta.page}/${products.meta.totalPages}`)
// Urun detayi
const product = await apiRequest<{ data: Product; meta: { requestId: string } }>(
'/products/f47ac10b-58cc-4372-a567-0e02b2c3d479'
)
console.log(product.data.name, product.data.barcode)
// Tum sayfalari iterasyon ile cek
async function fetchAllProducts(): Promise<Product[]> {
const all: Product[] = []
let page = 1
while (true) {
const res = await apiRequest<ApiResponse<Product[]>>(
`/products?page=${page}&limit=100`
)
all.push(...res.data)
if (page >= res.meta.totalPages) break
page++
}
return all
}typescriptPython
import requests
API_KEY = "rfp_live_xxxxxxxxxxxx"
BASE_URL = "https://rafplan.com/api/v1"
headers = {"X-API-Key": API_KEY}
def api_request(path: str, params: dict | None = None) -> dict:
"""API istegi gonder ve JSON dondur."""
response = requests.get(f"{BASE_URL}{path}", headers=headers, params=params)
response.raise_for_status()
return response.json()
# Urun listesi
result = api_request("/products", {"page": 1, "limit": 10})
products = result["data"]
meta = result["meta"]
print(f"Toplam {meta['total']} urun, sayfa {meta['page']}/{meta['totalPages']}")
for product in products:
print(f" {product['name']} - {product['barcode']}")
# Urun detayi
detail = api_request("/products/f47ac10b-58cc-4372-a567-0e02b2c3d479")
p = detail["data"]
print(f"Urun: {p['name']}, Boyut: {p['width']}x{p['height']}x{p['depth']} cm")
# Sube listesi (sehir filtresi)
branches = api_request("/branches", {"city": "Istanbul", "page": 1, "limit": 20})
for branch in branches["data"]:
print(f" {branch['name']} ({branch['code']}) - {branch['city']}")
# Tum sayfalari cek
def fetch_all_products() -> list[dict]:
"""Tum urunleri sayfa sayfa ceker."""
all_products = []
page = 1
while True:
result = api_request("/products", {"page": page, "limit": 100})
all_products.extend(result["data"])
if page >= result["meta"]["totalPages"]:
break
page += 1
return all_products
# Webhook imza dogrulama
import hashlib
import hmac
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
"""Webhook HMAC-SHA256 imzasini dogrula."""
expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)python