# Kimlik Doğrulama

Bir `/v1/api` rotasına yapılan her istek, bir tenant API anahtarıyla kimlik doğrulamasından geçer. Anahtar, tek bir mağazaya (tenant'a) ait bir bearer token'dır: hem isteği doğrular hem de mağazayı seçer; bu nedenle ayrı bir tenant tanımlayıcısına veya header'ına hiçbir zaman gerek yoktur. Bu sayfa anahtarların nasıl çalıştığını, hangi scope'ların bulunduğunu, kimlik endpoint'ini ve bir mağaza askıya alındığında ne olduğunu ele alır.

## API anahtarları

API anahtarı, tek bir mağaza için verilen uzun ömürlü gizli bir token'dır. Anahtarların süresi dolmaz; merchant tarafından iptal edilene kadar geçerli kalırlar. Düz metin anahtar yalnızca bir kez, oluşturma anında gösterilir. Anahtarı hemen bir secret manager'da saklayın; tekrar görüntülenemez.

Merchant'lar anahtarları client dashboard'da (app.borkol.com) Settings > API keys altında oluşturur ve iptal eder. Oluşturma sırasında merchant, anahtar için bir ad ve bir scope kümesi seçer. Dashboard her anahtarın adını, scope'larını, son kullanım zamanını ve oluşturulma zamanını listeler ve bir anahtarı istediği anda iptal edebilir. İptal edilen bir anahtar derhal çalışmayı durdurur: onunla yapılan istekler `401 {"message": "Unauthenticated."}` döndürür.

Anahtarı her istekte `Authorization` header'ında gönderin:

```
Authorization: Bearer {api_key}
```

`/v1/api` rotalarında `X-Tenant-Id` header'ı yoktur ve okunmaz. Mağaza bağlamı tamamen anahtardan türetilir.

## Scope'lar

Her anahtar, oluşturma sırasında verilen bir scope kümesi taşır. Scope'lar endpoint'leri korur: anahtarın taşımadığı bir scope gerektiren bir rota `403 {"message": "Invalid ability provided."}` döndürür.

Scope adları `{module}:{read|write}` desenini izler. Tam küme:

| Scope | Verdiği yetki |
| --- | --- |
| `tenant:read` | Temel mağaza kimliği erişimi (`GET /v1/api/business`, yönlendirme ve sitemap endpoint'leri). Her zaman verilebilir. |
| `catalog:read` | Ürünler, kategoriler ve configurator endpoint'leri. Aynı rotalarda `commerce:read` de kabul edilir. |
| `catalog:write` | Verilebilir; henüz hiçbir `/v1/api` rotası kullanmaz. |
| `commerce:read` | Sepetler (okuma), siparişler ve `catalog:read` veya `sales:read` kabul edilen her yer. |
| `commerce:write` | Sepetler (yazma), checkout, teklif istekleri ve `sales:write` kabul edilen her yer. |
| `configurator:read` / `configurator:write` | Verilebilir; configurator endpoint'leri bunları değil `catalog:read` veya `commerce:read` scope'unu denetler. |
| `contacts:read` | Müşteri hesabı GET endpoint'leri (`/v1/api/contacts/*`). |
| `contacts:write` | Müşteri kaydı, giriş, çıkış, parola sıfırlama, profil ve adres değişiklikleri. |
| `customers:read` / `customers:write` | `contacts:read` / `contacts:write` scope'larının eski adları. Hâlâ verilebilir ve aynı rotalarda kabul edilir; böylece yeniden adlandırmadan önce oluşturulan anahtarlar çalışmaya devam eder. |
| `sales:read` | Token ile bir teklifi okuma (`GET /v1/api/sales/quotes/by-token/{token}`). |
| `sales:write` | Token ile bir teklifi kabul etme veya reddetme. |
| `stock:read` | Stok seviyeleri (`GET /v1/api/stock/*`). |
| `stock:write` | Verilebilir; henüz hiçbir `/v1/api` rotası kullanmaz. |
| `objects:read` | Nesne türleri ve kayıtları (`GET /v1/api/objects/*`) ve sitemap. |
| `objects:write` | Verilebilir; henüz hiçbir `/v1/api` rotası kullanmaz. |
| `forms:read` | Yayınlanmış formları yükleme (`GET /v1/api/forms/{key}`) ve adres arama. |
| `forms:write` | Form dosya alanları için dosya yükleme (`POST /v1/api/forms/{key}/uploads`) ve form başvurusu gönderme (`POST /v1/api/forms/{key}/submissions`). Yalnızca sunucu tarafında; aşağıya bakın. |

Herkese açık yüzeyi olmayan bir modül (payroll) de izin adlarını scope olarak sunar; hiçbir `/v1/api` rotası bunları kullanmaz. Bir rota iki scope listelediğinde, ikisinden birini taşıyan anahtar geçer: eski `commerce:*` ailesi, commerce modülünün catalog, commerce ve sales olarak bölünmesinden öncesine aittir ve üçünde de kabul edilir.

Bir merchant yalnızca mağazasında o an etkin olan modüllerin scope'larını verebilir: verilebilir küme her zaman `tenant:read` artı etkin her modülün `{module}:read` ve `{module}:write` çiftidir. Anahtar oluşturma sırasında kullanılamayan bir scope talep etmek, dashboard akışında 422 ile başarısız olur.

**`forms:write` anahtarlarını sunucunuzda tutun.** `forms:write` yetkili bir anahtar başvuru gönderir ve her başvuru satıcı adına e-posta gönderir. Bu anahtarı asla bir tarayıcıya veya mobil uygulamaya koymayın: formları kendi sunucunuzdan yükleyip gönderin ve yükleme (`forms:read`) ile gönderim (`forms:write`) için ayrı anahtarlar kullanın. Bkz. [Formlar](/tr/api/forms/index#formswrite-anahtarlarn-sunucunuzda-tutun).

Scope'lar ve modül etkinliği birbirinden bağımsız olarak uygulanır. Anahtar `commerce:read` taşısa bile, commerce modülü mağaza için devre dışıyken bir commerce rotasını çağırmak `403 {"error": "Module not enabled: commerce"}` döndürür. Okuma endpoint'leri modülün `read` scope'unu; oluşturma, güncelleme ve silme endpoint'leri modülün `write` scope'unu gerektirir. Her endpoint'in referans sayfası gerektirdiği scope'u belirtir.

## İstek işleme sırası

Middleware, her `/v1/api` isteğinde sabit bir sırayla çalışır. Bu sırayı bilmek hata yanıtlarını yorumlamaya yardımcı olur:

1. **Kimlik doğrulama**: bearer token bir mağazaya çözümlenir. Eksik, bozuk veya iptal edilmiş token: `401 {"message": "Unauthenticated."}`.
2. **Tenancy ve askıya alma**: mağaza bağlamı anahtardan başlatılır. Askıya alınmış mağaza: `403 {"message": "Tenant suspended.", "code": "tenant_suspended"}`.
3. **Rate limiting**: mağaza başına dakikada 120 istek. Aşıldığında: `429 {"message": "Too Many Attempts."}`.
4. **Modül kapısı ve scope kontrolü** (yalnızca modül rotalarında): ikisi de yukarıdaki adımlardan sonra çalışır, ancak birbirlerine göre sıraları rotaya göre değişir. Devre dışı modül: `403 {"error": "Module not enabled: {key}"}`. Eksik yetki: `403 {"message": "Invalid ability provided."}`. Kontroller bağımsızdır; ikisi de başarısız olacaksa iki hatadan herhangi biri önce ortaya çıkabilir.

## Tenant askıya alınması

Borkol bir mağazayı askıya alabilir. Askıdayken, scope veya endpoint fark etmeksizin o mağazanın anahtarlarıyla yapılan her `/v1/api` isteği şunu döndürür:

```json title="Response (403, suspended)"
{
  "message": "Tenant suspended.",
  "code": "tenant_suspended"
}
```

HTTP durum kodu 403 ile. `code` alanı sabittir ve makine tarafından okunabilir; bu 403'ü scope ve modül hatalarından ayırt etmek için `tenant_suspended` değerini kontrol edin. Askıya alma anahtarları geçersiz kılmaz: askı kaldırıldığında mevcut anahtarlar hiçbir değişiklik olmadan yeniden çalışır.

## GET /v1/api/me

Sunulan API anahtarının ait olduğu mağazanın kimliğini ve o anahtara verilen scope'ları döndürür. Bir anahtarın çalıştığını doğrulamak ve yetkilerini incelemek için standart ilk çağrı budur. Scope gerektirmez; geçerli her anahtar çağırabilir.

### Parametreler

Yok. Yalnızca `Authorization: Bearer {api_key}` header'ı gereklidir.

### Yanıt alanları

| Ad | Tür | Zorunlu | Açıklama |
| --- | --- | --- | --- |
| `tenant` | object | her zaman | Anahtarın ait olduğu mağaza. |
| `tenant.id` | string (UUID) | her zaman | Mağaza ID'si. |
| `tenant.name` | string | her zaman | Mağazanın görünen adı. |
| `tenant.slug` | string | her zaman | URL güvenli mağaza tanımlayıcısı. |
| `scopes` | array of strings | her zaman | Bu anahtara verilen scope'lar, örneğin `["tenant:read", "commerce:read"]`. |

```bash title="Request"
curl https://api.borkol.com/v1/api/me \
  -H "Authorization: Bearer {api_key}"
```

```javascript title="Request (JS)"
const res = await fetch("https://api.borkol.com/v1/api/me", {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const me = await res.json();
```

```json title="Response"
{
  "tenant": {
    "id": "9c4e7f0a-2b31-4d6e-8f0a-1d2c3b4a5e6f",
    "name": "Example Store",
    "slug": "example-store"
  },
  "scopes": ["tenant:read", "commerce:read", "commerce:write", "stock:read"]
}
```

### Hatalar

| Durum | Body | Ne zaman |
| --- | --- | --- |
| 401 | `{"message": "Unauthenticated."}` | Bearer token eksik, bozuk veya iptal edilmiş. |
| 403 | `{"message": "Tenant suspended.", "code": "tenant_suspended"}` | Mağaza askıya alınmış. |
| 429 | `{"message": "Too Many Attempts."}` | Geçerli dakika içinde 120'den fazla istek. |

## GET /v1/ping

API v1 için kimlik doğrulamasız sağlık kontrolü. Kimlik bilgisi, mağaza bağlamı, scope ve tenant rate limit'i uygulanmaz. Uptime izleme için ve kimlik bilgilerini bağlamadan önce bağlantıyı ve base URL'i doğrulamak için kullanın.

### Parametreler

Yok.

### Yanıt alanları

| Ad | Tür | Zorunlu | Açıklama |
| --- | --- | --- | --- |
| `status` | string | her zaman | Her zaman `"ok"`. |
| `version` | string | her zaman | Her zaman `"v1"`. |

```bash title="Request"
curl https://api.borkol.com/v1/ping
```

```json title="Response"
{
  "status": "ok",
  "version": "v1"
}
```

### Hatalar

Bu rotaya özgü hata yok.
