# SMS API v3 Sandbox

> SMS API v3'ü canlı ortama geçmeden, gerçek SMS göndermeden ve ücret ödemeden denemeniz için hazırlanmış test ortamıdır.

- **Sürüm:** 3.0
- **Sandbox:** `https://ext-sandbox.netgsm.com.tr/sms/v3`
- **OpenAPI tanımı:** https://api-docs.netgsm.com.tr/openapi/sandbox-v3.yaml
- **HTML sayfası:** https://api-docs.netgsm.com.tr/sandbox/sms-api-v-3-sandbox/

SMS API v3'ü canlı ortama geçmeden, gerçek SMS göndermeden ve ücret ödemeden denemeniz için hazırlanmış test ortamıdır.

Sandbox, canlı API ile **aynı istekleri kabul eder ve aynı biçimde yanıt verir**: alan adları, doğrulama kuralları, hata kodları ve hata mesajları canlıdakiyle aynıdır. Fark, yanıtların arkasındaki verinin **sabit (örnek) veri** olmasıdır.

> **Sandbox hiçbir koşulda SMS göndermez.** Gönderim uç noktaları isteği doğrular ve gerçekçi bir yanıt döner; mesaj hiçbir operatöre iletilmez, hiçbir yere kaydedilmez ve ücretlendirilmez.

---

## Hızlı başlangıç

| | Adres |
|---|---|
| Token (Authorization API) | `https://ext-sandbox.netgsm.com.tr/auth/v3/token` |
| SMS API v3 | `https://ext-sandbox.netgsm.com.tr/sms/v3` |

**1. Token alın:**

```bash
curl -s https://ext-sandbox.netgsm.com.tr/auth/v3/token \
  -H 'Content-Type: application/json' \
  -d '{"username":"8500000000","password":"password001","scope":"sms"}'
```

**2. Token ile ilk SMS'inizi "gönderin":**

```bash
curl -s https://ext-sandbox.netgsm.com.tr/sms/v3/send \
  -H 'Authorization: Bearer <access_token>' \
  -H 'Content-Type: application/json' \
  -d '{"sender":"TESTHEADER","messages":[{"text":"Merhaba","recipient":"905551112233"}]}'
```

```json
{
  "jobId": "17937053582689000017972015",
  "status": "QUEUED",
  "accepted": 1,
  "rejected": 0,
  "rejectedItems": [],
  "rejectedItemsTruncated": false,
  "referenceId": null
}
```

---

## Token alma

SMS API v3'e yapılan her istek bir **Bearer token** taşır. Sandbox token'ları, Authorization API'nin sandbox'ından alınır.

### İstek

```
POST https://ext-sandbox.netgsm.com.tr/auth/v3/token
Content-Type: application/json
```

```json
{
  "username": "8500000000",
  "password": "password001",
  "scope": "sms"
}
```

| Alan | Açıklama |
|---|---|
| `username` | Demo hesabın kullanıcı adı (aşağıdaki tabloya bakın) |
| `password` | Demo hesabın şifresi |
| `scope` | SMS API için `sms`. Hesabın kendisini sorgulamak için `profile` |

### Yanıt

```json
{
  "access_token": "eyJhbGciOiJIUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 86400,
  "refresh_token": "4d5b2e0d-09fa-4cbe-b3f9-d325290a612e",
  "scope": "sms",
  "user_id": 900001,
  "sub_user_id": 0
}
```

- `access_token` her SMS isteğinde `Authorization: Bearer <access_token>` başlığıyla gönderilir.
- Token **24 saat** (`expires_in`: 86400 saniye) geçerlidir. Süresi dolan token ile yapılan istek `401` döner; yeni bir token alın.

### Token alınamayan durumlar

Bazı demo hesaplar, hata senaryolarını göstermek için `sms` kapsamında token **alamaz**. Authorization API bu durumda `403` döner:

| Hesap | `scope: "sms"` ile yanıt |
|---|---|
| 8500000001 | `403` `service_not_activated`: hesapta hizmet aktif değil |
| 8500000003 | `403` `sub_user_not_permitted`: alt kullanıcının hizmete yetkisi yok |

