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.
https://sms.gambi.devX-Api-Keyapplication/jsonHızlı Başlangıç
- 1. Hesap oluştur (30 saniye, e-posta + parola).
- 2. Panelde
/app/api-keyssayfasından bir API anahtarı oluştur. Anahtar formatı:gsms_xxxxxxxxxxxxxxxx(sadece 1 kez gösterilir, kaydet). - 3. Test isteğini at:
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:
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
/api/v1/meAuth GerekirHesap 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.
| HTTP | Code | Açıklama |
|---|---|---|
| 401 | NO_KEY | X-Api-Key header eksik |
| 401 | INVALID_KEY | API anahtarı geçersiz |
curl https://sms.gambi.dev/api/v1/me \ -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
{
"ok": true,
"userId": 42,
"email": "ops@bahis123.com",
"role": "USER",
"balanceCredits": 1250.5,
"balanceWaCredits": 800
}SMS Endpoint'leri
/api/v1/sms/sendAuth GerekirToplu 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).
| Ad | Tip | Açı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* | string | Mesaj gövdesi. En az 1 karakter, en fazla 5 segment |
| from | string | Gö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 |
| scheduled | string (ISO8601) | İleri tarihli gönderim zamanı. Boş = anında |
| smartScheduling | boolean | Varsayılan true. Açıkken gönderim yasal iletişim saatleri dışına denk gelirse ilk uygun saate ötelenir. false verirseniz öteleme yapılmaz |
| dlr_url | string (https) | Bu gönderime özel DLR webhook URL'i (https zorunlu). Boş bırakılırsa hesap ayarlarındaki varsayılan kullanılır |
| HTTP | Code | Açıklama |
|---|---|---|
| 400 | BAD_JSON | Gövde geçerli JSON değil |
| 401 | NO_KEY | X-Api-Key header eksik |
| 401 | INVALID_KEY | API anahtarı geçersiz |
| 402 | INSUFFICIENT_CREDIT | Yetersiz kredi |
| 409 | DUPLICATE_REQUEST | Aynı istek kısa süre içinde tekrarlandı (Idempotency-Key) |
| 413 | TOO_MANY | Alıcı limiti aşıldı (maks 100.000) |
| 422 | VALIDATION | Gövde doğrulanamadı |
| 422 | NO_RECIPIENTS | Geçerli E.164 alıcı yok |
| 422 | ALL_SUPPRESSED | Tüm alıcılar bastırılmış (opt-out/blacklist) |
| 422 | TOO_LONG | Mesaj 5 segmenti aşıyor |
| 429 | RATE_LIMIT | Hız limiti aşıldı (30 istek/sn) |
| 503 | QUEUE_UNAVAILABLE | Kuyruk geçici olarak kullanılamıyor, tekrar deneyin |
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"
}'{
"to": [
"+905551234567",
"+905559876543"
],
"text": "Bonusunuz hazır: 500 TL"
}{
"campaignId": 4521,
"totalRecipients": 2,
"suppressedSkipped": 0,
"segments": 1,
"costCredits": 2,
"costCreditsHuman": "2",
"status": "QUEUED",
"spamScore": {
"score": 0,
"level": "low",
"warnings": []
}
}/api/v1/sms/balanceAuth GerekirSMS 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.)
| HTTP | Code | Açıklama |
|---|---|---|
| 401 | NO_KEY | X-Api-Key header eksik |
| 401 | INVALID_KEY | API anahtarı geçersiz |
curl https://sms.gambi.dev/api/v1/sms/balance \ -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
{
"credits": 1248,
"creditsHuman": "1.248",
"currency": "GambiSMS Credit",
"balance": 0,
"usdt": null
}/api/v1/campaignsAuth GerekirKampanya 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.
| Ad | Tip | Açıklama |
|---|---|---|
| page | number | Sayfa numarası (1'den başlar), varsayılan 1 |
| pageSize | number | Sayfa başına kayıt (1-100), varsayılan 25 |
| HTTP | Code | Açıklama |
|---|---|---|
| 401 | INVALID_KEY | API anahtarı geçersiz |
| 429 | RATE_LIMIT | Hız limiti |
curl "https://sms.gambi.dev/api/v1/campaigns?page=1&pageSize=25" \ -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
{
"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
}/api/v1/campaigns/:idAuth GerekirKampanya detayı
Kampanyanın anlık durum ve sayaçları. Canlı kampanyalarda 5sn aralıklarla poll'lanabilir.
| Ad | Tip | Açıklama |
|---|---|---|
| id* | number | Kampanya ID |
| HTTP | Code | Açıklama |
|---|---|---|
| 401 | INVALID_KEY | API anahtarı geçersiz |
| 404 | NOT_FOUND | Kampanya bulunamadı (veya başka müşteriye ait) |
curl https://sms.gambi.dev/api/v1/campaigns/4521 \ -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
{
"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"
}/api/v1/contactsAuth GerekirKontak 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.
| Ad | Tip | Açıklama |
|---|---|---|
| page | number | Sayfa numarası (1'den başlar), varsayılan 1 |
| pageSize | number | Sayfa başına kayıt (1-100), varsayılan 50 |
| q | string | Telefon numarasına göre arama (contains) |
curl "https://sms.gambi.dev/api/v1/contacts?page=1&pageSize=50" \ -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
{
"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
}/api/v1/contactsAuth GerekirKontak oluştur
Yeni kontak ekler. Telefon E.164 formatında, duplicate kontroli sunucuda yapılır.
| Ad | Tip | Açıklama |
|---|---|---|
| phone* | string | E.164 (+905551234567) |
| firstName | string | Ad |
| lastName | string | Soyad |
| string | E-posta | |
| tags | string[] | Etiketler (örn ["vip","futbol"]) |
| customFields | object | Custom JSON alanlar |
| HTTP | Code | Açıklama |
|---|---|---|
| 409 | DUPLICATE | Bu telefonla kişi zaten var |
| 422 | VALIDATION | Gövde doğrulanamadı (örn. phone E.164 değil) |
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"]
}'{
"phone": "+905551234567",
"firstName": "Ahmet",
"lastName": "Yılmaz",
"tags": [
"vip",
"yatirim_5000_plus"
],
"customFields": {
"signupSource": "site_form"
}
}{
"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"
}/api/v1/contacts/:idAuth GerekirKiş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.
| Ad | Tip | Açıklama |
|---|---|---|
| id* | string (bigint) | Kişi kimliği (liste/oluşturma yanıtındaki id) |
| HTTP | Code | Açıklama |
|---|---|---|
| 404 | NOT_FOUND | Kişi bulunamadı veya size ait değil |
curl https://sms.gambi.dev/api/v1/contacts/1234567890 \ -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
{
"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"
}/api/v1/contacts/:idAuth GerekirKiş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.
| Ad | Tip | Açıklama |
|---|---|---|
| id* | string (bigint) | Kişi kimliği |
| Ad | Tip | Açıklama |
|---|---|---|
| phone | string | Yeni numara, E.164'e normalize edilir |
| firstName | string | null | Ad |
| lastName | string | null | Soyad |
| string | null | Geçerli e-posta adresi | |
| tags | string[] | Etiket listesi (tümünü değiştirir) |
| customFields | object | Serbest anahtar/değer alanları |
| optedOut | boolean | Çıkış (opt-out) durumu |
| HTTP | Code | Açıklama |
|---|---|---|
| 404 | NOT_FOUND | Kişi bulunamadı |
| 422 | VALIDATION | Geçersiz gövde |
| 422 | INVALID_PHONE | Telefon normalize edilemedi |
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"]}'{
"firstName": "Mehmet",
"tags": [
"vip",
"2026"
]
}{
"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"
}/api/v1/contacts/:idAuth GerekirKişi sil
Bir kişiyi kalıcı olarak siler. Başarılı silmede gövde dönmez (HTTP 204 No Content). Geri alınamaz.
| Ad | Tip | Açıklama |
|---|---|---|
| id* | string (bigint) | Silinecek kişi kimliği |
| HTTP | Code | Açıklama |
|---|---|---|
| 404 | NOT_FOUND | Kişi bulunamadı veya size ait değil |
curl -X DELETE https://sms.gambi.dev/api/v1/contacts/1234567890 \ -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
204 No Content, yanıt gövdesi yoktur.
/api/v1/sms/:messageIdAuth GerekirMesaj 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.
| Ad | Tip | Açıklama |
|---|---|---|
| messageId* | string | Gönderim yanıtındaki provider mesaj kimliği |
| HTTP | Code | Açıklama |
|---|---|---|
| 400 | BAD_ID | messageId eksik |
| 404 | NOT_FOUND | Mesaj bulunamadı |
curl https://sms.gambi.dev/api/v1/sms/2003b23d-4765-44f7-bdf7-bb14bbb0e36c \ -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
{
"messageId": "2003b23d-4765-44f7-bdf7-bb14bbb0e36c",
"campaignId": 4521,
"phone": "+905551234567",
"status": "SUBMITTED",
"errorCode": null,
"segments": 1,
"sentAt": "2026-05-20T10:00:00.000Z"
}/api/v1/dlrAuth GerekirDLR 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.
| Ad | Tip | Açıklama |
|---|---|---|
| (serbest) | object | Herhangi bir JSON, değişmeden 'received' alanında döner |
| HTTP | Code | Açıklama |
|---|---|---|
| 401 | INVALID_KEY | API anahtarı geçersiz |
| 405 | METHOD | GET/POST dışında bir method kullanıldı |
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"}'{
"messageId": "abc-123",
"status": "SUBMITTED"
}{
"ok": true,
"received": {
"messageId": "abc-123",
"status": "SUBMITTED"
}
}Webhook Formatı
[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.
# 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");{
"event": "dlr",
"campaignId": 4521,
"phone": "+905551234567",
"messageId": "a1b2c3d4-...",
"status": "SUBMITTED",
"timestamp": "2026-05-19T12:05:00.000Z"
}// 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.
| HTTP | Code | Açıklama |
|---|---|---|
| 400 | BAD_JSON | İstek gövdesi geçerli JSON değil |
| 401 | NO_KEY | X-Api-Key header eksik |
| 401 | INVALID_KEY | API anahtarı geçersiz veya iptal edilmiş |
| 405 | METHOD | Endpoint için izin verilmeyen HTTP method |
| 404 | NOT_FOUND | Kaynak bulunamadı veya başka müşteriye ait |
| 422 | VALIDATION | Body veya query doğrulanamadı |
| 429 | RATE_LIMIT | Hız limiti aşıldı (30 req/sn varsayılan); Retry-After header'ına bak |
| 429 | AUTH_RATE_LIMIT | Kimlik doğrulama denemesi çok sık (IP bazlı) |
| 500 | INTERNAL | Beklenmeyen sunucu hatası |
| 402 | INSUFFICIENT_CREDIT | Yetersiz kredi |
| 409 | DUPLICATE_REQUEST | Aynı istek kısa süre içinde tekrarlandı (Idempotency-Key) |
| 413 | TOO_MANY | Alıcı limiti aşıldı (maks 100.000) |
| 422 | NO_RECIPIENTS | Geçerli E.164 alıcı yok |
| 422 | ALL_SUPPRESSED | Tüm alıcılar bastırılmış (opt-out/blacklist) |
| 422 | TOO_LONG | Mesaj 5 segmenti aşıyor |
| 503 | QUEUE_UNAVAILABLE | Kuyruk geçici olarak kullanılamıyor, tekrar deneyin |
| 409 | DUPLICATE | Bu telefonla kişi zaten kayıtlı |
| 422 | INVALID_PHONE | Telefon E.164'e normalize edilemedi |
| 422 | CSW_WINDOW_CLOSED | 24h CSW kapalı, template gerek |
| 422 | BRAND_TERMS_NOT_ACCEPTED | MARKETING için BrandKit terms gerekli |
| 422 | FREQ_CAP | 24h içinde aynı alıcıya tekrar gönderim engellendi |
| 422 | QUALITY_LOW | Numara LOW quality, MARKETING bloklandı |
| 422 | OPTED_OUT | Alıcı STOP/DUR ile opt-out etmiş |