> ## Documentation Index
> Fetch the complete documentation index at: https://docs.payven.com.tr/llms.txt
> Use this file to discover all available pages before exploring further.

# API Anahtarı En İyi Uygulamaları

> client_secret yönetimi, sızıntı önleme ve operasyonel güvenlik.

Payven API'lerine erişim **OAuth 2.0 Client Credentials** akışı ile sağlanır:
`client_id` + `client_secret` → access token. `client_secret`, organizasyonunuz adına işlem yapma yetkisidir; sızdığında saldırganın elinde sizin adınıza ödeme oluşturma kapısı olur.

Aşağıdaki kurallara uymak sızıntı riskini ve sızıntı sonrası etkiyi minimuma indirir. Auth akışının tamamı için: [Kimlik Doğrulama](/documentation/concepts/authentication).

## Kuralname

<Check>**Asla kaynak kodda tutmayın** — `client_secret`'ı `.env`, secret manager veya environment variable olarak yönetin.</Check>
<Check>**Asla istemcide tutmayın** — tarayıcı, mobil uygulama veya desktop client'a göndermeyin. Token alma sunucu tarafında yapılmalı; istemciye yalnızca kısa ömürlü access token gider.</Check>
<Check>**Asla loglara yazmayın** — log framework'ünüzde request/response loglama açıksa `Authorization` header'ı ile `client_secret` body alanını maskeleyin.</Check>
<Check>**Asla destek ekibine paylaşmayın** — Payven destek ekibi sizden `client_secret` istemez.</Check>
<Check>**Sandbox ve production'ı ayırın** — farklı client'lar, farklı secret store'lar.</Check>
<Check>**IP whitelist tanımlayın** — production client'ları için zorunlu kabul edin (Identity tarafında enforce edilir).</Check>
<Check>**Düzenli rotasyon** — minimum 6 ayda bir, sızıntı şüphesinde anında.</Check>
<Check>**Audit logları izleyin** — konsoldaki API kayıtları ekranından beklenmeyen istek varsa hemen tepki verin.</Check>
<Check>**Token cache uygulayın** — her istek öncesi yeni token almayın; access token süresi dolmadan (60sn margin) refresh edin.</Check>

## Saklama önerileri

| Ortam      | Önerilen secret store                                   |
| ---------- | ------------------------------------------------------- |
| AWS        | AWS Secrets Manager veya Parameter Store (SecureString) |
| Azure      | Azure Key Vault                                         |
| GCP        | Secret Manager                                          |
| Kubernetes | External Secrets Operator + cloud KMS                   |
| On-premise | HashiCorp Vault                                         |
| Geliştirme | `.env` (commit edilmez) + `direnv` veya `dotenv`        |

## Çoklu client stratejisi

Tek bir client'la çalışmak yerine **işlevlere göre ayrılmış** client'lar oluşturmanız önerilir:

| Client             | Kullanım                                                                     |
| ------------------ | ---------------------------------------------------------------------------- |
| `payments-prod`    | Sadece ödeme alma servisinde kullanılan production client'ı                  |
| `reporting-prod`   | Sadece raporlama job'larında kullanılan, daha kısıtlı IP whitelist'li client |
| `dev-team-sandbox` | Geliştirici ekibinin paylaştığı sandbox client'ı                             |

Avantajlar: Bir `client_secret` sızdığında etki alanı sınırlı kalır, audit'lerde hangi servisin ne yaptığını ayırt etmek kolaylaşır.

## Rotasyon prosedürü

Sıfır kesinti ile rotasyon:

<Steps>
  <Step title="Yeni client veya secret üretin">
    Konsol → API Anahtarları → **Yeni Client Oluştur** (veya mevcut client için **Secret Rotate**). Mevcut secret'ı **silmeyin** — Identity, geçiş süresince eski ve yeni secret'ı geçici olarak birlikte kabul eder.
  </Step>

  <Step title="Yeni secret'ı secret store'a yazın">
    Production secret manager'ında yeni değeri kaydedin.
  </Step>

  <Step title="Servisinizi yeniden deploy edin">
    Yeni secret ile başlayan servis pod/instance'ları çalışmaya başlasın. Eski olanlar hâlâ eski secret'la çalışıyor — geçiş penceresinde ikisi de geçerli.
  </Step>

  <Step title="Audit log'u izleyin">
    Konsol → API Kayıtları ekranında eski secret'a gelen istek olup olmadığını izleyin. Trafik sıfıra inene dek bekleyin.
  </Step>

  <Step title="Eski secret'ı pasife alın">
    Trafik tamamen kesildiğinde eski secret'ı revoke edin.
  </Step>
</Steps>

## Sızıntı şüphesinde acil müdahale

`client_secret`'ınızın sızdığını düşündüğünüz an aşağıdaki adımları **paralel** uygulayın:

<Steps>
  <Step title="Secret'ı hemen revoke edin">
    Konsoldan client'ı **pasife çekin** veya secret'ı rotate edin. Süreç anlıktır.
  </Step>

  <Step title="Yeni secret üretip servisinizi rotasyona alın">
    Yukarıdaki adımları hızlandırılmış şekilde uygulayın.
  </Step>

  <Step title="Audit log incelemesi">
    Sızıntı penceresinde gerçekleşen tüm işlemleri konsol → API Kayıtları'ndan ekstrakt edin.
  </Step>

  <Step title="Destek ekibine bildirin">
    [Destek talebi](/resources/support) açın — etki analizi konusunda yardım alın.
  </Step>
</Steps>

## Loglama kuralı

Request/response loglaması yapan kütüphaneler için header maskeleme örneği:

<CodeGroup>
  ```csharp C# theme={null}
  public class SensitiveHeaderRedactor : DelegatingHandler
  {
      private static readonly string[] SensitiveHeaders =
      {
          "Authorization"
      };

      protected override async Task<HttpResponseMessage> SendAsync(
          HttpRequestMessage request, CancellationToken ct)
      {
          var clone = new HttpRequestMessage(request.Method, request.RequestUri);
          foreach (var header in request.Headers)
          {
              var value = SensitiveHeaders.Contains(header.Key, StringComparer.OrdinalIgnoreCase)
                  ? new[] { "***REDACTED***" }
                  : header.Value.ToArray();
              clone.Headers.Add(header.Key, value);
          }
          // logger logs `clone`, sends `request`
          return await base.SendAsync(request, ct);
      }
  }
  ```

  ```javascript Node.js theme={null}
  function redactSensitive(headers) {
    const sensitive = ["authorization"];
    const safe = {};
    for (const [k, v] of Object.entries(headers)) {
      safe[k] = sensitive.includes(k.toLowerCase()) ? "***REDACTED***" : v;
    }
    return safe;
  }

  // Token alma isteklerinde body'deki client_secret'ı da maskelemeyi unutmayın
  function redactBody(body) {
    if (typeof body !== "object" || body === null) return body;
    const safe = { ...body };
    if (safe.client_secret) safe.client_secret = "***REDACTED***";
    if (safe.refresh_token) safe.refresh_token = "***REDACTED***";
    return safe;
  }

  logger.info("payven request", {
    url,
    headers: redactSensitive(headers),
    body: redactBody(body),
  });
  ```
</CodeGroup>
