Geliştiriciler/Başlarken

Kimlik doğrulama

Her API isteği Merchant ID'nizi ve API anahtarınızı taşır. Sipariş verirken (POST/orders) ayrıca bir imza gönderilir. Böylece kimse siparişi değiştiremez veya tekrarlayamaz.

İlgili: Ürünler ve siparişler · Güvenlik · README

#Kimlik bilgileri

BilgiÖrnekGizli mi?
Merchant IDM00000001Hayır. Kim olduğunuzu gösterir.
API anahtarıcvb2b_...Evet. Hem şifreniz hem de imzalama anahtarınızdır.
  • Merchant ID, hesabınız onaylandığında CardV tarafından verilir.
  • API anahtarını Portal'da bir Owner oluşturur (bkz. API anahtarları).
  • Live ve Sandbox'ın anahtarları ayrıdır. Bir ortamın anahtarı diğerinde asla çalışmaz.
  • API, ancak CardV işletmenizi onayladıktan sonra çalışır. Onaydan sonra GET/account yanıtında "api_access_enabled": true görünür.

#Başlıklar

Her istekte şu iki başlığı gönderin:

HTTP
X-Merchant-Id: M00000001
X-Api-Key: cvb2b_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

POST/orders isteğinde bunlara ek olarak şu üçünü de gönderin:

HTTP
X-Timestamp: 1790000000
X-Nonce: 0123456789abcdef0123456789abcdef
X-Signature: fd55fa31a3b6817d5368903dbb4bad4458381e024c17e688580bac96577acfed
  • X-Timestamp, saniye cinsinden şu anki Unix zamanıdır. CardV'nin saatinden en fazla 5 dakika (300 saniye) farklı olabilir.
  • X-Nonce, bir daha asla kullanmayacağınız rastgele bir değerdir. 32 karakterlik rastgele bir hex değer kullanın.
  • X-Signature, Sipariş imzalama bölümünde anlatılıyor. Küçük harfli hex olmalıdır.

GET isteklerinde imza gerekmez.

#Sipariş imzalama

  1. Siparişinizi bir kez JSON metnine çevirin. İmzalayacağınız ve göndereceğiniz bayt dizisi tam olarak budur.

  2. Gövdenin özetini alın: BODY_HASH = gövdenin SHA-256 özeti, küçük harfli hex olarak.

  3. Şu beş satırı yeni satır karakteriyle (\n) birleştirin. Sonuna yeni satır eklemeyin:

    Text
    POST
    /api/v1/orders
    <X-Timestamp>
    <X-Nonce>
    <BODY_HASH>
  4. Metni imzalayın: X-Signature = bu metnin HMAC-SHA256 değeri. Anahtar olarak API anahtarınızın tamamını kullanın. Sonucu küçük harfli hex olarak yazın.

En sık yapılan hata, JSON'un bir halini imzalayıp başka bir halini göndermektir. Örneğin {"a":1} ile {"a": 1} farklı bayt dizileridir. Kullandığınız HTTP kütüphanesinin gövdeyi imzaladıktan sonra değiştirmediğinden emin olun.

Test verisi. Kodunuzu bu değerlerle kontrol edin. Anahtar sahtedir.

Text
API key      cvb2b_TEST_ONLY_not_a_real_key_0123456789abcdef
Method       POST
Path         /api/v1/orders
X-Timestamp  1790000000
X-Nonce      0123456789abcdef0123456789abcdef

Gövde (108 bayt, tek satır, sonunda yeni satır yok):

JSON
{"external_order_id":"TEST-0001","items":[{"sku_id":"S000001","quantity":1,"expected_unit_price":"9.2500"}]}

Beklenen sonuçlar:

Text
BODY_HASH    b0545ae25d54b219f27d8bd90e4dcbf26cf0d491f53982da67b8eef0a1a59960
X-Signature  fd55fa31a3b6817d5368903dbb4bad4458381e024c17e688580bac96577acfed

#Kod örnekleri

Tüm örnekler test verisindeki sonucu üretir. Anahtarı koda yazmayın, gizli bilgi deponuzdan okuyun.

cURL (bash + OpenSSL)

