# Kimlik Doğrulama ve İstek İmzalama

> API isteklerini project UUID ve API key kullanarak HMAC-SHA256 ile imzalayın.

Her API isteği (gelen webhook'lar hariç) project UUID'nizi ve bir istek imzasını taşımalıdır. İmza, isteğin sizden geldiğini ve yolda kimsenin değiştirmediğini kanıtlar.

## API key'leri

2328.io, aynı imzalama algoritmasını paylaşan ancak farklı endpoint'leri kapsayan **iki anahtar** kullanır:

| Anahtar | Kullanım yeri |
|---------|---------------|
| **API key** | Ödemeler, statik cüzdanlar, bakiye, döviz kurları ve ödeme / statik cüzdan webhook'larının doğrulanması |
| **Payout API key** | Tüm `/v1/payout/*` endpoint'leri ve çekim webhook'larının doğrulanması |

Her iki anahtar da [2328.io](https://2328.io) üzerindeki proje ayarlarınızda yer alır. Aşağıdaki örneklerde "API key" genel olarak belirtilmiştir — çağırdığınız endpoint'e uygun olanını yerine koyun.

> **INFO:** İki anahtarı **asla** karıştırmayın: bir çekim isteğini normal API key ile (veya bir ödeme isteğini payout key ile) imzalamak imza hatası döner.

## Gerekli header'lar

| Header | Tip | Gerekli | Açıklama |
|--------|-----|---------|----------|
| `Content-Type` | string | evet | Her zaman `application/json` |
| `project` | string | evet | Project UUID'niz |
| `sign` | string | evet | API key'iniz ile hesaplanan isteğin HMAC-SHA256 imzası |
| `User-Agent` | string | evet | Uygulamanızı tanımlar (örn. `MyShop/1.4 (+https://myshop.example)`). `User-Agent` olmayan istekler engellenebilir. |

## İmza nasıl çalışır

İmzayı isteğin gövdesinin parmak izi gibi düşünün. Şu adımlarla oluşturulur:

1. Gövdeyi JSON'a serileştirin (kompakt — fazladan boşluk yok).
2. Bu JSON'u Base64 ile encode edin. Bu adım girdiyi diller arası normalleştirir — düz ASCII olduğunda her dil HMAC için aynı baytları üretir.
3. API key'inizi kullanarak Base64 string'inin **HMAC-SHA256**'sını hesaplayın, sonra sonucu küçük harf hex'e dönüştürün.

Gövdesiz **GET** ve diğer istek türleri için JSON yerine boş bir string'i imzalayın.

> **INFO:** Verilen bir API key için boş string imzası sabittir. Çok sayıda GET çağrısı yapıyorsanız bunu cache'leyebilirsiniz.

## Uygulamalar

<CodeSnippet name="apiSign" langs="php,js,ts,python,go" />

### Gövdesiz istekler (GET)

Boş gövdeli istekler için (örn. `GET /v1/payout/status/{uuid}`), boş bir string'i imzalayın:

<CodeSnippet name="apiSignBodyless" langs="curl,php,js,ts,python,go" />

## Tam istek örneği

<CodeSnippet name="fullRequestExample" langs="curl,php,js,ts,python,go" />

> **DANGER:** **API key'inizi asla istemci tarafı kodda açığa çıkarmayın.** İstekleri backend'inizde imzalayın. Sızdırılan bir API key, herkese merchant hesabınıza tam erişim verir.

## Webhook imzalarını doğrulama

2328.io size bir webhook gönderdiğinde, aynı algoritma ters yönde çalışır:

1. Payload'dan `sign` alanını çıkarın.
2. Kalan alanları JSON'a encode edin (kompakt, boşluksuz).
3. Bu string'i Base64 ile encode edin.
4. Uygun anahtarla `HMAC-SHA256` hesaplayın.
5. Bunu, alınan `sign` ile **sabit zamanlı** karşılaştırma kullanarak (`hash_equals`, `crypto.timingSafeEqual`, `hmac.compare_digest`, `subtle.ConstantTimeCompare`, `OpenSSL.fixed_length_secure_compare`) karşılaştırın.

İmzalama anahtarı webhook kaynağına bağlıdır:

| Webhook | Doğrulama anahtarı |
|---------|---------------------|
| Ödeme / statik cüzdan webhook'ları (`/v1/payment`, `/v1/static-wallet`) | **API key** |
| Çekim webhook'ları (`/v1/payout`) | **Payout API key** |

> **WARNING:** **Sık karşılaşılan doğrulama tuzakları.** JSON kodlayıcınız gönderenin ürettiği **birebir aynı baytları** üretmelidir — aksi halde Base64 farklılaşır ve imza eşleşmez.

- **Go**: `json.NewEncoder` ile `SetEscapeHTML(false)` kullanın. Varsayılan `json.Marshal`, `<`, `>`, `&` karakterlerini `<` olarak escape eder ve imzayı bozar.
- **Python**: `json.dumps` çağrısına `ensure_ascii=False` geçirin. Bu olmadan, ASCII olmayan karakterler (Kiril, Çince, …) `\uXXXX` olarak escape edilir.
- **Kompakt JSON**: alanlar arasında boşluk olmamalı (Python'da `separators=(",", ":")`).
- **Alan sırası** (Go): düz bir `map[string]any` yeniden kodlamada anahtarları rastgeleleştirir. `json.RawMessage`, sıralı bir struct kullanın ya da `sign` alanını ham baytlardan çıkarın.

Doğrulama hâlâ başarısız oluyorsa, payload üzerinde `apiSign` fonksiyonunu kendiniz çalıştırın — alınan `sign` ile aynı hex dizesini üretmelidir.

> **INFO:** **Geçerli bir imza yeniden oynatmaları (replay) engellemez.** Yalnızca webhook'un 2328.io'dan geldiğini kanıtlar — bir saldırganın *yakalanmış* bir webhook'u sonradan tekrar göndermesini engellemez. Fonları alacaklandırmadan önce her zaman `uuid` (veya statik cüzdanlar için `txid`) ile idempotency kontrolü yapın. İmza eksik veya yanlışsa HTTP `401` ile reddedin.

Tam kod örnekleri **[Webhook Notifications](/docs/webhooks#verifying-the-signature)** sayfasındadır. Yeniden deneme yönetimi ve idempotency kuralları [En iyi uygulamalar](/docs/webhooks#best-practices) bölümünde bulunur.