API Dokümantasyonu
SMS ve WhatsApp Business mesajlaşma 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-Remaining: 28 X-RateLimit-Reset: 1700000123
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, DLR webhook'larıyla durumu takip edilir. Segment hesaplaması otomatik (GSM-7 için 160 char, Unicode için 70 char). Kredi düşümü gönderim öncesi atılır, başarısız mesajlar için iade yapılır. NOT: Mesajdaki linkler teslimat için otomatik normalize edilir, http(s):// ve www. kaldırılır (ör. https://www.site.com → site.com). Linki noktasıyla yazmanız yeterli; operatör filtresi ve ulaşılabilirlik için bu işlem otomatik yapılır.
| Ad | Tip | Açıklama |
|---|---|---|
| to* | string[] | string | E.164 formatında alıcı(lar): '+905551234567'. Tek string veya array |
| text* | string | Mesaj gövdesi. Maks 5 segment (Unicode için 5×70=350 char) |
| sender | string | Onaylı gönderici adı. Boş bırakılırsa varsayılan kullanılır |
| campaignName | string | Raporlarda görünecek kampanya adı (varsayılan: 'API send') |
| scheduledAt | string (ISO8601) | İleri tarihli gönderim. Boş = anında |
| HTTP | Code | Açıklama |
|---|---|---|
| 401 | NO_KEY | X-Api-Key header eksik |
| 401 | INVALID_KEY | API anahtarı geçersiz |
| 402 | INSUFFICIENT_CREDIT | Yetersiz bakiye |
| 403 | SENDER_NOT_APPROVED | Sender ID onaysız |
| 422 | VALIDATION | Body doğrulanamadı (zod) |
| 422 | TOO_LONG | Mesaj 5 segmenti aşıyor |
| 422 | NO_RECIPIENTS | Geçerli E.164 alıcı yok |
| 413 | TOO_MANY | Alıcı limiti aşıldı (100k) |
| 429 | RATE_LIMIT | 30 istek/sn limit |
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",
"sender": "BAHIS123"
}'{
"to": [
"+905551234567",
"+905559876543"
],
"text": "Merhaba {{1}}, bonusunuz hazır: {{2}} TL",
"sender": "BAHIS123",
"campaignName": "Hafta sonu bonus"
}{
"ok": true,
"campaignId": 4521,
"accepted": 2,
"rejected": 0,
"creditsReserved": "2.00",
"balanceAfter": "1248.50"
}/api/v1/sms/balanceAuth GerekirSMS bakiyesi
SMS kredi bakiyenizi (kredi cinsinden + TL karşılığı) döner. 1 kredi = 1 SMS segmenti. Tier'ınıza göre per-segment fiyat değişir.
| 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"
{
"ok": true,
"balanceCredits": 1248.5,
"balanceTL": 374.55,
"pricePerSegmentTL": 0.3,
"tier": "Pro"
}/api/v1/campaignsAuth GerekirKampanya listesi
Son 30 günlük SMS kampanyalarınızı sayfalı olarak döner. ?limit=N (max 100) ve ?cursor=N pagination.
| Ad | Tip | Açıklama |
|---|---|---|
| limit | number | 1-100, varsayılan 20 |
| cursor | number | Önceki yanıtın nextCursor'u |
| status | string | DRAFT|QUEUED|SENDING|COMPLETED|FAILED |
| 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?limit=20" \ -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
{
"ok": true,
"items": [
{
"id": 4521,
"name": "Hafta sonu bonus",
"status": "COMPLETED",
"totalRecipients": 2,
"sentCount": 2,
"deliveredCount": 2,
"failedCount": 0,
"createdAt": "2026-05-19T10:30:00Z"
}
],
"nextCursor": 4520
}/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"
{
"ok": true,
"campaign": {
"id": 4521,
"name": "Hafta sonu bonus",
"status": "SENDING",
"totalRecipients": 1000,
"sentCount": 750,
"deliveredCount": 620,
"failedCount": 30,
"pendingCount": 250,
"creditsReserved": 1000,
"creditsSpent": 750,
"createdAt": "2026-05-19T10:30:00Z"
}
}/api/v1/contactsAuth GerekirKontak listesi
Numara rehberindeki kontakları sayfalı döner.
| Ad | Tip | Açıklama |
|---|---|---|
| limit | number | 1-100, varsayılan 50 |
| cursor | string | Önceki yanıtın nextCursor'u (BigInt) |
| search | string | Telefon/ad arama |
curl "https://sms.gambi.dev/api/v1/contacts?limit=50" \ -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
{
"ok": true,
"items": [
{
"id": "1234567890",
"phone": "+905551234567",
"firstName": "Ahmet",
"lastName": "Yılmaz",
"country": "TR",
"optedOut": false,
"createdAt": "2026-04-01T08:00:00Z"
}
],
"nextCursor": "1234567889"
}/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 kontak zaten var |
| 422 | VALIDATION | 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"
}
}{
"ok": true,
"contact": {
"id": "1234567890",
"phone": "+905551234567",
"createdAt": "2026-05-19T11:00:00Z"
}
}/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 durumunu döndürür. messageId, gönderim yanıtındaki provider mesaj kimliğidir (results[].messageId). 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": "DELIVERED",
"errorCode": null,
"segments": 1,
"sentAt": "2026-05-20T10:00:00.000Z",
"deliveredAt": "2026-05-20T10:00:05.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":"DELIVERED"}'{
"messageId": "abc-123",
"status": "DELIVERED"
}{
"ok": true,
"received": {
"messageId": "abc-123",
"status": "DELIVERED"
}
}OTP Endpoint'leri
/api/v1/otp/sendAuth GerekirOTP gönder
Bir telefon numarasına tek kullanımlık doğrulama kodu (OTP) gönderir. Kod sunucuda üretilir ve güvenli saklanır; siz yalnızca bir requestId alırsınız (kod yanıtta DÖNMEZ). Onaylı bir sender ID zorunludur. Şablon {code} placeholder'ı içermelidir; mesaj 5 segmenti aşamaz. Kredi gönderim anında düşülür.
| Ad | Tip | Açıklama |
|---|---|---|
| phone* | string | Alıcı numara (E.164 veya hesabın varsayılan ülkesine göre normalize edilir) |
| sender* | string | Onaylı gönderici adı (maks 15 karakter) |
| template | string | Mesaj şablonu; {code} yerine kod konur. Varsayılan: 'GambiSMS dogrulama kodunuz: {code}' |
| length | number | Kod uzunluğu, 4-10 |
| ttl | number | Geçerlilik süresi (saniye), 60-1800 |
| maxAttempts | number | İzin verilen doğrulama denemesi, 1-10 |
| HTTP | Code | Açıklama |
|---|---|---|
| 400 | INVALID_PHONE | Geçersiz telefon numarası |
| 400 | INVALID_TEMPLATE | Şablon {code} placeholder içermiyor |
| 402 | INSUFFICIENT_CREDITS | Yetersiz kredi |
| 403 | SENDER_NOT_APPROVED | Sender ID onaylı değil |
| 422 | TOO_LONG | OTP mesajı 5 segmenti aşıyor |
| 502 | SEND_FAILED | SMS gönderimi başarısız |
curl -X POST https://sms.gambi.dev/api/v1/otp/send \
-H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"phone":"+905551234567","sender":"GAMBI","template":"Kodunuz: {code}"}'{
"phone": "+905551234567",
"sender": "GAMBI",
"template": "Kodunuz: {code}",
"length": 6,
"ttl": 300
}{
"requestId": "otp_a1b2c3d4",
"phone": "+905551234567",
"expiresAt": "2026-05-20T10:05:00.000Z",
"status": "PENDING",
"costCredits": "1"
}/api/v1/otp/verifyAuth GerekirOTP doğrula
Kullanıcının girdiği kodu, otp/send'den dönen requestId ile doğrular. verified=true ise kod doğru. Yanlış kodda triesRemaining kalan deneme sayısını verir; denemeler bitince veya süre dolunca status REJECTED/EXPIRED olur.
| Ad | Tip | Açıklama |
|---|---|---|
| requestId* | string | otp/send yanıtındaki requestId |
| code* | string | Kullanıcının girdiği kod |
| HTTP | Code | Açıklama |
|---|---|---|
| 404 | NOT_FOUND | OTP isteği bulunamadı |
| 422 | VALIDATION | requestId/code eksik veya geçersiz |
curl -X POST https://sms.gambi.dev/api/v1/otp/verify \
-H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"requestId":"otp_a1b2c3d4","code":"123456"}'{
"requestId": "otp_a1b2c3d4",
"code": "123456"
}{
"verified": true,
"status": "APPROVED",
"triesRemaining": 0
}/api/v1/otp/statusAuth GerekirOTP durumu
Bir OTP isteğinin güncel durumunu döndürür. Süresi geçmiş PENDING istekler bu çağrıda EXPIRED'a çevrilir. Kredi yakmaz.
| Ad | Tip | Açıklama |
|---|---|---|
| requestId* | string | otp/send yanıtındaki requestId |
| HTTP | Code | Açıklama |
|---|---|---|
| 404 | NOT_FOUND | OTP isteği bulunamadı |
| 422 | VALIDATION | requestId gereklidir |
curl "https://sms.gambi.dev/api/v1/otp/status?requestId=otp_a1b2c3d4" \ -H "X-Api-Key: gsms_xxxxxxxxxxxxxxxx"
{
"requestId": "otp_a1b2c3d4",
"status": "PENDING",
"phone": "+905551234567",
"expiresAt": "2026-05-20T10:05:00.000Z",
"verifyAttempts": 0,
"maxAttempts": 3,
"createdAt": "2026-05-20T10:00:00.000Z"
}Webhook Formatı
[Senin webhook URL'in]DLR webhook (SMS + WhatsApp)
Mesaj durumu değiştikçe (DELIVERED/FAILED/READ vs.) sistem senin kayıtlı webhook URL'ine POST yapar. İmza: x-gambisms-signature header'ında HMAC-SHA256(body, USER_WEBHOOK_SECRET). İlk başarısızda 5 deneme exponential backoff.
# 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": "status.delivered",
"channel": "whatsapp",
"campaignId": 101,
"phone": "+905551234567",
"providerMessageId": "wamid.HBgM...",
"status": "DELIVERED",
"timestamp": "2026-05-19T12:05:00Z",
"windowType": "MARKETING"
}// Beklenen yanıt: 2xx (HTTP 200-299). Body göz ardı edilir. // 4xx/5xx alırsa exponential backoff retry yapılır.
[Senin webhook URL'in]WhatsApp inbound message webhook
Müşterilerinizden gelen tüm WhatsApp mesajları (text, image, button reply, vb.) webhook URL'ine POST edilir. İmza aynı DLR mantığı. Ek alanlar: messageDirection, contentType, mediaUrl, templateName (eğer önceki template'e yanıtsa).
# Aynı imza doğrulama akışı, yukarıda DLR örneğine bak.
{
"event": "message.inbound",
"channel": "whatsapp",
"numberId": 7,
"phone": "+905551234567",
"providerMessageId": "wamid.HBgM...",
"contentType": "TEXT",
"text": "Bonusumu nasıl alırım?",
"timestamp": "2026-05-19T12:01:00Z",
"windowOpened": true
}// Beklenen yanıt: 2xx. Aynı imza doğrulama mantığı. // İçerik: text mesajda "text"; medyalı mesajda "mediaUrl" alanı dolu gelir.
Tüm Hata Kodları
Hata yanıtları daima { ok: false, code: "...", message: "..." } formatındadır. HTTP status koduyla birlikte bu kodu kontrol et.
| HTTP | Code | Açıklama |
|---|---|---|
| 401 | NO_KEY | X-Api-Key header eksik |
| 401 | INVALID_KEY | API anahtarı geçersiz veya iptal edilmiş |
| 402 | INSUFFICIENT_CREDIT | Yetersiz bakiye |
| 403 | SENDER_NOT_APPROVED | Sender ID admin tarafından onaylanmamış |
| 404 | NOT_FOUND | Kaynak bulunamadı veya başka müşteriye ait |
| 409 | DUPLICATE | Aynı kayıt zaten var |
| 413 | TOO_MANY | Alıcı limiti aşıldı |
| 422 | VALIDATION | Body veya query doğrulanamadı (zod) |
| 422 | TOO_LONG | Mesaj 5 segmenti aşıyor |
| 422 | NO_RECIPIENTS | Geçerli E.164 alıcı yok |
| 422 | TEMPLATE_NOT_APPROVED | WhatsApp şablonu APPROVED değil |
| 422 | CHANNEL_NOT_ACTIVE | WhatsApp numarası aktif değil |
| 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ş |
| 429 | RATE_LIMIT | Hız limiti (30 req/sn varsayılan) |
| 500 | INTERNAL | Beklenmeyen sunucu hatası |