Shell
BASE_URL="https://sandbox.cardv.net"
REQ_PATH="/api/v1/orders"      # do not call this variable PATH
BODY='{"external_order_id":"SHOP-10001","items":'
BODY+='[{"sku_id":"S000001","quantity":1,"expected_unit_price":"9.2500"}]}'
TS=$(date +%s)
NONCE=$(openssl rand -hex 16)
BODY_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | sed 's/^.*= //')
SIG=$(printf 'POST\n%s\n%s\n%s\n%s' "$REQ_PATH" "$TS" "$NONCE" "$BODY_HASH" \
  | openssl dgst -sha256 -hmac "$CARDV_API_KEY" -hex | sed 's/^.*= //')

curl -sS -X POST "$BASE_URL$REQ_PATH" \
  -H "Content-Type: application/json" \
  -H "X-Merchant-Id: $CARDV_MERCHANT_ID" \
  -H "X-Api-Key: $CARDV_API_KEY" \
  -H "X-Timestamp: $TS" \
  -H "X-Nonce: $NONCE" \
  -H "X-Signature: $SIG" \
  --data-raw "$BODY"

-d @file yerine --data-raw kullanın. -d yeni satırları siler ve gönderilen baytlar imzayla eşleşmez.

Python (requests)

Python
import hashlib, hmac, json, os, secrets, time
import requests

BASE_URL = "https://sandbox.cardv.net"
MERCHANT_ID = os.environ["CARDV_MERCHANT_ID"]
API_KEY = os.environ["CARDV_API_KEY"]
AUTH = {"X-Merchant-Id": MERCHANT_ID, "X-Api-Key": API_KEY}


def sign(path: str, body: bytes, ts: str, nonce: str) -> str:
    body_hash = hashlib.sha256(body).hexdigest()
    text = "\n".join(["POST", path, ts, nonce, body_hash])
    return hmac.new(API_KEY.encode(), text.encode(), hashlib.sha256).hexdigest()


def cardv_get(path: str, params=None) -> requests.Response:
    return requests.get(BASE_URL + path, params=params, headers=AUTH, timeout=30)


def cardv_post(path: str, payload: dict) -> requests.Response:
    body = json.dumps(payload, separators=(",", ":"), ensure_ascii=False).encode()
    ts, nonce = str(int(time.time())), secrets.token_hex(16)
    headers = {
        **AUTH,
        "Content-Type": "application/json",
        "X-Timestamp": ts,
        "X-Nonce": nonce,
        "X-Signature": sign(path, body, ts, nonce),
    }
    return requests.post(BASE_URL + path, data=body, headers=headers, timeout=30)


resp = cardv_post("/api/v1/orders", {
    "external_order_id": "SHOP-10001",
    "items": [{"sku_id": "S000001", "quantity": 1, "expected_unit_price": "9.2500"}],
})
print(resp.status_code, resp.json())

order_id = resp.json()["order"]["order_id"]
print(cardv_get(f"/api/v1/orders/{order_id}").json()["status"])

Node.js 18+ (yerleşik fetch)

Node.js
import crypto from "node:crypto";

const BASE_URL = "https://sandbox.cardv.net";
const { CARDV_MERCHANT_ID, CARDV_API_KEY } = process.env;
const AUTH = { "X-Merchant-Id": CARDV_MERCHANT_ID, "X-Api-Key": CARDV_API_KEY };

function sign(path, body, timestamp, nonce) {
  const bodyHash = crypto.createHash("sha256").update(body).digest("hex");
  const text = ["POST", path, timestamp, nonce, bodyHash].join("\n");
  return crypto.createHmac("sha256", CARDV_API_KEY).update(text, "utf8").digest("hex");
}

async function cardvPost(path, payload) {
  const body = Buffer.from(JSON.stringify(payload), "utf8"); // serialize once
  const timestamp = String(Math.floor(Date.now() / 1000));
  const nonce = crypto.randomBytes(16).toString("hex");
  const headers = {
    ...AUTH,
    "Content-Type": "application/json",
    "X-Timestamp": timestamp,
    "X-Nonce": nonce,
    "X-Signature": sign(path, body, timestamp, nonce),
  };
  const res = await fetch(BASE_URL + path, { method: "POST", headers, body });
  return { status: res.status, body: await res.json() };
}

console.log(await cardvPost("/api/v1/orders", {
  external_order_id: "SHOP-10001",
  items: [{ sku_id: "S000001", quantity: 1, expected_unit_price: "9.2500" }],
}));

PHP (yalnızca imzalama)

PHP
<?php
function cardv_sign(
    string $apiKey, string $path, string $body, string $ts, string $nonce
): string {
    $text = implode("\n", ['POST', $path, $ts, $nonce, hash('sha256', $body)]);
    return hash_hmac('sha256', $text, $apiKey); // lowercase hex
}

