Rubikpara

Kimlik Doğrulama

PF Gateway API'ye yapılan isteklerde HMAC tabanlı kimlik doğrulama ve imza oluşturma rehberi.

PF Gateway API, her istekte HMAC-SHA256 tabanlı kimlik doğrulama kullanır. Bu sayede isteklerin yetkili bir kaynaktan geldiği ve iletim sırasında değiştirilmediği doğrulanır.

Gerekli Bilgiler

Entegrasyona başlamadan önce aşağıdaki bilgilere sahip olmanız gerekir:

PublicKey (API Key)

Üye işyerine ait açık anahtar. Her istekte header veya form field olarak gönderilir.

SecretKey (API Secret)

Üye işyerine ait gizli anahtar (Base64 encoded). Yalnızca imza oluşturmada kullanılır, asla istekte gönderilmez.

MerchantNumber

Üye işyeri numarası. Her istekte header veya form field olarak gönderilir.


İmza Oluşturma Algoritması

İmza 2 aşamalı HMAC-SHA256 ile oluşturulur. Her iki aşamada da key olarak SecretKey Base64 decode edilerek kullanılır.

SecretKey size Base64 encoded olarak verilir. HMAC hesaplamalarında bu değeri önce Base64 decode edip byte dizisine çevirmeniz gerekir. Direkt string olarak kullanmayın.

Algoritma Özeti

Adım 1 — SecurityData hesapla:
  message       = PublicKey + Nonce
  securityData  = HMAC-SHA256(message, Base64Decode(SecretKey)) → Base64

Adım 2 — Signature hesapla:
  payload       = SecretKey + ConversationId + Nonce + SecurityData
  signature     = HMAC-SHA256(payload, Base64Decode(SecretKey)) → Base64

Adım Adım İmza Oluşturma

1. Nonce ve ConversationId Oluşturun

Her istek için benzersiz bir Nonce (milisaniye cinsinden zaman damgası) ve ConversationId oluşturun.

string nonce = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
string conversationId = Guid.NewGuid().ToString("N")[..8];
const nonce = Date.now().toString();
const conversationId = crypto.randomUUID().slice(0, 8);
import time
import uuid

nonce = str(int(time.time() * 1000))
conversation_id = uuid.uuid4().hex[:8]
$nonce = (string) round(microtime(true) * 1000);
$conversationId = substr(str_replace('-', '', (string) \Ramsey\Uuid\Uuid::uuid4()), 0, 8);
// veya UUID kütüphanesi kullanmadan:
// $conversationId = substr(bin2hex(random_bytes(4)), 0, 8);

2. SecurityData Hesaplayın (1. HMAC)

PublicKey ve Nonce değerlerini birleştirip HMAC-SHA256 ile hash'leyin.

message      = PublicKey + Nonce
securityData = HMAC-SHA256(message, key: Base64Decode(SecretKey)) → Base64
byte[] secretKeyBytes = Convert.FromBase64String(secretKey);

string message = publicKey + nonce;

using var hmac = new HMACSHA256(secretKeyBytes);
string securityData = Convert.ToBase64String(
    hmac.ComputeHash(Encoding.UTF8.GetBytes(message))
);
const secretKeyBytes = Buffer.from(secretKey, 'base64');

const message = publicKey + nonce;

const securityData = createHmac('sha256', secretKeyBytes)
    .update(message, 'utf8')
    .digest('base64');
secret_key_bytes = base64.b64decode(secret_key)

message = public_key + nonce

security_data = base64.b64encode(
    hmac.new(secret_key_bytes, message.encode('utf-8'), hashlib.sha256).digest()
).decode('utf-8')
$secretKeyBytes = base64_decode($secretKey);

$message = $publicKey . $nonce;

$securityData = base64_encode(
    hash_hmac('sha256', $message, $secretKeyBytes, true)
);

3. Signature Hesaplayın (2. HMAC)

SecretKey, ConversationId, Nonce ve bir önceki adımda hesapladığınız SecurityData değerlerini birleştirip tekrar HMAC-SHA256 ile hash'leyin.

payload   = SecretKey + ConversationId + Nonce + SecurityData
signature = HMAC-SHA256(payload, key: Base64Decode(SecretKey)) → Base64
string payload = secretKey + conversationId + nonce + securityData;

