API Dokümantasyonu

Toplu SMS gönderimi için tam REST API referansı. Her endpoint'in yanındaki "AI'ya Kopyala" butonu, endpoint metadata'sını yapay zeka asistanlarına yapıştırılınca eksiksiz çalışacak yapılandırılmış prompt'a çevirir.

Base URL
https://sms.gambi.dev
Auth
X-Api-Key
Format
application/json

Hızlı Başlangıç

  1. 1. Hesap oluştur (30 saniye, e-posta + parola).
  2. 2. Panelde /app/api-keys sayfasından bir API anahtarı oluştur. Anahtar formatı: gsms_xxxxxxxxxxxxxxxx (sadece 1 kez gösterilir, kaydet).
  3. 3. Test isteğini at:
İlk istek
curl https://sms.gambi.dev/api/v1/me \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"

Kimlik Doğrulama

Tüm authenticated istekler X-Api-Key header'ı ile yapılır. Anahtarlar sunucuda SHA-256 hash olarak saklanır; plaintext sadece üretim anında bir kez gösterilir. Anahtar sızdığında /app/api-keys sayfasından anında iptal edebilirsin. Per-key audit log (son 30 gün) görüntülenebilir.

Rate Limit

Varsayılan limit her API anahtarı için 30 istek/sn. Premium müşterilerde 100/sn'e yükseltilebilir. Her yanıt aşağıdaki header'ları içerir:

Response headers
X-RateLimit-Limit: 30
X-RateLimit-Policy: 30;w=1
X-RateLimit-Remaining: 28

Limit aşıldığında 429 RATE_LIMIT döner. Retry-After saniye olarak yanıt header'ında gelir. Client tarafında exponential backoff önerilir.

Yetkilendirme

GET/api/v1/meAuth Gerekir

Hesap bilgisi

API anahtarınızın geçerliliğini test etmek ve hesap kimliği + rolü doğrulamak için kullanılır. Bu endpoint çağrısı kredi yakmaz.

Hatalar
HTTPCodeAçıklama
401NO_KEYX-Api-Key header eksik
401INVALID_KEYAPI anahtarı geçersiz
shell
curl https://sms.gambi.dev/api/v1/me \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
Yanıt örneği (başarı)
json
{
  "ok": true,
  "userId": 42,
  "email": "ops@bahis123.com",
  "role": "USER",
  "balanceCredits": 1250.5,
  "balanceWaCredits": 800
}

SMS Endpoint'leri

POST/api/v1/sms/sendAuth Gerekir

Toplu SMS gönderimi

Bir veya birden fazla alıcıya SMS gönderir. Kampanya olarak kayıt edilir; durum /api/v1/sms/:messageId ile sorgulanır veya DLR webhook'u ile takip edilir. Segment hesabı otomatiktir: alfanumerik başlıkta GSM-7 tek SMS 155 karakter (çok parçalı 153/segment), Türkçe karakter içeren metin 150/segment, Unicode (emoji vb.) tek SMS 70 karakter (çok parçalı 67/segment). Azami 5 segment. ÜCRETLENDİRME: kredi gönderim anında, mesaj operatöre iletildikçe düşer; gönderilmeyen alıcı için ücret alınmaz, iletilen mesaj teslim edilemese bile ücretlendirilir ve iade yapılmaz. Karantinadaki ve geçersiz numaralar gönderimden önce elenir, ücretlendirilmez. NOT: Mesajdaki linkler teslimat için otomatik normalize edilir, http(s):// ve www. kaldırılır (ör. https://www.site.com → site.com).

