# Template'leri listeleme (Sandbox)

> Hesabın POST /send/template ile kullanabileceği template'leri, en yenisi önce, sayfa sayfa listeler: hesabın kendi template'leri ve herkese açık template'ler.

- **İstek:** `GET https://ext-sandbox.netgsm.com.tr/sms/v3/templates`
- **Sandbox:** `https://ext-sandbox.netgsm.com.tr/sms/v3`
- **Kimlik doğrulama:** `Authorization: Bearer <token>`
- **HTML sayfası:** https://api-docs.netgsm.com.tr/sandbox/list-templates/
- **OpenAPI tanımı:** https://api-docs.netgsm.com.tr/openapi/sandbox-v3.yaml (operationId: `listTemplates`)

## Açıklama

Hesabın `POST /send/template` ile kullanabileceği template'leri, en yenisi önce, sayfa sayfa listeler:
hesabın kendi template'leri ve herkese açık template'ler. Yalnızca hesabın kendi template'leri için
`includePublic=false` verilir. Boş bir sayfa da 200 döner.

Her template, gönderimde `params` içinde verilmesi gereken parametreleri ve her birinin kabul
ettiği değer türünü taşır.

**İstek sınırı.** Hesap başına dakikada 20 istek. Pencere ilk istekle başlar ve sabittir;
reddedilen istekler de sayılır. Aşıldığında 429 `Retry-After` başlığıyla döner.

## İstek

### Parametreler

- `includePublic` (sorgu, boolean, isteğe bağlı): `false` yalnızca hesabın kendi template'lerini listeler; herkese açık template'ler dahil edilmez. Varsayılan: `true`.
- `type` (sorgu, string, isteğe bağlı, en fazla uzunluk 100): Template tipi, birebir eşleşir. Örnek: `AUTH_OTP`.
- `search` (sorgu, string, isteğe bağlı, en fazla uzunluk 100): Açıklamada geçen metin; büyük/küçük harf fark etmez.
- `content` (sorgu, string, isteğe bağlı, en fazla uzunluk 100): Template metninde geçen metin; büyük/küçük harf fark etmez.
- `page` (sorgu, integer, isteğe bağlı, en az 0): Sıfırdan başlayan sayfa numarası. Varsayılan: `0`.
- `size` (sorgu, integer, isteğe bağlı, en az 1, en fazla 100): Sayfa başına template. Varsayılan: `20`.

## Örnek istek

```bash
curl -X GET 'https://ext-sandbox.netgsm.com.tr/sms/v3/templates?type=AUTH_OTP' \
  -H 'Authorization: Bearer <token>'
```

## Yanıtlar

### 200 — Bir sayfa template; en yenisi önce. Boş olabilir.

Gövde (`application/json`):

- `count` (integer, zorunlu): Bu sayfadaki template sayısı.
- `page` (integer, zorunlu): İstenen sayfa.
- `total` (integer, int64, zorunlu): Filtreye uyan template'lerin tüm sayfalardaki toplamı.
- `totalPages` (integer, zorunlu): Bu `size` ile toplam sayfa sayısı.
- `templates` (array<object>, zorunlu)
- `templates[].templateId` (integer, int64, zorunlu): Template'in kimliği; `POST /send/template` kayıtlarındaki `templateId`. Örnek: `3`.
- `templates[].content` (string, zorunlu): Template metni. Yer tutucular `${ad}` biçimindedir ve gönderimde `params` ile doldurulur. Örnek: `Dogrulama kodunuz: ${otpCode}`.
- `templates[].type` (string, zorunlu): Template tipi, örn. `AUTH_OTP`, `SECURITY_ALERT`, `SERVICE_ALERT`.
- `templates[].description` (string, null olabilir, zorunlu): Template'in açıklaması.
- `templates[].public` (boolean, zorunlu): Herkese açık bir template'se `true`, hesabın kendi template'iyse `false`.
- `templates[].parameters` (array<object>, zorunlu): Template'in yer tutucuları; gönderimde her birini `params` içinde vermelisiniz.
- `templates[].parameters[].name` (string, zorunlu): Yer tutucunun adı; `params` anahtarı. Örnek: `otpCode`.
- `templates[].parameters[].type` (string, zorunlu): Kabul edilen değer türü; biçimleri `POST /send/template` `params` açıklamasındadır. Değerler: `BIGINT`, `FLOAT`, `TEXT`, `DATE`, `DATETIME`.
- `templates[].parameters[].maxLength` (integer, null olabilir, zorunlu): En fazla değer uzunluğu; yalnızca `TEXT` için dolu.
- `templates[].createdAt` (string, date-time, null olabilir, zorunlu): Template'in kayıt zamanı, saat dilimi farkıyla. Örnek: `2026-05-18T11:25:12.502+03:00`.