using var hmac = new HMACSHA256(secretKeyBytes);
string signature = Convert.ToBase64String(
    hmac.ComputeHash(Encoding.UTF8.GetBytes(payload))
);
const payload = secretKey + conversationId + nonce + securityData;

const signature = createHmac('sha256', secretKeyBytes)
    .update(payload, 'utf8')
    .digest('base64');
payload = secret_key + conversation_id + nonce + security_data

signature = base64.b64encode(
    hmac.new(secret_key_bytes, payload.encode('utf-8'), hashlib.sha256).digest()
).decode('utf-8')
$payload = $secretKey . $conversationId . $nonce . $securityData;

$signature = base64_encode(
    hash_hmac('sha256', $payload, $secretKeyBytes, true)
);

Tam Kod Örneği

Yukarıdaki adımların hepsini birleştiren, kopyala-yapıştır kullanıma hazır fonksiyonlar:

using System;
using System.Security.Cryptography;
using System.Text;

public sealed class PfSignatureService
{
    private readonly byte[] _secretKeyBytes;
    private readonly string _publicKey;
    private readonly string _secretKey;

    public PfSignatureService(string publicKey, string secretKey)
    {
        _publicKey = publicKey;
        _secretKey = secretKey;
        _secretKeyBytes = Convert.FromBase64String(secretKey);
    }

    public SignatureResult CreateSignature(string? conversationId = null)
    {
        string nonce = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
        conversationId ??= Guid.NewGuid().ToString("N")[..8];

        // 1. SecurityData
        string securityData = ComputeHmac(_publicKey + nonce);

        // 2. Signature
        string signature = ComputeHmac(_secretKey + conversationId + nonce + securityData);

        return new SignatureResult(nonce, signature, conversationId);
    }

    private string ComputeHmac(string data)
    {
        using var hmac = new HMACSHA256(_secretKeyBytes);
        return Convert.ToBase64String(
            hmac.ComputeHash(Encoding.UTF8.GetBytes(data))
        );
    }
}

public record SignatureResult(string Nonce, string Signature, string ConversationId);

// Kullanım:
// var service = new PfSignatureService("YOUR_PUBLIC_KEY", "YOUR_SECRET_KEY");
// var result = service.CreateSignature();
// Console.WriteLine(result.Signature);
import { createHmac } from 'node:crypto';

class PfSignatureService {
    #secretKeyBytes;
    #publicKey;
    #secretKey;

    constructor(publicKey, secretKey) {
        this.#publicKey = publicKey;
        this.#secretKey = secretKey;
        this.#secretKeyBytes = Buffer.from(secretKey, 'base64');
    }

    createSignature(conversationId) {
        const nonce = Date.now().toString();
        conversationId ??= crypto.randomUUID().slice(0, 8);

        // 1. SecurityData
        const securityData = this.#computeHmac(this.#publicKey + nonce);

        // 2. Signature
        const signature = this.#computeHmac(
            this.#secretKey + conversationId + nonce + securityData
        );

        return { nonce, signature, conversationId };
    }

    #computeHmac(data) {
        return createHmac('sha256', this.#secretKeyBytes)
            .update(data, 'utf8')
            .digest('base64');
    }
}

// Kullanım:
// const service = new PfSignatureService('YOUR_PUBLIC_KEY', 'YOUR_SECRET_KEY');
// const { nonce, signature, conversationId } = service.createSignature();
import hmac
import hashlib
import base64
import time
import uuid
from dataclasses import dataclass


@dataclass(frozen=True)
class SignatureResult:
    nonce: str
    signature: str
    conversation_id: str


class PfSignatureService:
    def __init__(self, public_key: str, secret_key: str):
        self._public_key = public_key
        self._secret_key = secret_key
        self._secret_key_bytes = base64.b64decode(secret_key)

    def create_signature(self, conversation_id: str | None = None) -> SignatureResult:
        nonce = str(int(time.time() * 1000))
        conversation_id = conversation_id or uuid.uuid4().hex[:8]

        # 1. SecurityData
        security_data = self._compute_hmac(self._public_key + nonce)

        # 2. Signature
        signature = self._compute_hmac(
            self._secret_key + conversation_id + nonce + security_data
        )

        return SignatureResult(nonce, signature, conversation_id)

    def _compute_hmac(self, data: str) -> str:
        return base64.b64encode(
            hmac.new(self._secret_key_bytes, data.encode('utf-8'), hashlib.sha256).digest()
        ).decode('utf-8')


