API başvurusu
Tüm 2X ürünleri aynı API’yi kullanır. Bu sayfa geliştirici için kısa bir başvurudur; tam şema panelde ve OpenAPI belgesinde yer alır.
Durum: e-posta gönderimi ve webhook canlıdır. SMS gönderiminde operatör bağlantısı açılış aşamasındadır. OTP uçları açılış aşamasındadır; alan adları değişebilir.
Genel kurallar
- Taban adres:
https://api.reach2x.com - İstek ve yanıtlar JSON (UTF-8). Zamanlar RFC 3339, UTC.
- Telefon numaraları E.164 (
+905321234567) gönderilir, yanıtlarda maskelenir (+90 5** *** ** 67). - İleti gövdesi kuruluşunuzun saklama süresi boyunca tutulur ve API’den asla geri döndürülmez. otp kategorisinde gövde hiç saklanmaz.
Kimlik doğrulama
Her isteğe proje API anahtarını Bearer olarak ekleyin:
Authorization: Bearer rx_canli_… (canlı) · rx_test_… (test projesi; gerçek alıcıya hiçbir şey gitmez)
Anahtarlar panelde oluşturulur. Gizli değer yalnız bir kez gösterilir; yalnız karması saklanır. Bir anahtar tek projeye aittir; isteğe bağlı olarak izinli göndericiler, IP izin listesi ve son kullanma tarihi taşır.
| Kapsam | İzin verdiği |
|---|---|
sms.send | SMS gönderme ve zamanlanmış SMS iptali |
sms.read | SMS ve ileti listesini okuma |
email.send | E-posta gönderme |
email.read | E-posta okuma |
otp.send | Doğrulama kodu gönderme (açılış aşamasında) |
otp.verify | Doğrulama kodunu kontrol etme (açılış aşamasında) |
webhook.manage | Webhook uçlarını yönetme |
balance.read | Kota ve kullanım okuma |
Idempotency
Bir şey gönderen her çağrı Idempotency-Key başlığı ister: 8–128 karakter, A-Z a-z 0-9 _ - : . (UUID uygundur). Anahtar kuruluş + kimlik başına 24 saat saklanır.
- Aynı anahtar + aynı gövde → ilk yanıt döner,
Idempotent-Replay: truebaşlığıyla. - Aynı anahtar + farklı gövde →
422 idempotency_key_mismatch. - İlk istek sürerken →
409 idempotency_in_progress.
E-posta gönder POST /v1/emails
Kapsam email.send. Alıcı başına bir ileti oluşturur ve kalıcı olarak kaydettikten sonra 202 döner. Gönderen alan adının doğrulanmış olması gerekir; ileti o alan için DKIM ile imzalanır. Ek dosya bu sürümde yoktur.
| Alan | Tip | Açıklama |
|---|---|---|
from | string | {email, name} | Doğrulanmış gönderen alanınızdan adres. Zorunlu. |
to | string | string[] | Bir adres ya da en çok 50 adres. Zorunlu. |
subject | string | 1–998 karakter. Zorunlu. |
text / html | string | En az biri zorunlu; her biri en çok 500.000 karakter. |
category | informational | otp | commercial | Zorunlu. commercial henüz açık değil. |
reply_to | string | Yanıt adresi. |
send_at | date-time | En çok 30 gün ileri; boşsa hemen. |
valid_for_minutes | integer | 1–4320, varsayılan 2880. Süre dolunca expired. |
tags | object | En çok 10 anahtar/değer; kişisel veri koymayın. |
curl https://api.reach2x.com/v1/emails \
-H "Authorization: Bearer $REACH2X_API_KEY" \
-H "Idempotency-Key: rapor-2026-11-0001" \
-H "Content-Type: application/json" \
-d '{
"from": { "email": "[email protected]", "name": "Example" },
"to": "[email protected]",
"subject": "Aylık raporunuz hazır",
"text": "Raporunuz hazır: https://example.com/r/Ab12",
"category": "informational"
}' {
"batch_id": "7d1c2e60-4a8b-4f0e-9b1a-2f6c1d9e3a10",
"messages": [{
"id": "c0a8f1e2-5b3d-4e7f-8a9b-1c2d3e4f5a6b",
"object": "email",
"status": "queued",
"category": "informational",
"from": "[email protected]",
"to": "a***@example.org"
}]
} Okuma: GET /v1/emails, GET /v1/emails/{id} (olay zaman çizelgesiyle; kapsam email.read).
SMS gönder POST /v1/sms
TXT2X operatör bağlantısı açılış aşamasındadır — yakında canlı. Test anahtarıyla aynı çağrıyı bugün deneyebilirsiniz.
Kapsam sms.send. category hukuki işlemi belirler: informational (işlem bilgisi), otp (gövde saklanmaz), commercial (İYS: alıcı tipi ve marka kodu gerekir; izni olmayan alıcı recipient_no_consent ile düşer).
Kodlama otomatik seçilir: gsm7 160/153, gsm7_tr 155/149, ucs2 70/67 karakter/segment.
| Alan | Tip | Açıklama |
|---|---|---|
to | string | string[] | E.164 numara ya da en çok 100 farklı numara. Zorunlu. |
body | string | Kodlamadan sonra en çok 7 segment. Zorunlu. |
category | informational | otp | commercial | Zorunlu. Hukuki işlemi belirler. |
sender | string | Onaylı gönderici adı, 3–11 karakter. Boşsa projenin varsayılanı. |
send_at | date-time | En çok 30 gün ileri. |
valid_for_minutes | integer | 1–2880, varsayılan 1440. |
commercial.recipient_type | individual | merchant | commercial kategoride zorunlu (İYS alıcı tipi). |
tags | object | En çok 10 anahtar/değer. |
curl https://api.reach2x.com/v1/sms \
-H "Authorization: Bearer $REACH2X_API_KEY" \
-H "Idempotency-Key: randevu-48213" \
-H "Content-Type: application/json" \
-d '{
"to": "+905321234567",
"body": "Randevunuz 18 Kasım 14:30. Değişiklik: https://example.com/r/Ab12",
"category": "informational",
"sender": "EXAMPLE"
}' {
"batch_id": "3f9a2b7c-1d4e-4a5b-8c6d-7e8f9a0b1c2d",
"messages": [{
"id": "8b7a6c5d-4e3f-4a2b-9c1d-0e9f8a7b6c5d",
"object": "sms",
"status": "queued",
"to": "+90 5** *** ** 67",
"sender": "EXAMPLE",
"segments": 1,
"encoding": "gsm7_tr"
}]
} Diğer uçlar: GET /v1/sms/{id}, POST /v1/sms/{id}/cancel (yalnız scheduled), GET /v1/balance (kapsam balance.read).
Doğrulama kodu (OTP)
E-posta kanalı canlıdır; SMS kanalı operatör bağlantısıyla birlikte açılır. Her POST bir Idempotency-Key ister; aynı alıcıya 60 sn’de bir kod (saatte en çok 5), 5 yanlış denemede kod kilitlenir, kod tek kullanımlıktır.
POST /v1/otp—{ channel: "sms" | "email", to, from?, subject?, sender?, length?, ttl_seconds?, template? }→ 201{ id, status, attempts_left, expires_at, … }. Kapsamotp.send.POST /v1/otp/{id}/verify—{ code }→{ verified, attempts_left, status }; hata kodlarıotp_expired410,otp_locked409,otp_already_verified409,otp_rate_limited429. Kapsamotp.verify.
curl https://api.reach2x.com/v1/otp \
-H "Authorization: Bearer $REACH2X_API_KEY" \
-H "Idempotency-Key: giris-7f3a91c2" \
-H "Content-Type: application/json" \
-d '{
"channel": "email",
"to": "[email protected]",
"from": "[email protected]",
"length": 6,
"ttl_seconds": 300
}' {
"id": "5e4d3c2b-1a09-4f8e-8d7c-6b5a49382716",
"object": "otp",
"channel": "email",
"status": "pending",
"to": "a***@ornek.com",
"attempts_left": 5,
"expires_at": "2026-11-14T09:35:00Z"
} curl https://api.reach2x.com/v1/otp/5e4d3c2b-1a09-4f8e-8d7c-6b5a49382716/verify \
-H "Authorization: Bearer $REACH2X_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "code": "482913" }' {
"verified": true,
"attempts_left": 4,
"status": "verified"
} İleti durumları
scheduled → queued → sending → sent → delivered | failed | expired; canceled yalnız scheduled’dan.
| Durum | Anlamı |
|---|---|
scheduled | send_at zamanını bekliyor; yalnız bu durumda iptal edilebilir. |
queued | Kuyrukta; geçici ağ hatasında da buraya döner. |
sending | Ağa teslim ediliyor (geçici). |
sent | Ağ kabul etti; cihaz raporu bekleniyor. |
delivered | SMS: cihaz raporu geldi. E-posta: alıcı sunucusu kabul etti (SMTP 250). |
failed | Teslim edilemedi; error.code nedeni verir. |
expired | Geçerlilik süresi teslimden önce doldu. |
canceled | Zamanlanmış ileti iptal edildi. |
Webhook
Uçları GET/POST /v1/webhooks, DELETE /v1/webhooks/{id}, POST /v1/webhooks/{id}/rotate-secret ile yönetin (kapsam webhook.manage). Yalnız herkese açık adrese çözülen https adresleri kabul edilir. İmza sırrı yalnız oluşturma yanıtında bir kez gösterilir.
Olaylar: sms.queued, sms.sent, sms.delivered, sms.failed, sms.expired, email.queued, email.delivered, email.failed, email.expired, otp.verified, otp.failed. Hepsi için "*" kullanın.
curl https://api.reach2x.com/v1/webhooks \
-H "Authorization: Bearer $REACH2X_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/2x",
"events": ["sms.delivered", "sms.failed", "email.delivered", "email.failed"]
}' {
"webhook": {
"id": "1b2c3d4e-5f60-4a7b-8c9d-0e1f2a3b4c5d",
"url": "https://example.com/hooks/2x",
"status": "active",
"secret_prefix": "whsec_9fK2"
},
"secret": "whsec_… (shown only once)"
} Her isteği doğrulayın
- Başlık
x-imza:t=<unix>,v1=<hex>. HMAC-SHA256(secret, "<t>.<ham gövde>")hesaplayın (küçük harf hex).- v1 ile sabit sürede karşılaştırın; |şimdi − t| > 300 sn ise reddedin.
x-olay-idile tekrarları ayıklayın (aynı olay birden çok gelebilir).
import crypto from 'node:crypto';
// header "x-imza": t=<unix seconds>,v1=<hex>
export function verify(rawBody, header, secret) {
const p = Object.fromEntries(header.split(',').map((x) => x.split('=')));
const expected = crypto
.createHmac('sha256', secret)
.update(`${p.t}.${rawBody}`)
.digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(p.t)) <= 300;
return (
fresh &&
expected.length === p.v1?.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(p.v1))
);
} 10 saniyede 2xx gelmezse yeniden deneme: 1 dk, 5 dk, 30 dk, 2 sa, 6 sa, 24 sa. 20 ardışık hatada uç devre dışı kalır. Olay sırası garanti edilmez; veri.status ve veri.updated_at’e bakın.
Zarf alanları: id, olay (olay tipi), zaman, kiraci (kuruluş), veri (ileti özeti).
Hata kodları
Hatalar RFC 9457 problem+json’dur. code alanı sabittir; title ve detail insan içindir ve değişebilir.
{
"type": "https://reach2x.com/docs/errors#sender_not_allowed",
"title": "Sender not allowed",
"status": 422,
"code": "sender_not_allowed",
"request_id": "req_01JD3Q7Z8K2M"
} | code | HTTP | Anlamı |
|---|---|---|
invalid_request | 400 | Bozuk JSON, bilinmeyen alan ya da yanlış tip. |
idempotency_key_required | 400 | Gönderimde Idempotency-Key yok. |
unauthorized | 401 | Kimlik yok, geçersiz, süresi dolmuş ya da iptal. |
forbidden | 403 | Kapsam, gönderici ya da IP yetkisi yok. |
not_found | 404 | Kuruluşunuzda yok (başka kiracının kimliği de 404). |
idempotency_in_progress | 409 | Aynı anahtarlı istek hâlâ işleniyor. |
not_cancelable | 409 | İleti artık zamanlanmış değil. |
payload_too_large | 413 | Gövde 1 MB’tan büyük. |
idempotency_key_mismatch | 422 | Aynı anahtar farklı gövdeyle kullanıldı. |
validation_failed | 422 | Anlamca geçersiz girdi; errors[] alanları listeler. |
invalid_phone_number | 422 | Alıcı geçerli E.164 değil. |
body_too_long | 422 | Gövde 7 segmentten uzun. |
sender_not_allowed | 422 | Gönderici onaylı değil ya da anahtara izinli değil. |
iys_recipient_type_required | 422 | commercial ama recipient_type yok. |
iys_brand_code_missing | 422 | commercial ama kuruluşun İYS marka kodu yok. |
invalid_send_at | 422 | send_at geçmişte ya da 30 günden ileri. |
sender_domain_not_verified | 422 | from alanı doğrulanmış değil (e-posta). |
commercial_email_not_supported | 422 | commercial e-posta henüz yok. |
quota_exceeded | 429 | Aylık segment kotası doldu (bilgilendirme/OTP kesilmez). |
rate_limited | 429 | Çok fazla istek; Retry-After’a uyun. |
internal_error | 500 | Beklenmeyen hata; request_id ile bildirin. |
service_unavailable | 503 | Geçici; aynı Idempotency-Key ile güvenle tekrar deneyin. |
Teslim hataları (error.code — SMS): undeliverable, unknown_number, rejected_by_carrier, content_rejected, duplicate_message, recipient_no_consent, commercial_not_permitted, recipient_blocked, destination_not_supported, sender_rejected, expired, delivery_failed, delivery_unavailable.
E-posta: recipient_rejected, domain_not_found, message_rejected, delivery_unavailable, expired, delivery_failed.
Okuma ve sayfalama
Listeler en yeniden eskiye döner ve imleç tabanlıdır: limit (1–100, varsayılan 50) + cursor → { data, next_cursor, has_more }. Filtreler: status, category, batch_id, created_after, created_before.