// Send exactly $body.
$body = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
$ts = (string) time();
$nonce = bin2hex(random_bytes(16));
$signature = cardv_sign($apiKey, '/api/v1/orders', $body, $ts, $nonce);

#Hatalar

Bu hataların tümü HTTP 403 döner (401 değil). Tek istisna istek limitidir, o 429 döner. Yanıt gövdesi şöyle görünür:

JSON
{"detail": "Invalid HMAC signature."}
SorunNe yapmalı
Merchant ID veya API anahtarı eksik ya da hatalıİki başlığı ve ortamı kontrol edin.
API erişimi açık değilCardV'nin işletmenizi onaylamasını bekleyin.
Sunucunuzun IP adresine izin verilmiyorIP adresini Portal'daki IP izin listesine ekleyin.
Uç nokta yalnızca Portal'da kullanılabiliyorPortal'ı kullanın. Anahtarla yalnızca yedi uç nokta çalışır.
İmza eksik veya hatalıİmzalama kodunuzu düzeltin. Test verisiyle deneyin.
Zaman damgası çok eski veya çok ileriSunucu saatinizi senkronize edin (NTP).
Nonce daha önce kullanılmışHer sipariş isteğinde yeni bir rastgele nonce kullanın.
Çok fazla istek (429)Retry-After içindeki saniye kadar bekleyip tekrar deneyin.

Önemli:

  • Bir siparişi yeniden gönderirken zaman damgası, nonce ve imzayı yeniden oluşturun. Gövde aynı kalsın. Bkz. güvenli yeniden deneme.
  • İmza hatalı olsa bile nonce kullanılmış sayılır.
  • CardV başarısız denemeleri kaydeder, sayıları artarsa ekibini uyarır.

#IP izin listesi

IP izin listesi, anahtarınızı yalnızca sizin sunucularınızın kullanmasını sağlar. Listeyi Portal'dan yönetirsiniz (Owner).

  • Kullanmak zorunlu değildir. Hiç kural yoksa her IP adresinden gelen istek kabul edilir.
  • En az bir kural varsa, diğer IP adreslerinden gelen istekler HTTP 403 alır.
  • Kurallar 203.0.113.10/32 (IPv4) veya 2001:db8::/48 (IPv6) biçimindedir.
  • Liste yalnızca API anahtarıyla yapılan istekler için geçerlidir, Portal girişini etkilemez.
  • Listeyi açmadan önce NAT ağ geçitleri ve yedek bölgeler dahil tüm sunucu IP adreslerinizi ekleyin.

#API anahtarları

Bir API anahtarı, Kısaca API bölümündeki yedi uç noktayı kullanabilir, fazlasını değil. Buna sipariş vermek ve kodları okumak da dahildir. Bu yüzden anahtarı bir Owner şifresi gibi koruyun.

Anahtarları yalnızca Owner yönetebilir: Portal'da Integrations → API keys bölümünden. Bu işlemi Live ve Sandbox için ayrı ayrı yapın.

  1. Oluşturun: Anahtara bir ad verin. Portal anahtarı henüz göstermez.
  2. Görüntüleyin (Reveal): CardV size 6 haneli bir kod e-postalar. Kod 10 dakika geçerlidir (5 deneme hakkı). Kodu girince anahtarın tamamı görünür. Hemen kaydedin. Her görüntüleme kayda geçer.
  3. Devre dışı bırakın: Artık ihtiyacınız olmayan anahtarı kapatın. Bu işlem anında ve kalıcı olarak uygulanır.

Kesinti yaşamadan anahtar değiştirmek için:

  1. Yeni bir anahtar oluşturun ve görüntüleyin.
  2. Yeni anahtarı tüm sunucularınıza dağıtın.
  3. Eski anahtarın artık kullanılmadığını Portal'dan kontrol edin.
  4. Eski anahtarı devre dışı bırakın.

Anahtarları en az yılda bir kez ve erişimi olan biri ayrıldığında mutlaka değiştirin. Bir anahtarın sızmış olabileceğinden şüpheleniyorsanız önce anahtarı kapatın, sonra inceleyin.

Entegrasyonla ilgili sorunuz mu var? Merchant ID’nizi ve sipariş ya da istek kimliğini ekleyerek [email protected] adresine yazın.