Odesin Geliştirici Merkezi
Ödeme oturumları, kart ve havale entegrasyonları, webhook bildirimleri ve kod örnekleri — mağazanızı Odesin'e bağlamak için tek referans.
Ne bulabilirsiniz
- Canlı API referansı
- Hosted & whitelabel akışlar
- Webhook akışı
Base URL
https://odesin.com
Protokol
HTTPS / REST
Format
JSON
Sanal POS (Hosted) modelinde ödeme oturumunu siz API ile oluşturursunuz; tahsilat işlemi banka sanal POS altyapısı üzerinden 3D Secure ile güvenli şekilde işlenir. Müşteri kart bilgilerini checkout_url ile verdiğimiz Odesin checkout sayfasında girer — bu adresi doğrudan yönlendirme ile açabilir veya kendi sitenizde <iframe> içinde gösterebilirsiniz. Kart verisi mağaza sistemlerinize uğramaz, doğrudan bankaya iletilir. Ödeme sonucunda müşteri return_url adresinize döner; isteğe bağlı callback_url ile sunucunuza webhook bildirimi gönderilir.
Genel Bakış
Sanal POS (Hosted) akışında ödeme oturumunu API ile açar, müşteriyi checkout_url adresine yönlendirirsiniz. Kart verisi Odesin checkout üzerinde toplanır ve 3D Secure doğrulaması banka tarafında yürür.
POST /api/payment/create-sessionilemode: "card"gönderilir.- Yanıttaki
checkout_urlmüşterinin ödeme ekranıdır; yönlendirme veya iframe ile açılır. - Ödeme başarılı veya başarısız olduğunda müşteri
return_urladresinize otomatik yönlendirilir (5 saniyelik geri sayım ve "Mağazaya Dön" butonu ile). URL'eodesin_payment=success|failedveodesin_ref=ISLEM_NOquery parametreleri eklenir. - Mağazada
pos_enabledaçık olmalıdır; kapalıysa403döner.
Kimlik Doğrulama
Tüm API isteklerinde x-api-key ile kimlik doğrulaması yapılır. API v1.2 sözleşmesine göre aynı isteklerde HMAC istek imzası da zorunludur.
İstek İmzası (HMAC)
API v1.2 ile mağaza sunucunuzdan Odesin'e giden POST /api/payment/create-session, POST /api/payment/notify, GET /api/payment/session-status ve GET /api/payment/iban-accounts çağrılarında X-Odesin-Timestamp ile X-Odesin-Signature başlıkları zorunludur. İmza anahtarı, x-api-key ile gönderdiğiniz sk_live_... değerinin ta kendisidir.
- POST isteklerinde imzalanacak metin (UTF-8, satır sonu
\n):{unixSaniye}\n{METHOD}\n{hamGövde}—hamGövde, ağa giden JSON'un aynen aynısı olmalıdır (boşluk ve sıra dahil). - GET isteklerinde:
{unixSaniye}\nGET\n{yolVeQuery}—yolVeQueryörnek:/api/payment/session-status?session_id=...(baştaki slash ile). - İmza:
HMAC-SHA256(apiKey, imzaMetni)çıktısının hex gösterimi (küçük harf önerilir). X-Odesin-Timestamp: Unix saniye; sunucu saati ile fark en fazla ±5 dakika olmalıdır.
| Başlık | Zorunlu | Açıklama |
|---|---|---|
X-Odesin-Timestamp | Evet | Unix epoch (saniye) |
X-Odesin-Signature | Evet | HMAC-SHA256 hex |
Örnek (Node.js, POST)
import crypto from "crypto";
function odesinSignPost(apiKey, rawBody) {
const ts = Math.floor(Date.now() / 1000).toString();
const payload = `${ts}\nPOST\n${rawBody}`;
const sig = crypto.createHmac("sha256", apiKey).update(payload, "utf8").digest("hex");
return { "x-odesin-timestamp": ts, "x-odesin-signature": sig };
}
function odesinSignGet(apiKey, pathWithQuery) {
const ts = Math.floor(Date.now() / 1000).toString();
const payload = `${ts}\nGET\n${pathWithQuery}`;
const sig = crypto.createHmac("sha256", apiKey).update(payload, "utf8").digest("hex");
return { "x-odesin-timestamp": ts, "x-odesin-signature": sig };
}Örnek (bash, OpenSSL — POST)
API_KEY="sk_live_XXXXXXXXXXXX"
BODY='{"amount":250,"customer_name":"Ahmet Yılmaz","customer_email":"ahmet@email.com","customer_phone":"05321234567","description":"Sipariş #1234","callback_url":"https://yoursite.com/api/webhook","return_url":"https://yoursite.com/order/success"}'
TS=$(date +%s)
SIG=$(printf '%s\nPOST\n%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$API_KEY" | awk '{print $2}')
curl -X POST https://odesin.com/api/payment/create-session \
-H "Content-Type: application/json" \
-H "x-api-key: $API_KEY" \
-H "x-odesin-timestamp: $TS" \
-H "x-odesin-signature: $SIG" \
--data-binary "$BODY"Örnek (PHP)
<?php
/** POST / GET imza başlıkları (ham gövde veya yol+query ile aynı kural). */
function odesin_sign_post(string $apiKey, string $rawBody): array {
$ts = (string) time();
$sig = hash_hmac('sha256', $ts . "\nPOST\n" . $rawBody, $apiKey);
return ['x-odesin-timestamp' => $ts, 'x-odesin-signature' => $sig];
}
function odesin_sign_get(string $apiKey, string $pathWithQuery): array {
$ts = (string) time();
$sig = hash_hmac('sha256', $ts . "\nGET\n" . $pathWithQuery, $apiKey);
return ['x-odesin-timestamp' => $ts, 'x-odesin-signature' => $sig];
}
// Kullanım: $h = odesin_sign_post($apiKey, $jsonBodyString);
// CURLOPT_HTTPHEADER: 'x-odesin-timestamp: '.$h['x-odesin-timestamp'], 'x-odesin-signature: '.$h['x-odesin-signature']Kart oturumu oluştur
İstek POST /api/payment/create-session endpoint'ine gider. Kart modunda return_url zorunludur; diğer alanlar aşağıdaki tabloda özetlenmiştir.
| Alan | Zorunlu | Açıklama |
|---|---|---|
| mode | Evet | "card" |
| amount | Evet | Tutar (TRY) |
| return_url | Evet | Ödeme tamamlandıktan sonra müşterinin döneceği HTTPS adresi |
| callback_url | Hayır | Mağaza webhook URL'i; yoksa mağaza ayarındaki webhook kullanılır. Başarılı kart ödemesinde payment.approved benzeri bildirim gönderilir. |
| customer_name | Evet | Müşteri adı soyadı |
| customer_email | Evet | Müşteri e-posta adresi |
| customer_phone | Evet | Müşteri telefon numarası |
| description | Hayır | Sipariş / açıklama metni |
API_KEY="sk_live_XXXXXXXXXXXX"
BODY='{"mode":"card","amount":199.9,"return_url":"https://magazaniz.com/siparis/tesekkur","callback_url":"https://magazaniz.com/api/odesin-webhook","customer_name":"Ali Veli","customer_email":"ali@email.com","customer_phone":"05321234567","description":"Sipariş #4521"}'
TS=$(date +%s)
SIG=$(printf '%s\nPOST\n%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$API_KEY" | awk '{print $2}')
curl -X POST https://odesin.com/api/payment/create-session \
-H "Content-Type: application/json" \
-H "x-api-key: $API_KEY" \
-H "x-odesin-timestamp: $TS" \
-H "x-odesin-signature: $SIG" \
--data-binary "$BODY"Örnek yanıt
{
"session_id": "uuid",
"mode": "card",
"checkout_url": "https://odesin.com/checkout/uuid",
"reference_code": "ODSN-XXXX",
"amount": 199.9,
"currency": "TRY",
"expires_at": "2025-01-01T12:00:00.000Z"
}Checkout ve 3D Secure
Müşteri checkout_url üzerindeki Odesin checkout sayfasında kart bilgilerini (PAN, SKT, CVV) girer. Form gönderildiğinde Odesin sunucusu kart verisini banka sanal POS altyapısı üzerinden 3D Secure akışına sokar.
Akış
- Müşteri Odesin checkout sayfasında kartını girer ve "Öde" butonuna tıklar.
- Odesin, kart verisi ile
gt3dengineformunu oluşturup bankaya POST eder (3D_PAY). - Banka, müşterinin tarayıcısını 3D Secure doğrulama sayfasına yönlendirir (SMS / mobil onay).
- Doğrulama sonrası banka, Odesin callback adresine sonucu POST eder.
- Oturum durumu
paidveyafailedolur; müşteri her iki durumda dareturn_urladresinize otomatik yönlendirilir (?odesin_payment=success|failed&odesin_ref=ISLEM_NO).
window.location.href) önerilir.Dönüş ve webhook
Ödeme sonrası (başarılı veya başarısız) müşteri return_url adresinize otomatik yönlendirilir. URL'e eklenen query parametreleri ile ödeme durumunu anlık kontrol edebilirsiniz:
| Parametre | Değer | Açıklama |
|---|---|---|
| odesin_payment | success / failed | Ödeme sonucu |
| odesin_ref | Metin | İşlem no (session ID kısaltması) |
| odesin_detail | Metin | Banka hata mesajı (red durumunda) |
| odesin_hash_ok | 1 / 0 | Banka yanıt hash doğrulaması |
Sunucu tarafında, oturum oluştururken verdiğiniz callback_url veya mağaza panelinde tanımlı webhook adresine JSON bildirim gönderilir:
{
"event": "payment.approved",
"session_id": "uuid",
"reference_code": "ODSN-XXXX",
"amount": 199.9,
"currency": "TRY",
"status": "paid",
"transaction_id": "uuid",
"payment_method": "card",
"provider": "bank_pos",
"timestamp": "2025-01-01T12:00:00.000Z"
}reference_code ve session_id ile kendi sisteminizde mutabakat yapın. Ödeme başarısız olduğunda olay tipi payment.rejected olur.Kod örnekleri
JavaScriptOturum oluştur ve müşteriyi checkout'a yönlendir
const BASE = "https://odesin.com";
const API_KEY = "sk_live_XXXXXXXXXXXX";
function odesinSignPost(apiKey, rawBody) {
const ts = Math.floor(Date.now() / 1000).toString();
const enc = new TextEncoder();
const payload = enc.encode(`${ts}\nPOST\n${rawBody}`);
return crypto.subtle.importKey("raw", enc.encode(apiKey), { name: "HMAC", hash: "SHA-256" }, false, ["sign"])
.then((key) => crypto.subtle.sign("HMAC", key, payload))
.then((buf) => ({
"x-odesin-timestamp": ts,
"x-odesin-signature": Array.from(new Uint8Array(buf), (b) => b.toString(16).padStart(2, "0")).join(""),
}));
}
async function startHostedCardCheckout(order) {
const rawBody = JSON.stringify({
mode: "card",
amount: order.total,
currency: "TRY",
return_url: order.successUrl,
callback_url: order.webhookUrl,
customer_name: order.customerName,
customer_email: order.customerEmail,
customer_phone: order.customerPhone,
description: order.description ?? "",
});
const sig = await odesinSignPost(API_KEY, rawBody);
const res = await fetch(`${BASE}/api/payment/create-session`, {
method: "POST",
headers: { "Content-Type": "application/json", "x-api-key": API_KEY, ...sig },
body: rawBody,
});
const data = await res.json();
if (!res.ok) throw new Error(data.error ?? res.statusText);
window.location.href = data.checkout_url;
}Pythoncreate-session (kart / hosted)
import hashlib, hmac, time, json, requests
BASE = "https://odesin.com"
API_KEY = "sk_live_XXXXXXXXXXXX"
def odesin_sign_post(api_key: str, raw_body: str) -> dict:
ts = str(int(time.time()))
msg = f"${ts}\nPOST\n${raw_body}".encode("utf-8")
sig = hmac.new(api_key.encode("utf-8"), msg, hashlib.sha256).hexdigest()
return {"x-odesin-timestamp": ts, "x-odesin-signature": sig}
body = {
"mode": "card",
"amount": 199.90,
"return_url": "https://magazaniz.com/tesekkur",
"callback_url": "https://magazaniz.com/api/webhook",
"customer_name": "Ali Veli",
"customer_email": "ali@email.com",
"customer_phone": "05321234567",
}
raw = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
sig_h = odesin_sign_post(API_KEY, raw)
r = requests.post(
f"{BASE}/api/payment/create-session",
headers={"Content-Type": "application/json", "x-api-key": API_KEY, **sig_h},
data=raw.encode("utf-8"),
)
r.raise_for_status()
checkout_url = r.json()["checkout_url"]PHPcreate-session (kart / hosted)
<?php
$base = "https://odesin.com";
$apiKey = getenv('ODESIN_API_KEY') ?: '';
$payload = [
'mode' => 'card',
'amount' => 199.90,
'currency' => 'TRY',
'return_url' => 'https://magazaniz.com/tesekkur',
'callback_url' => 'https://magazaniz.com/api/webhook',
'customer_name' => 'Ali Veli',
'customer_email' => 'ali@email.com',
'customer_phone' => '05321234567',
'description' => 'Sipariş #4521',
];
$body = json_encode($payload, JSON_UNESCAPED_UNICODE);
$ts = (string) time();
$sig = hash_hmac('sha256', $ts . "
POST
" . $body, $apiKey);
$ch = curl_init($base . '/api/payment/create-session');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'x-api-key: ' . $apiKey,
'x-odesin-timestamp: ' . $ts,
'x-odesin-signature: ' . $sig,
],
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode($raw, true);checkout_url üzerindeki Odesin sayfasında tamamlanır; sunucunuz kart PAN/CVV görmez.Sık görülen hatalar
| HTTP | Durum |
|---|---|
| 403 | Mağazada Sanal POS kapalı (pos_enabled) |
| 400 | mode: "card" iken return_url eksik veya geçersiz gövde |
| 401 | İstek imzası geçersiz, zaman damgası ±5 dk dışında veya imza başlıklarından yalnızca biri gönderildi |
| 401 | API anahtarı eksik veya geçersiz |
| 402 / 409 / 410 | Kart reddi, oturum uygun değil veya süre dolmuş |