Bu iki hesabın SMS API'deki davranışını görmek isterseniz `scope: "profile"` ile token alabilirsiniz; SMS API bu token'ı kabul eder ve hesaba göre `403` döner (bkz. [Demo hesaplar](#demo-hesaplar)).

---

## Demo hesaplar

| Kullanıcı adı | Şifre | `user_id` | Rolü | SMS API'deki davranış |
|---|---|---|---|---|
| **8500000000** | **password001** | **900001** | **Tüm hizmetler aktif** | **Bütün uç noktalarda başarılı yanıt.** Denemeleriniz için bu hesabı kullanın. |
| 8500000001 | password002 | 900002 | Hizmet aktivasyonu yok | Gönderim ve gelen kutusu (`/send`, `/send/template`, `/send/otp`, `/directory/send`, `/inbox`): `403 account is not activated for this operation`. Diğer uç noktalar başarılı. |
| 8500000003 | password004 | 900004 | Menü yetkisi olmayan alt kullanıcı | `/length`, `/blacklist` ve `/balance` dışında bütün uç noktalarda `403 sub user may not use the sms api`. |
| 8500000002 | password003 | 900003 | IP izni yok | Token alınamaz (Authorization API hatası). |
| 8500000004 | password005 | 900005 | API erişimi kapalı | Token alınamaz (Authorization API hatası). |
| 8500000005 | password006 | 900006 | Hesap pasif | Token alınamaz (Authorization API hatası). |

---

## Ortak kurallar

### İstek başlıkları

| Başlık | Değer |
|---|---|
| `Authorization` | `Bearer <access_token>`, her istekte zorunlu |
| `Content-Type` | Gövdeli isteklerde `application/json` |

Gövde sıkıştırılmadan gönderilmelidir; `Content-Encoding` (ör. `gzip`) içeren istek `415` döner.

### Tarih ve saat

Tarihler ISO-8601 biçiminde, saat dilimi farkıyla yazılır: `2026-11-03T14:30:00+03:00`. Sorgu parametresinde `+` işareti `%2B` olarak kodlanmalıdır: `startAt=2026-11-01T00:00:00%2B03:00`.

Yanıtlardaki tarihler Türkiye saatiyle (`+03:00`) döner.

### Numara biçimi

- **SMS gönderiminde alıcı** (`/send`, `/send/template`): yurt içi numara `90` + 10 hane (`905551112233`); yurt dışı numara `-` + 9-17 hane. `+90…`, `0…` ya da `5…` biçimleri kabul edilmez.
- **OTP alıcısı** (`/send/otp`): `5XXXXXXXXX`, `05XXXXXXXXX` ya da `905XXXXXXXXX`; başına `+` eklenebilir (`+905XXXXXXXXX`).

### Hata biçimi

Her hata aynı gövdeyle döner:

```json
{
  "code": "INVALID_REQUEST",
  "message": "2 field(s) rejected",
  "requestId": "37619d5202a44485ba3b2531d7832a89",
  "timestamp": "2026-11-03T14:29:20.336008+03:00",
  "violations": [
    { "field": "sender", "message": "must not be blank" },
    { "field": "messages", "message": "must not be empty" }
  ]
}
```

| Alan | Açıklama |
|---|---|
| `code` | Makinenin okuyacağı hata kodu (aşağıdaki tablo) |
| `message` | İnsanın okuyacağı açıklama |
| `requestId` | İsteğin kimliği. Destek talebinde bunu iletin |
| `timestamp` | Hatanın zamanı |
| `violations` | Alan doğrulama hatalarında hangi alanın neden reddedildiği. Diğer hatalarda `null` |
| `rejectedItems`, `rejectedItemsTruncated` | Yalnızca `NO_DELIVERABLE_MESSAGES` hatasında bulunur |

### Hata kodları

| HTTP | `code` | Ne zaman |
|---|---|---|
| 400 | `INVALID_REQUEST` | Gövde ya da parametre hatalı, JSON okunamadı |
| 401 | `UNAUTHENTICATED` | Token yok (`no bearer token`) ya da geçersiz / süresi dolmuş (`invalid or expired token`) |
| 403 | `FORBIDDEN` | Hesabın bu işleme yetkisi yok |
| 404 | `NOT_FOUND` | Böyle bir uç nokta yok (`no such endpoint`) |
| 405 | `INVALID_REQUEST` | Yöntem bu uç noktada desteklenmiyor. Desteklenenler `Allow` başlığında |
| 406 | — | `Accept` başlığı JSON'u kabul etmiyor (gövdesiz) |
| 413 | `INVALID_REQUEST` | Gövde boyut sınırını aşıyor |
| 415 | `INVALID_REQUEST` | `Content-Type` JSON değil ya da gövde sıkıştırılmış |
| 422 | `REJECTED_HEADER` | Gönderici başlığı kullanılamıyor (mesajda nedeni yazar) |
| 422 | `NO_DELIVERABLE_MESSAGES` | İstekteki mesajların hiçbiri gönderilebilir değil |
| 503 | `SERVICE_UNAVAILABLE` | Kimlik doğrulama servisine o an ulaşılamadı; yeniden deneyin |
| 500 | `INTERNAL_ERROR` | Beklenmeyen hata; `requestId` ile bildirin |

---

## Sandbox'taki sabit veriler

Canlı ortamda hesabınıza ait olan veriler, sandbox'ta herkes için aynıdır:

| Veri | Sandbox'taki değer |
|---|---|
| Gönderici başlıkları | `TESTHEADER` (alfanümerik, kullanılabilir, **varsayılan**) ve `8500000000` (abone numarası, **kullanılamaz**: `SUBSCRIBER_NUMBER_RESTRICTED`) |
| Şablonlar | Tek şablon: `templateId` **1**, içerik `Merhaba ${name}, kodunuz ${code}` |
| Kara liste | `5000000001`, `5000000002` |
| Rapor satırı | Her `jobId` için: numara `5000000000`, `DELIVERED`, `NETGSM`, 1 parça, teslim `2026-01-01T12:00:00+03:00` |
| Gelen kutusu | Tek mesaj: gönderen `5000000000`, metin `Sandbox inbound message` |
| Bakiye | 1500 `Adet SMS` (iki kayıt), 300 `Adet OTP Sms`, 600 `Dakika` (ses), 50 `Adet Fax`, 100 `Whatsapp Authentication`, kredi 125,50 TL. Hesap faturasızdır |

`5000000000`, `5000000001` ve `5000000002` gerçek bir aboneye ait olamayacak örnek numaralardır.

---

## Uç noktalar

Bütün yollar `https://ext-sandbox.netgsm.com.tr/sms/v3` ile başlar.

| Yöntem | Yol | İşlev |
|---|---|---|
| POST | `/send` | SMS gönder |
| POST | `/send/template` | Şablondan SMS gönder |
| POST | `/send/otp` | OTP gönder |
| POST | `/directory/send` | Rehberdeki gruplara / kişilere gönder |
| POST | `/length` | Metnin SMS uzunluğunu hesapla |
| POST | `/cancel` | Gönderimi iptal et |
| GET | `/report` | Teslim raporu |
| GET | `/stats` | Gönderim özeti |
| GET | `/inbox` | Gelen SMS'ler |
| GET | `/senders` | Gönderici başlıkları |
| GET | `/senders/default` | Varsayılan başlık |
| PUT | `/senders/default` | Varsayılan başlığı değiştir |
| GET | `/templates` | Şablonlar |
| GET | `/blacklist` | Kara liste |
| GET | `/balance` | Kalan paketler ve kredi |

Her uç noktanın ayrıntısı kenar çubuğundaki sayfasındadır.

---

## Canlı ortamdan farklar

Sandbox'ta istek doğrulaması ve hata yanıtları canlıyla aynıdır. Şu konularda canlıdan farklı davranır:

**Gönderim**
- SMS gönderilmez, kaydedilmez, ücretlendirilmez. `jobId` gerçek bir gönderime karşılık gelmez.
- İYS (izin) kontrolü yapılmaz; `iysFilter` kabul edilir ama etkisi yoktur.
- Gönderim penceresi (`startAt` / `stopAt`) denetlenmez. `startAt` gelecekteyse `status` `SCHEDULED` döner.
- Bakiye denetlenmez; OTP'de `422 INSUFFICIENT_CREDIT` dönmez.
- `/directory/send` grup numaralarını rehberde aramaz; her grup numarası kabul edilir.

**Okuma uç noktaları**
- `/report`, `/stats`, `/inbox` sabit veri döner. Tarih aralığı **doğrulanır ama veriyi süzmez**: hangi aralığı sorarsanız sorun aynı kayıtlar döner.
- Bilinmeyen bir `jobId` için canlıdaki `404 job not found` (`/stats`) ve `404 job not found for this account, or no longer waiting to be sent` (`/cancel`) dönmez; her `jobId` başarılı yanıt alır.
- `PUT /senders/default` kaydedilmez.
- `/balance` her hesap için aynı sabit bakiyeyi döner ve gönderimlerle azalmaz; canlıdaki 10 saniyelik önbellek yoktur. Faturalı hesap özeti (`stip=2` → `"0"`) sandbox'ta görülmez.
- Yalnızca `templateId: 1` vardır; başka numaralar `400 templates not found` döner.

**Sınırlar**
- İstek sınırları (rate limit) uygulanmaz; `429` dönmez.

**Yanıt süresi**
- Her istekte token, Authorization API'nin sandbox'ında doğrulanır; yanıtlar canlıdan biraz yavaş olabilir.

## Kimlik doğrulama şemaları

- `bearer` (HTTP bearer): Bearer erişim token'ı. Herhangi bir gövde okunmadan önce kontrol edilir.

## Uç noktalar

### Gönderim

SMS gönderme, rehber gruplarına ve OTP gönderme, mesaj uzunluğu hesaplama ve zamanlanmış görevleri iptal etme.

- [`POST /cancel` Zamanlanmış gönderimi iptal etme (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/cancel-job.md): Hesabınızın henüz gönderilmemiş bir görevini geri çeker.
- [`POST /length` SMS uzunluğunu hesaplama (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/measure-length.md): Bir metnin kaç parça tuttuğu ve sınıra ne kadar uzak olduğu; send uç noktasının saydığı şekilde birebir sayılır.
- [`POST /send/otp` OTP SMS gönderme (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/send-otp.md): Tek bir alıcıya OTP (tek kullanımlık şifre) SMS'i gönderir.
- [`POST /send` SMS gönderme (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/send-sms.md): Bir ya da daha fazla alıcıya SMS gönderen bir görev oluşturur.
- [`POST /directory/send` Rehbere SMS gönderme (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/send-to-directory.md): Rehberdeki kişi gruplarına, istekte verilen kişilere ya da her ikisine tek bir metinle gönderimi kuyruğa alır.

### Raporlar ve gelen kutusu

İletim raporları, görev istatistikleri ve hesabınıza gelen SMS'ler.

- [`GET /inbox` Gelen SMS'leri listeleme (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/read-inbox.md): Kimliği doğrulanmış hesabın gelen kutusu, isteğe bağlı olarak bir aralıkla sınırlanır.
- [`GET /report` İletim raporlarını sorgulama (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/read-reports.md): Kimliği doğrulanmış hesabın iletim raporlarından bir sayfa.
- [`GET /stats` Gönderim istatistiklerini sorgulama (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/read-stats.md): Kimliği doğrulanmış hesabın bir görevi için, gönderildiği ay üzerinden toplanmış, her farklı sonuç başına bir satır.

### Gönderici adları

Hesabınıza kayıtlı gönderici başlıkları ve varsayılan başlık.

- [`PUT /senders/default` Varsayılan gönderici başlığını değiştirme (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/change-default-sender.md): Kayıtlı bir başlığı varsayılan yapar.
- [`GET /senders` Gönderici başlıklarını listeleme (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/list-senders.md): Kimliği doğrulanmış hesaba kayıtlı gönderici başlıkları.
- [`GET /senders/default` Varsayılan gönderici başlığını öğrenme (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/read-default-sender.md): Hesabın varsayılan gönderici başlığı, anlık olarak okunur; bu yüzden bir değişiklik hemen görünür.

### Template

Template ile SMS gönderme ve kullanabileceğiniz kayıtlı ve herkese açık template'leri listeleme.

- [`GET /templates` Template'leri listeleme (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/list-templates.md): 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.
- [`POST /send/template` Template ile SMS gönderme (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/send-from-template.md): Kayıtlı template'leri verilen parametrelerle doldurup gönderen bir görev oluşturur.

### Kara liste

Hesabınızın kara listesindeki numaralar.

- [`GET /blacklist` Kara listeyi öğrenme (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/read-blacklist.md): Hesabın kara listesindeki numaraları döndürür.

### Hesap

Hesabın kalan paketleri, kampanyaları ve kredi bakiyesi.

- [`GET /balance` Bakiye sorgulama (Sandbox)](https://api-docs.netgsm.com.tr/sandbox/get-balance.md): Hesabın kalan paketlerini, kampanyalarını ve kredi bakiyesini döner.