Örnek:

```json
{
  "count": 1,
  "page": 0,
  "total": 1,
  "totalPages": 1,
  "templates": [
    {
      "templateId": 3,
      "content": "Dogrulama kodunuz: ${otpCode}",
      "type": "AUTH_OTP",
      "description": "Giriş kodu",
      "public": false,
      "parameters": [
        {
          "name": "otpCode",
          "type": "BIGINT",
          "maxLength": null
        }
      ],
      "createdAt": "2026-05-18T11:25:12.502+03:00"
    }
  ]
}
```

### 400 — INVALID_REQUEST. `message` şunlardan biridir:

| `message` | Anlamı |
|---|---|
| `page must not be negative` | `page` negatif. |
| `size must be between 1 and 100` | `size` aralık dışında. |
| `type must be at most 100 characters` | Bir filtre (`type`, `search`, `content`) 100 karakterden uzun. |

Gövde (`application/json`):

- `code` (string, zorunlu): Değerler: `INVALID_REQUEST`.
- `message` (string, zorunlu): Okunabilir ayrıntı. `UNAUTHENTICATED` için `no bearer token` ya da `invalid or expired token`. `REJECTED_HEADER` için ret adıdır; yalnızca rakamlardan oluşan bir göndericide ` (subscriber number headers were not offered)` ekini taşıyabilir. `RATE_LIMITED` için sınırı belirtir; `FORBIDDEN` ve `REJECTED_IYS` için sabit bir cümledir. `SERVICE_UNAVAILABLE` ve `INTERNAL_ERROR` genel bir cümle taşır; bildirirken `requestId` değerini paylaşmanız gerekir.
- `requestId` (string, zorunlu): İsteğe özgü kimlik, 32 onaltılık karakter. Bir sorun bildirirken bu değeri paylaşmanız, isteğin kayıtlarda bulunmasını sağlar.
- `timestamp` (string, date-time, zorunlu)
- `violations` (array<object>, null olabilir, zorunlu): Yalnızca gövde doğrulamasından gelen INVALID_REQUEST için dolu, aksi halde `null`.
- `violations[].field` (string, isteğe bağlı)
- `violations[].message` (string, isteğe bağlı)
- `rejectedItems` (array<object>, isteğe bağlı, en fazla kayıt 100): Yalnızca `NO_DELIVERABLE_MESSAGES` yanıtında bulunur; diğer hatalarda alan hiç yer almaz. Reddedilen kayıtlar, `index` sırasıyla ilk 100 tanesi; 202 yanıtındaki `rejectedItems` ile aynıdır.
- `rejectedItems[].index` (integer, zorunlu): Kaydın istekteki `messages` dizisindeki sırası, sıfırdan başlar.
- `rejectedItems[].recipient` (string, null olabilir, zorunlu): Kayıttaki alıcı. Kayıt `null` ise ya da alıcısı yoksa `null`.
- `rejectedItems[].reason` (string, zorunlu): Değerler: `INVALID_RECIPIENT`, `INVALID_MESSAGE`, `MESSAGE_TOO_LONG`, `MALFORMED_ENTRY`, `DUPLICATE_RECIPIENT`, `NO_INTERNATIONAL_PERMISSION`.

  | Değer | Ne zaman |
  |---|---|
  | `INVALID_RECIPIENT` | Numara eksik ya da biçimi yanlış; bkz. `recipient`. |
  | `INVALID_MESSAGE` | Metin eksik ya da boş. |
  | `MESSAGE_TOO_LONG` | Metin, `encoding` ve gönderici türüne göre sınırı aşıyor; bkz. `encoding`. |
  | `MALFORMED_ENTRY` | Kayıt `null`. |
  | `DUPLICATE_RECIPIENT` | Aynı alıcı istekte daha sonra yeniden geçiyor. Yalnızca son geçen kayıt gönderilir, öncekiler bu nedenle reddedilir; son kayıt başka bir nedenle reddedilse bile. Numaralar yazıldığı gibi karşılaştırılır. Mükerrer gönderime izin verilen hesaplarda uygulanmaz. |
  | `NO_INTERNATIONAL_PERMISSION` | Numara yurt dışı (`-` ile başlıyor) ve hesabın yurt dışı gönderim izni yok. İzin için destek ekibiyle iletişime geçmelisiniz. Yalnızca başka bir hatası olmayan kayıtlarda bildirilir. |

  Bir kayıt birden fazla nedenle hatalıysa tek neden bildirilir; öncelik: `DUPLICATE_RECIPIENT`,
  `MALFORMED_ENTRY`, `MESSAGE_TOO_LONG`, `INVALID_RECIPIENT`, `INVALID_MESSAGE`,
  `NO_INTERNATIONAL_PERMISSION`.