Request Body (application/json)
AdTipAçıklama
to*string | string[]E.164 formatında alıcı(lar): '+905551234567'. Tek string veya dizi. Tek istekte en fazla 100.000 alıcı
text*stringMesaj gövdesi. En az 1 karakter, en fazla 5 segment
fromstringGönderici başlığı. Hesabınızda onaylı ve operatörde tanımlı bir başlık verirseniz o kullanılır; aksi halde hesabınızın aktif başlığına inilir (istek reddedilmez). Boş bırakabilirsiniz
scheduledstring (ISO8601)İleri tarihli gönderim zamanı. Boş = anında
smartSchedulingbooleanVarsayılan true. Açıkken gönderim yasal iletişim saatleri dışına denk gelirse ilk uygun saate ötelenir. false verirseniz öteleme yapılmaz
dlr_urlstring (https)Bu gönderime özel DLR webhook URL'i (https zorunlu). Boş bırakılırsa hesap ayarlarındaki varsayılan kullanılır
Hatalar
HTTPCodeAçıklama
400BAD_JSONGövde geçerli JSON değil
401NO_KEYX-Api-Key header eksik
401INVALID_KEYAPI anahtarı geçersiz
402INSUFFICIENT_CREDITYetersiz kredi
409DUPLICATE_REQUESTAynı istek kısa süre içinde tekrarlandı (Idempotency-Key)
413TOO_MANYAlıcı limiti aşıldı (maks 100.000)
422VALIDATIONGövde doğrulanamadı
422NO_RECIPIENTSGeçerli E.164 alıcı yok
422ALL_SUPPRESSEDTüm alıcılar bastırılmış (opt-out/blacklist)
422TOO_LONGMesaj 5 segmenti aşıyor
429RATE_LIMITHız limiti aşıldı (30 istek/sn)
503QUEUE_UNAVAILABLEKuyruk geçici olarak kullanılamıyor, tekrar deneyin
shell
curl -X POST https://sms.gambi.dev/api/v1/sms/send \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "to": ["+905551234567", "+905559876543"],
    "text": "Bonusunuz hazır: 500 TL"
  }'
Request body örneği
json
{
  "to": [
    "+905551234567",
    "+905559876543"
  ],
  "text": "Bonusunuz hazır: 500 TL"
}
Yanıt örneği (başarı)
json
{
  "campaignId": 4521,
  "totalRecipients": 2,
  "suppressedSkipped": 0,
  "segments": 1,
  "costCredits": 2,
  "costCreditsHuman": "2",
  "status": "QUEUED",
  "spamScore": {
    "score": 0,
    "level": "low",
    "warnings": []
  }
}
GET/api/v1/sms/balanceAuth Gerekir

SMS bakiyesi

SMS kredi bakiyenizi döner. 1 kredi = 1 SMS segmenti. (balance ve usdt alanları geriye dönük uyumluluk için bırakılmıştır, artık kullanılmaz.)

Hatalar
HTTPCodeAçıklama
401NO_KEYX-Api-Key header eksik
401INVALID_KEYAPI anahtarı geçersiz
shell
curl https://sms.gambi.dev/api/v1/sms/balance \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
Yanıt örneği (başarı)
json
{
  "credits": 1248,
  "creditsHuman": "1.248",
  "currency": "GambiSMS Credit",
  "balance": 0,
  "usdt": null
}
GET/api/v1/campaignsAuth Gerekir

Kampanya listesi

SMS kampanyalarınızı sayfalı olarak döner. ?page (varsayılan 1) ve ?pageSize (varsayılan 25, maks 100) ile sayfalanır. total alanı toplam kayıt sayısıdır.