# Kullanım:
# service = PfSignatureService('YOUR_PUBLIC_KEY', 'YOUR_SECRET_KEY')
# result = service.create_signature()
# print(result.signature)
<?php

class PfSignatureService
{
    private string $publicKey;
    private string $secretKey;
    private string $secretKeyBytes;

    public function __construct(string $publicKey, string $secretKey)
    {
        $this->publicKey = $publicKey;
        $this->secretKey = $secretKey;
        $this->secretKeyBytes = base64_decode($secretKey);
    }

    public function createSignature(?string $conversationId = null): array
    {
        $nonce = (string) round(microtime(true) * 1000);
        $conversationId = $conversationId ?? substr(bin2hex(random_bytes(4)), 0, 8);

        // 1. SecurityData
        $securityData = $this->computeHmac($this->publicKey . $nonce);

        // 2. Signature
        $signature = $this->computeHmac(
            $this->secretKey . $conversationId . $nonce . $securityData
        );

        return [
            'nonce'          => $nonce,
            'signature'      => $signature,
            'conversationId' => $conversationId,
        ];
    }

    private function computeHmac(string $data): string
    {
        return base64_encode(
            hash_hmac('sha256', $data, $this->secretKeyBytes, true)
        );
    }
}

// Kullanım:
// $service = new PfSignatureService('YOUR_PUBLIC_KEY', 'YOUR_SECRET_KEY');
// $result  = $service->createSignature();
// echo $result['signature'];

İstek Header'ları

Oluşturduğunuz değerleri HTTP header'larına ekleyin:

HeaderAçıklama
PublicKeyÜye işyerine ait açık anahtar
NonceHer istek için benzersiz zaman damgası (milisaniye)
Signature2 aşamalı HMAC-SHA256 ile oluşturulan imza (Base64)
ConversationIdİstek takip numarası
MerchantNumberÜye işyeri numarası
ClientIpAddressİşlem yapan kullanıcının IP adresi
POST /v1/Payments/provision HTTP/1.1
Content-Type: application/json
PublicKey: your-public-key
Nonce: 1770882490683
Signature: cQli2lp3XcVgcamhxw793sFbPwsnPZ8JJOTH...
ConversationId: conv-123456
MerchantNumber: 000001
ClientIpAddress: 192.168.1.1

Base URL: https://testpfapi.rubikpara.com

Bazı endpoint'lerde (ör. /v1/Tokens, /v1/ThreeDS/init3ds) bu değerler header yerine form field olarak gönderilir. Her endpoint'in dokümantasyonunu kontrol edin.


Test Ortamı

Geliştirme sırasında imza oluşturmayı kendi sunucunuzda yapmak yerine, Test İmzası Oluştur endpoint'ini kullanabilirsiniz.

Bu endpoint yalnızca test ortamında kullanılabilir. Prodüksiyon ortamında imzayı yukarıdaki algoritma ile kendi sunucunuzda oluşturmalısınız.

Test İmzası Oluşturma

POST /v1/Signatures/generate-test-signature
Content-Type: application/json

{
  "publicKey": "your-public-key",
  "merchantNumber": "000001",
  "conversationId": "conv-123456"
}
Yanıt
{
  "publicKey": "your-public-key",
  "nonce": "1770629965755",
  "signature": "dZspDJX18zdC1MnX4d0mhIX0F3IitK0+DQb5ZyxqR3U=",
  "conversationId": "conv-123456",
  "merchantId": "e7051f0d-0e16-406f-a518-310a4b92dae4"
}

Dönen Değerleri Kullanma

Yanıttaki değerleri doğrudan hedef API isteğine aktarın:

Yanıt AlanıHedef ParametreAçıklama
publicKeyPublicKeyAçık anahtar
nonceNonceBenzersiz istek kimliği
signatureSignatureHesaplanmış HMAC imzası
conversationIdConversationIdİstek takip numarası

Her API isteği için yeni bir imza oluşturmanız gerekir. Aynı Nonce ve Signature değerleri tekrar kullanılamaz.


Kimlik Doğrulama Gereken Endpoint'ler

On this page