- `rejectedItemsTruncated` (boolean, isteğe bağlı): Yalnızca `rejectedItems` ile birlikte bulunur. 100'den fazla kayıt reddedildiğinde true.

Örnek (şemadan üretildi):

```json
{
  "code": "INVALID_REQUEST",
  "message": "string",
  "requestId": "string",
  "timestamp": "2026-01-01T10:00:00+03:00",
  "violations": [
    {
      "field": "string",
      "message": "string"
    }
  ],
  "rejectedItems": [
    {
      "index": 0,
      "recipient": "string",
      "reason": "INVALID_RECIPIENT"
    }
  ],
  "rejectedItemsTruncated": true
}
```

### 401 — UNAUTHENTICATED. Bearer token yok ya da token geçersiz veya süresi dolmuş; `message` `no bearer token` ya da `invalid or expired token`.

Gövde (`application/json`): alanlar 400 yanıtıyla aynı; farklı olanlar:

- `code` (string, zorunlu): Değerler: `UNAUTHENTICATED`.

Örnek (şemadan üretildi):

```json
{
  "code": "UNAUTHENTICATED",
  "message": "string",
  "requestId": "string",
  "timestamp": "2026-01-01T10:00:00+03:00",
  "violations": [
    {
      "field": "string",
      "message": "string"
    }
  ],
  "rejectedItems": [
    {
      "index": 0,
      "recipient": "string",
      "reason": "INVALID_RECIPIENT"
    }
  ],
  "rejectedItemsTruncated": true
}
```

### 429 — RATE_LIMITED, `message` `template list rate limit exceeded`. Hesap başına dakikada 20 istek aşıldı; `Retry-After` kadar bekleyip yeniden denemelisiniz.

Başlıklar:

- `Retry-After` (integer): Yeniden denemeden önce beklenecek saniye.

Gövde (`application/json`): alanlar 400 yanıtıyla aynı; farklı olanlar:

- `code` (string, zorunlu): Değerler: `RATE_LIMITED`.

Örnek (şemadan üretildi):

```json
{
  "code": "RATE_LIMITED",
  "message": "string",
  "requestId": "string",
  "timestamp": "2026-01-01T10:00:00+03:00",
  "violations": [
    {
      "field": "string",
      "message": "string"
    }
  ],
  "rejectedItems": [
    {
      "index": 0,
      "recipient": "string",
      "reason": "INVALID_RECIPIENT"
    }
  ],
  "rejectedItemsTruncated": true
}
```

### 500 — INTERNAL_ERROR, `message` `internal error`. Beklenmeyen hata; bildirirken `requestId` değerini paylaşmanız gerekir.

Gövde (`application/json`): alanlar 400 yanıtıyla aynı; farklı olanlar:

- `code` (string, zorunlu): Değerler: `INTERNAL_ERROR`.

Örnek (şemadan üretildi):

```json
{
  "code": "INTERNAL_ERROR",
  "message": "string",
  "requestId": "string",
  "timestamp": "2026-01-01T10:00:00+03:00",
  "violations": [
    {
      "field": "string",
      "message": "string"
    }
  ],
  "rejectedItems": [
    {
      "index": 0,
      "recipient": "string",
      "reason": "INVALID_RECIPIENT"
    }
  ],
  "rejectedItemsTruncated": true
}
```

### 503 — SERVICE_UNAVAILABLE. Hiçbir şey yapılmadı; yeniden denemek güvenlidir.

Gövde (`application/json`): alanlar 400 yanıtıyla aynı; farklı olanlar:

- `code` (string, zorunlu): Değerler: `SERVICE_UNAVAILABLE`.

Örnek (şemadan üretildi):

```json
{
  "code": "SERVICE_UNAVAILABLE",
  "message": "string",
  "requestId": "string",
  "timestamp": "2026-01-01T10:00:00+03:00",
  "violations": [
    {
      "field": "string",
      "message": "string"
    }
  ],
  "rejectedItems": [
    {
      "index": 0,
      "recipient": "string",
      "reason": "INVALID_RECIPIENT"
    }
  ],
  "rejectedItemsTruncated": true
}
```