Query Parametreleri
AdTipAçıklama
pagenumberSayfa numarası (1'den başlar), varsayılan 1
pageSizenumberSayfa başına kayıt (1-100), varsayılan 25
Hatalar
HTTPCodeAçıklama
401INVALID_KEYAPI anahtarı geçersiz
429RATE_LIMITHız limiti
shell
curl "https://sms.gambi.dev/api/v1/campaigns?page=1&pageSize=25" \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
Yanıt örneği (başarı)
json
{
  "data": [
    {
      "id": 4521,
      "name": "Hafta sonu bonus",
      "status": "COMPLETED",
      "totalRecipients": 2,
      "sentCount": 2,
      "createdAt": "2026-05-19T10:30:00.000Z"
    }
  ],
  "total": 137,
  "page": 1,
  "pageSize": 25
}
GET/api/v1/campaigns/:idAuth Gerekir

Kampanya detayı

Kampanyanın anlık durum ve sayaçları. Canlı kampanyalarda 5sn aralıklarla poll'lanabilir.

Path Parametreleri
AdTipAçıklama
id*numberKampanya ID
Hatalar
HTTPCodeAçıklama
401INVALID_KEYAPI anahtarı geçersiz
404NOT_FOUNDKampanya bulunamadı (veya başka müşteriye ait)
shell
curl https://sms.gambi.dev/api/v1/campaigns/4521 \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
Yanıt örneği (başarı)
json
{
  "id": 4521,
  "name": "Hafta sonu bonus",
  "sender": "MARKANIZ",
  "text": "Bonusunuz hazır: 500 TL",
  "status": "SENDING",
  "segments": 1,
  "encoding": "GSM7",
  "totalRecipients": 1000,
  "sentCount": 750,
  "pendingCount": 250,
  "creditsReserved": 1000,
  "creditsSpent": 750,
  "creditsReservedHuman": "1.000",
  "creditsSpentHuman": "750",
  "scheduledAt": null,
  "createdAt": "2026-05-19T10:30:00.000Z",
  "updatedAt": "2026-05-19T10:45:00.000Z"
}
GET/api/v1/contactsAuth Gerekir

Kontak listesi

Numara rehberindeki kişileri sayfalı döner. ?page (varsayılan 1) ve ?pageSize (varsayılan 50, maks 100) ile sayfalanır. ?q ile telefona göre arama yapılır.

Query Parametreleri
AdTipAçıklama
pagenumberSayfa numarası (1'den başlar), varsayılan 1
pageSizenumberSayfa başına kayıt (1-100), varsayılan 50
qstringTelefon numarasına göre arama (contains)
shell
curl "https://sms.gambi.dev/api/v1/contacts?page=1&pageSize=50" \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
Yanıt örneği (başarı)
json
{
  "data": [
    {
      "id": "1234567890",
      "phone": "+905551234567",
      "firstName": "Ahmet",
      "lastName": "Yılmaz",
      "email": null,
      "country": "TR",
      "tags": [
        "vip"
      ],
      "customFields": null,
      "optedOut": false,
      "createdAt": "2026-04-01T08:00:00.000Z"
    }
  ],
  "total": 4210,
  "page": 1,
  "pageSize": 50
}
POST/api/v1/contactsAuth Gerekir

Kontak oluştur

Yeni kontak ekler. Telefon E.164 formatında, duplicate kontroli sunucuda yapılır.

Request Body (application/json)
AdTipAçıklama
phone*stringE.164 (+905551234567)
firstNamestringAd
lastNamestringSoyad
emailstringE-posta
tagsstring[]Etiketler (örn ["vip","futbol"])
customFieldsobjectCustom JSON alanlar
Hatalar
HTTPCodeAçıklama
409DUPLICATEBu telefonla kişi zaten var
422VALIDATIONGövde doğrulanamadı (örn. phone E.164 değil)
shell
curl -X POST https://sms.gambi.dev/api/v1/contacts \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+905551234567",
    "firstName": "Ahmet",
    "tags": ["vip"]
  }'
Request body örneği
json
{
  "phone": "+905551234567",
  "firstName": "Ahmet",
  "lastName": "Yılmaz",
  "tags": [
    "vip",
    "yatirim_5000_plus"
  ],
  "customFields": {
    "signupSource": "site_form"
  }
}
Yanıt örneği (başarı)
json
{
  "id": "1234567890",
  "phone": "+905551234567",
  "firstName": "Ahmet",
  "lastName": "Yılmaz",
  "email": null,
  "country": "TR",
  "tags": [
    "vip"
  ],
  "customFields": {
    "signupSource": "site_form"
  },
  "optedOut": false,
  "createdAt": "2026-05-19T11:00:00.000Z"
}
GET/api/v1/contacts/:idAuth Gerekir

Kişi detayı

Tek bir kişiyi ID ile döndürür. Yalnızca kendi hesabınıza ait kişilere erişebilirsiniz. Kredi yakmaz.

Path Parametreleri
AdTipAçıklama
id*string (bigint)Kişi kimliği (liste/oluşturma yanıtındaki id)
Hatalar
HTTPCodeAçıklama
404NOT_FOUNDKişi bulunamadı veya size ait değil
shell
curl https://sms.gambi.dev/api/v1/contacts/1234567890 \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
Yanıt örneği (başarı)
json
{
  "id": "1234567890",
  "phone": "+905551234567",
  "firstName": "Ahmet",
  "lastName": null,
  "email": null,
  "country": "TR",
  "tags": [
    "vip"
  ],
  "customFields": null,
  "optedOut": false,
  "createdAt": "2026-05-20T10:00:00.000Z"
}
PATCH/api/v1/contacts/:idAuth Gerekir

Kişi güncelle

Bir kişinin alanlarını kısmi günceller, yalnızca gönderdiğiniz alanlar değişir. PUT da aynı şekilde çalışır. phone gönderirseniz hesabın varsayılan ülkesine göre E.164'e normalize edilir. tags gönderildiğinde mevcut etiketlerin tamamını değiştirir.

Path Parametreleri
AdTipAçıklama
id*string (bigint)Kişi kimliği
Request Body (application/json)
AdTipAçıklama
phonestringYeni numara, E.164'e normalize edilir
firstNamestring | nullAd
lastNamestring | nullSoyad
emailstring | nullGeçerli e-posta adresi
tagsstring[]Etiket listesi (tümünü değiştirir)
customFieldsobjectSerbest anahtar/değer alanları
optedOutbooleanÇıkış (opt-out) durumu
Hatalar
HTTPCodeAçıklama
404NOT_FOUNDKişi bulunamadı
422VALIDATIONGeçersiz gövde
422INVALID_PHONETelefon normalize edilemedi
shell
curl -X PATCH https://sms.gambi.dev/api/v1/contacts/1234567890 \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"firstName":"Mehmet","tags":["vip","2026"]}'
Request body örneği
json
{
  "firstName": "Mehmet",
  "tags": [
    "vip",
    "2026"
  ]
}
Yanıt örneği (başarı)
json
{
  "id": "1234567890",
  "phone": "+905551234567",
  "firstName": "Mehmet",
  "lastName": null,
  "email": null,
  "country": "TR",
  "tags": [
    "vip",
    "2026"
  ],
  "customFields": null,
  "optedOut": false,
  "createdAt": "2026-05-20T10:00:00.000Z"
}
DELETE/api/v1/contacts/:idAuth Gerekir

Kişi sil

Bir kişiyi kalıcı olarak siler. Başarılı silmede gövde dönmez (HTTP 204 No Content). Geri alınamaz.

Path Parametreleri
AdTipAçıklama
id*string (bigint)Silinecek kişi kimliği
Hatalar
HTTPCodeAçıklama
404NOT_FOUNDKişi bulunamadı veya size ait değil
shell
curl -X DELETE https://sms.gambi.dev/api/v1/contacts/1234567890 \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
Yanıt örneği (başarı)
json
204 No Content, yanıt gövdesi yoktur.
GET/api/v1/sms/:messageIdAuth Gerekir

Mesaj durumu sorgula

Tek bir mesajın güncel gönderim durumunu döndürür. messageId, mesajın benzersiz kimliğidir — DLR webhook payload'ındaki messageId alanından gelir (gönderim yanıtı kampanya bazlıdır, tekil messageId döndürmez). errorCode yalnızca kalıcı hatalarda doludur ve jeneriktir (ham operatör kodu içermez). Kredi yakmaz.

Path Parametreleri
AdTipAçıklama
messageId*stringGönderim yanıtındaki provider mesaj kimliği
Hatalar
HTTPCodeAçıklama
400BAD_IDmessageId eksik
404NOT_FOUNDMesaj bulunamadı
shell
curl https://sms.gambi.dev/api/v1/sms/2003b23d-4765-44f7-bdf7-bb14bbb0e36c \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
Yanıt örneği (başarı)
json
{
  "messageId": "2003b23d-4765-44f7-bdf7-bb14bbb0e36c",
  "campaignId": 4521,
  "phone": "+905551234567",
  "status": "SUBMITTED",
  "errorCode": null,
  "segments": 1,
  "sentAt": "2026-05-20T10:00:00.000Z"
}
POST/api/v1/dlrAuth Gerekir

DLR test (echo)

Entegrasyon test ucu: gönderdiğiniz JSON gövdesini (POST) ya da query parametrelerini (GET) aynen 'received' içinde geri döndürür. Gerçek teslim raporları bu uçtan GELMEZ, onlar sizin webhook URL'inize POST edilir (bkz. Webhooks › DLR webhook). Bu uç yalnızca kendi tarafınızı denemek/log akışını görmek içindir; GET ve POST kabul eder, kredi yakmaz.

Request Body (application/json)
AdTipAçıklama
(serbest)objectHerhangi bir JSON, değişmeden 'received' alanında döner
Hatalar
HTTPCodeAçıklama
401INVALID_KEYAPI anahtarı geçersiz
405METHODGET/POST dışında bir method kullanıldı
shell
curl -X POST https://sms.gambi.dev/api/v1/dlr \
  -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"messageId":"abc-123","status":"SUBMITTED"}'
Request body örneği
json
{
  "messageId": "abc-123",
  "status": "SUBMITTED"
}
Yanıt örneği (başarı)
json
{
  "ok": true,
  "received": {
    "messageId": "abc-123",
    "status": "SUBMITTED"
  }
}

Webhook Formatı

POST[Senin webhook URL'in]

DLR webhook (durum raporu)

Mesajın durumu kesinleştikçe (SUBMITTED/FAILED/EXPIRED/REJECTED) sistem senin kayıtlı webhook URL'ine POST yapar. SUBMITTED, mesajın operatöre iletildiği anlamına gelir. İmza: x-gambisms-signature header'ında HMAC-SHA256(raw body, webhook secret); ayrıca x-gambisms-event: dlr header'ı gelir. 2xx beklenir; 5xx/ağ hatasında 5 deneme exponential backoff (yaklaşık 5s, 25s, 2dk, 10dk, 50dk), 4xx kalıcı hata sayılır. status alanı jeneriktir; ham operatör kodları gönderilmez.

shell
# Webhook URL'ini hesap ayarlarından kaydet:
# /app/settings → Webhook URL → Kaydet

# İmza doğrulama (Node.js):
import crypto from "node:crypto";
const sig = req.headers["x-gambisms-signature"];
const expected = crypto
  .createHmac("sha256", USER_WEBHOOK_SECRET)
  .update(req.rawBody)
  .digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
  return res.status(401).send("Invalid signature");
}
// process req.body...
res.status(200).send("ok");
Request body örneği
json
{
  "event": "dlr",
  "campaignId": 4521,
  "phone": "+905551234567",
  "messageId": "a1b2c3d4-...",
  "status": "SUBMITTED",
  "timestamp": "2026-05-19T12:05:00.000Z"
}
Yanıt örneği (başarı)
json
// Beklenen yanıt: 2xx (HTTP 200-299). Body göz ardı edilir.
// 4xx/5xx alırsa exponential backoff retry yapılır.

Tüm Hata Kodları

Hata yanıtları daima { "error": "...", "code": "..." } formatındadır (error insan-okur mesaj, code makine-okur kod). HTTP status koduyla birlikte code alanını kontrol et.

HTTPCodeAçıklama
400BAD_JSONİstek gövdesi geçerli JSON değil
401NO_KEYX-Api-Key header eksik
401INVALID_KEYAPI anahtarı geçersiz veya iptal edilmiş
405METHODEndpoint için izin verilmeyen HTTP method
404NOT_FOUNDKaynak bulunamadı veya başka müşteriye ait
422VALIDATIONBody veya query doğrulanamadı
429RATE_LIMITHız limiti aşıldı (30 req/sn varsayılan); Retry-After header'ına bak
429AUTH_RATE_LIMITKimlik doğrulama denemesi çok sık (IP bazlı)
500INTERNALBeklenmeyen sunucu hatası
402INSUFFICIENT_CREDITYetersiz kredi
409DUPLICATE_REQUESTAynı istek kısa süre içinde tekrarlandı (Idempotency-Key)
413TOO_MANYAlıcı limiti aşıldı (maks 100.000)
422NO_RECIPIENTSGeçerli E.164 alıcı yok
422ALL_SUPPRESSEDTüm alıcılar bastırılmış (opt-out/blacklist)
422TOO_LONGMesaj 5 segmenti aşıyor
503QUEUE_UNAVAILABLEKuyruk geçici olarak kullanılamıyor, tekrar deneyin
409DUPLICATEBu telefonla kişi zaten kayıtlı
422INVALID_PHONETelefon E.164'e normalize edilemedi
422CSW_WINDOW_CLOSED24h CSW kapalı, template gerek
422BRAND_TERMS_NOT_ACCEPTEDMARKETING için BrandKit terms gerekli
422FREQ_CAP24h içinde aynı alıcıya tekrar gönderim engellendi
422QUALITY_LOWNumara LOW quality, MARKETING bloklandı
422OPTED_OUTAlıcı STOP/DUR ile opt-out etmiş