API belgeleri
Herkese açık API /v1 — bir API anahtarıyla kimlik doğrulayın ve gelen kutusu kiralamalarını kendi yazılımınızdan otomatikleştirin
API anahtarınız
Giriş yapmadınız — kendi API anahtarınızı almak için giriş yapın.
Bu anahtarı Authorization: Bearer <key> başlığında veya ?api_key=<key> sorgu parametresinde gönderin. Anahtarın tamamını görmek için göz simgesine tıklayın; değiştirmeniz gerektiğinde Yeni anahtar oluştur düğmesine tıklayın (eski anahtar hemen çalışmaz hale gelir).Genel bakış
Temel URL
https://otpgmail.netKimlik doğrulama
API anahtarınızı her isteğe ekleyin:
Authorization: Bearer og_xxx... başlığında (önerilir) veya ?api_key=og_xxx... sorgu dizesinde.Idempotency-Key (yinelenen siparişleri önler)
Her
POST /v1/orders isteği Idempotency-Key: <sipariş başına yeni UUID> başlığını içermelidir. İstek zaman aşımına uğrarsa veya bağlantı kesilirse isteği aynı anahtarla yeniden gönderin — sunucu yeni bir sipariş oluşturmak yerine orijinal yanıtı döndürür. Her yeni sipariş için yeni bir UUID üretin; bir UUID'yi yalnızca yeniden denerken tekrar kullanın.Aynı anda çok sayıda sipariş: tek çağrıda durum
Onlarca, yüzlerce gelen kutusu mu kiralıyorsunuz? Durumlarını tek tek değil birlikte okuyun:
POST /v1/orders/status çağrı başına en fazla 100 sipariş döndürür (istek sınırınıza tek istek olarak sayılır), GET /v1/orders ise siparişlerinizi listeler — yeniden başlattıktan sonra ?status=waiting_code hâlâ kod bekleyen tüm siparişleri geri verir. Her hata ayrıca yeniden denemeye değip değmeyeceğini de söyler (error.retryable, error.retryAfterSec). Ayrıntılar: Çok sayıda siparişin durumu bölümü.Gelen kutusu türü: Gmail veya iCloud
Varsayılan olarak bir
@gmail.com gelen kutusu alırsınız. @icloud.com gelen kutusu kiralamak için POST /v1/orders gövdesine "domain": "icloud.com" ekleyin. domain belirtilmezse gmail.com anlamına gelir — mevcut entegrasyonlar değişiklik yapmadan çalışmaya devam eder. iCloud yalnızca GET /v1/services yanıtında icloud alanı null olmayan hizmetler için kullanılabilir; iCloud fiyatı Gmail fiyatından farklı olabilir (bkz. icloud.price). Her sipariş yanıtı, siparişin hangi gelen kutusu türünü kullandığını gösteren bir domain alanı içerir. Bazı hizmetler ayrıca @gmx.com gelen kutuları sunar (şu anda yalnızca Pokemon, kod pkm, kaynak 2): "domain": "gmx.com" gönderin — bir hizmetin GET /v1/services yanıtındaki offers[] dizisinde domain = "gmx.com" olan bir kayıt varsa bunu sunar; diğer tüm hizmetler ⇒ DOMAIN_UNAVAILABLE. gmx.com toplu siparişlerde kullanılamaz.Kaynaklar (warehouse): tek hizmet, birden fazla gelen kutusu kaynağı
Bir hizmet, her biri kendi fiyatına, stokuna ve kod kurallarına sahip birden fazla kaynaktan (warehouse) satılabilir (
GET /v1/services içindeki offers[] dizisi). Birini seçmek için sipariş oluştururken "warehouse": 2 gönderin; "warehouse": 99 ⇒ sistem stokta olan en ucuz kaynağı seçer, tükenirse bir sonrakine geçer (Facebook ve Instagram gibi sık tükenen hizmetler için idealdir); 0 ⇒ stokta olan en ucuz kaynak. Mevcut istemcilerde değişiklik gerekmez: warehouse belirtilmezse ⇒ eskisi gibi kaynak 1 kullanılır ve price, stock ile icloud kaynak 1'i tanımlar (kaynak 1'i olmayan hizmetlerde ⇒ stokta olan en ucuz kaynak). Ayrıntılar için bkz. Kaynaklar.Toplu kiralama (toplu siparişler)
Toplu siparişler web'de (Toplu kiralama sayfası) satın alınır; API ile toplu siparişleri listeleyip kodları okuyabilirsiniz. Gmail (Kaynak 1): her gelen kutusunun, API anahtarı gerektirmeyen bir kod bağlantısı olan
proxyUrl alanı vardır. iCloud (Kaynak 3): özel gelen kutuları; kodları GET /v1/batches/{id}/mails/{mailId}/codes ile okuyun veya web'de readUrl adresini açın. Ayrıntılar: Toplu kiralama bölümü.Kısa ömürlü Gmail hesabı satın alma (mail shop)
Gelen kutusu kiralamanın yanı sıra 2 mail kaynağından Gmail hesaplarını bütünüyle satın alabilirsiniz — kaynak 1: e-posta, şifre, çerezler + gelen kutusu bağlantısı (JSON olarak da); kaynak 2: e-posta, şifre + hızlı giriş bağlantısı; kaynak 99 önce en ucuzunu seçer (web'deki Kısa ömürlü Gmail satın al sayfası). API, o sayfanın yaptığı her şeyi yapar: kaynakları, fiyatları ve stoku görme, satın alma (
Idempotency-Key zorunlu), teslimatı izleme, hesapları indirme ve e-postalarını okuma. Ayrıntılar: Kısa ömürlü Gmail satın alma bölümü.Müşterileriniz kodları kendileri görsün (/otp sayfası)
Kiraladığınız gelen kutularını (web'de ya da API ile) yeniden mi satıyorsunuz? Hesabım sayfasında bir paylaşım kodu açın, sonra müşterinize
https://otpgmail.net/tr/otp#k7m2q9:[email protected] bağlantısını gönderin (k7m2q9 = paylaşım kodunuz) — o e-postanın en son kodlarını giriş yapmadan görürler, fiyatları veya bakiyenizi asla görmezler; sayfa yalnızca ücretsiz işlemler yapar (sizden asla ücret almaz).Araçlar / botlar için JSON bağlantısı (sizin ya da müşterinizin): yol biçimindeki
https://otpgmail.net/tr/otp/k7m2q9:[email protected] bağlantısını alın (# bağlantısı gibi /otp sayfasını açar) ve sonuna ?json ekleyin ⇒ sunucu, sayfanın gösterdiği verinin aynısını JSON olarak döndürür: cards[] — o e-postada kiralanan her hizmet için bir kart (email, serviceName, state, items[] = en yeniden başlayarak en fazla 5 kod / bağlantı) — ve serverTime. state: waiting ilk kod bekleniyor · listening yeni kod bekleniyor · received kod geldi · needs_owner satıcının uzatması gerekir · expired süresi doldu · banned posta kilitlendi. Birden fazla e-posta: virgülle ayırın (en fazla 50). API anahtarı ve çerez gerekmez, CORS açık; yalnızca okuma (“Yeni OTP yükle” / “Bu e-postayı yeniden kirala” /otp sayfasında kalır). Sayfayla aynı tahmin önleme sınırları: yanlış kod / e-postada gösterilecek sipariş yok ⇒ 404 NOT_FOUND; tekrarlanan hatalar veya bir e-posta için dakikada 30'dan fazla okuma ⇒ 429 RATE_LIMITED ve retryAfter (saniye). /otp#… bağlantısına ?json eklemek JSON döndürmez: tarayıcılar # işaretinden sonrasını sunucuya hiç göndermez.curl "https://otpgmail.net/tr/otp/k7m2q9:[email protected]?json"{
"success": true,
"data": {
"cards": [
{
"ref": "Q3vX9kL2mP0aB7cD",
"serviceCode": "fb",
"serviceName": "Facebook",
"logo": "/logos/fb.png?v=20261007",
"domain": "gmail.com",
"email": "[email protected]",
"state": "received",
"until": null,
"items": [
{
"kind": "code",
"value": "529170",
"label": null,
"at": 1760000405
},
{
"kind": "code",
"value": "381904",
"label": null,
"at": 1759999030
}
],
"total": 2,
"canLoad": true
}
],
"serverTime": 1760000530
}
}GitHub'da eksiksiz örnek kod
Python, Node.js, PHP, C# (.NET) ve curl için çalıştırmaya hazır istemciler — gelen kutusu kiralayın, kodu bekleyin, iade için otomatik iptal edin ve stok tükendiğinde iCloud ile Gmail arasında geçiş yapın: github.com/letoan0902/otpgmail-email-otp-api (İngilizce) · thue-otp-gmail (Vietnamca). Python notu: yalın
urllib yerine requests kullanın (varsayılan User-Agent'ı CDN'den 403 alır).Webhook'lar
Her siparişi sürekli sorgulamak yerine bir URL kaydedin; bir sipariş yeni kod aldığında veya iptal edilip iade edildiğinde imzalı bir POST alırsınız — bkz. Webhook'lar.
Uç noktalar
GET/v1/balance
İstekte kullanılan API anahtarına ait hesap bakiyesini (VND cinsinden) döndürür.
Örnekcurl
Python
Node.js
curl "https://otpgmail.net/v1/balance" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"balance": 25000
}
}Olası hatalar: UNAUTHORIZEDGET/v1/services
Etkin hizmetleri listeler — kod, ad, Gmail fiyatı (VND cinsinden) ve güncel Gmail stoku, @icloud.com gelen kutularının fiyatını ve stokunu içeren bir icloud bloğu ve bir offers[] dizisi: hizmeti satan her kaynak için, kaynak × gelen kutusu türü başına bir kayıt (fiyat, stok, kod sayısı, kurallar). Veriler önbelleğe alınır: stok yaklaşık 30–60 saniyede bir, fiyatlar daha seyrek yenilenir.
icloud = null, hizmetin henüz iCloud'u desteklemediği anlamına gelir (sağlayıcı sunmuyor veya geçici olarak devre dışı) — yalnızca Gmail kiralanabilir. icloud bloğu olan hizmetlerde, icloud.price fiyatıyla bir @icloud.com gelen kutusu almak için sipariş oluştururken "domain": "icloud.com" gönderin. price / stock / icloud.price, kaynak 1'i tanımlar — warehouse belirtilmeyen siparişler oraya gider (kaynak 1'i olmayan hizmetlerde ⇒ stokta olan en ucuz kaynak); kaynak bazında fiyat ve stok offers[] içindedir (bkz. Kaynaklar). stock, sağlayıcının yayımladığı sayıdır (kaynak 1: yaklaşık her 30 saniyede bir yenilenir) ve tek bir çağrının o kadarını kiralayabileceğini garanti etmez: gelen kutuları tek tek atanır ve sağlayıcı yarıda tükenebilir — bu durumda POST /v1/orders daha az sipariş ve bir partial alanı döndürür. Kaynak 2 ve 4 de kendi sağlayıcılarının sayılarını gösterir.
Örnekcurl
Python
Node.js
curl "https://otpgmail.net/v1/services" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": [
{
"code": "dr",
"name": "OpenAI (ChatGPT)",
"price": 350,
"stock": 616525,
"icloud": {
"price": 630,
"stock": 12464
},
"offers": [
{
"warehouse": 2,
"domain": "gmail.com",
"price": 350,
"stock": 616525,
"maxCodes": null,
"rules": null,
"fee": {
"freeHours": 6,
"paidPct": 50,
"maxHours": 24
},
"isDefault": true
},
{
"warehouse": 1,
"domain": "gmail.com",
"price": 630,
"stock": 12464,
"maxCodes": 3,
"rules": null,
"fee": null,
"isDefault": false
},
{
"warehouse": 1,
"domain": "icloud.com",
"price": 630,
"stock": 12464,
"maxCodes": 5,
"rules": null,
"fee": null,
"isDefault": true
}
],
"note": null
},
{
"code": "fb",
"name": "Facebook",
"price": 1590,
"stock": 88,
"icloud": null,
"offers": [
{
"warehouse": 1,
"domain": "gmail.com",
"price": 1590,
"stock": 88,
"maxCodes": 10,
"rules": null,
"fee": null,
"isDefault": false
},
{
"warehouse": 4,
"domain": "gmail.com",
"price": 1580,
"stock": 2310,
"maxCodes": null,
"rules": null,
"fee": null,
"isDefault": true
}
],
"note": null
}
]
}Olası hatalar: UNAUTHORIZEDPOST/v1/orders
Doğrulama kodlarını alan bir gelen kutusu için sipariş oluşturur — varsayılan olarak Gmail, domain: "icloud.com" gönderirseniz iCloud. Sağlayıcı gelen kutusunu atar atamaz bakiyenizden ücret düşülür. Bir sipariş listesi döndürür (bir tane veya quantity > 1 ise birkaç tane).
Eksik teslimat: quantity bir üst sınırdır
- Gelen kutuları tek tek atanır. Sağlayıcı yarıda tükenirse (örneğin kaynak 1'de o an o hizmet için gelen kutusu kalmadıysa) çağrı durur ve o ana kadar oluşturulan siparişlerle birlikte HTTP 200 döndürür —
data, quantity değerinden kısa olabilir ve yalnızcadataiçindeki siparişler için ücret alınır.GET /v1/servicesiçindekistock, tek bir çağrının kaç tane alacağını garanti etmez. - Bu durumda yanıtta
dataalanının yanında üst düzey birpartialalanı da bulunur (her şey teslim edildiyse yoktur; yalnızcadataokuyan botlar değişiklik gerektirmez):requested,delivered,missingvereason={code, message, retryable, retryAfterSec};code, çağrıyı durduran hatadır (NO_MAILS_AVAILABLE,OUT_OF_STOCK,ALL_WAREHOUSES_EXHAUSTED,INSUFFICIENT_BALANCE,WAITING_LIMIT_REACHED…). - Tükenme genellikle geçicidir — kaynak 1'de sağlayıcının birkaç saniye sonra çoğu zaman yine gelen kutusu olur.
reason.retryable= true isereason.retryAfterSecsaniye (3–5 sn) bekleyin, ardındanmissingkadar gelen kutusunu YENİ birIdempotency-Keyile tekrar isteyin (eski anahtar yalnızca bu yanıtı aynen yeniden döndürür); hepsini alana kadar yineleyin. - Eksik teslimattan hemen sonraki çağrı 409
WAREHOUSE_UNAVAILABLE/OUT_OF_STOCKveya 503NO_MAILS_AVAILABLEdöndürebilir — bu normaldir: çağrılar arasında 3–5 sn beklemeye devam edin ve ancak art arda çok sayıda çağrı başarısız olursa (örneğin 10 deneme, yaklaşık bir dakika) vazgeçin; ardından daha sonra yeniden deneyin ya da sistemin başka kaynaklara geçmesi için"warehouse": 99gönderin.retryable= false (INSUFFICIENT_BALANCE,WAITING_LIMIT_REACHED…) ⇒ önce nedeni giderin (bakiye yükleyin veya açık siparişlerin bitmesini bekleyin). - Hata yanıtları da aynı iki alanı
erroriçinde taşır:error.retryableveerror.retryAfterSec(ör. 409OUT_OF_STOCK⇒true, 5; 402INSUFFICIENT_BALANCE⇒false,null) — Hata kodları bölümüne bakın.
Idempotency-Key başlığı (bir UUID) zorunludur. Her yeni kiralama için yeni bir UUID üretin; zaman aşımından sonra yeniden denerken yinelenen sipariş oluşmaması için AYNI anahtarı kullanın. Bu çağrı, sağlayıcının bir gelen kutusu atamasını bekler; bu yüzden genellikle yaklaşık 0,3 saniye sürer ancak yoğun saatlerde (nadiren) 10 saniyeye kadar çıkabilir — 5 saniye sonra vazgeçip erken yeniden denemek yerine istemci zaman aşımınızı yaklaşık 15 saniyeye ayarlayın.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
service | string | Evet | Hizmet kodu (GET /v1/services yanıtından, örn. "ig", "tg", "fb") |
quantity | number | Hayır | Kiralanacak AZAMİ gelen kutusu sayısı (varsayılan 1; istek başına en fazla 200) — kaynak yarıda tükenirse daha azını alırsınız: data[] öğelerini sayın ve partial alanını okuyun |
domain | string | Hayır | Gelen kutusu türü: "gmail.com" (varsayılan), "icloud.com" veya "gmx.com". Belirtilmezse = gmail.com — mevcut entegrasyonlarda değişiklik gerekmez. iCloud yalnızca GET /v1/services yanıtında icloud alanı null olmayan hizmetler için kiralanabilir; "gmx.com" yalnızca offers[].domain = "gmx.com" olan hizmetler için (şu anda yalnızca Pokemon, kod pkm) — aksi halde çağrı DOMAIN_UNAVAILABLE ile başarısız olur. Başka herhangi bir değer ⇒ VALIDATION_ERROR. |
warehouse | number | Hayır | Kiralanacak kaynak. Belirtilmezse = KAYNAK 1, çoklu kaynak desteğinden önceki davranışın aynısı (kaynak 1'i olmayan hizmetler en ucuz kaynağa düşer) — mevcut istemcilerde değişiklik gerekmez. 0 = stokta olan en ucuz kaynak (yalnızca bir kaynak denenir). 1–4 = tam olarak o kaynak (GET /v1/services içindeki offers[].warehouse değeri); bu hizmeti/gelen kutusu türünü satmıyorsa, duraklatılmışsa veya stoğu tükenmişse ⇒ WAREHOUSE_UNAVAILABLE. 99 = OTOMATİK: stokta olan kaynaklar en ucuzdan en pahalıya doğru denenir, biri tükenirse veya hata verirse sonrakine geçilir; hiçbiri kalmazsa ⇒ ALL_WAREHOUSES_EXHAUSTED — sık tükenen hizmetler (Facebook, Instagram…) için önerilir. Bkz. Kaynaklar. |
curl
Python
Node.js
# Her YENİ sipariş için rastgele bir Idempotency-Key üretin
# Zaman aşımından sonra yeniden denerken AYNI anahtarı tekrar kullanın (yinelenen siparişleri önler)
# domain: "gmail.com" (varsayılan, isteğe bağlı) | "icloud.com" (@icloud.com gelen kutusu kirala) | "gmx.com" (yalnızca sunan hizmetler, örn. Pokemon)
# warehouse: 0 | 1–4 | 99 (isteğe bağlı — eskisi gibi kaynak 1 için belirtmeyin; 0 = stokta olan en ucuz kaynak; 99 = otomatik, bir kaynak tükenince sonrakine geçer; bkz. GET /v1/services içindeki offers[])
curl -X POST "https://otpgmail.net/v1/orders" \
-H "Authorization: Bearer og_xxx..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"service":"ig","quantity":1,"domain":"gmail.com"}'{
"success": true,
"data": [
{
"orderId": "abc123xyz",
"service": "ig",
"domain": "gmail.com",
"email": "[email protected]",
"status": "waiting_code",
"price": 1060,
"otp": [],
"codeDeadlineAt": 1753270000,
"rentExpiresAt": 1753356400,
"createdAt": 1753268200,
"warehouse": 1,
"nextCodeFee": null,
"listening": false,
"listenUntil": null,
"nextCodeBlocked": false,
"nextCodeBlockReason": null
}
]
}Örnek yanıt — eksik teslimat (quantity 5, 2 gelen kutusu teslim edildi)
Olası hatalar: {
"success": true,
"data": [
{
"orderId": "abc123xyz",
"service": "ig",
"domain": "gmail.com",
"email": "[email protected]",
"status": "waiting_code",
"price": 1060,
"otp": [],
"codeDeadlineAt": 1753270000,
"rentExpiresAt": 1753356400,
"createdAt": 1753268200,
"warehouse": 1,
"nextCodeFee": null,
"listening": false,
"listenUntil": null,
"nextCodeBlocked": false,
"nextCodeBlockReason": null
},
{
"orderId": "jkl012mno",
"service": "ig",
"domain": "gmail.com",
"email": "[email protected]",
"status": "waiting_code",
"price": 1060,
"otp": [],
"codeDeadlineAt": 1753270001,
"rentExpiresAt": 1753356401,
"createdAt": 1753268201,
"warehouse": 1,
"nextCodeFee": null,
"listening": false,
"listenUntil": null,
"nextCodeBlocked": false,
"nextCodeBlockReason": null
}
],
"partial": {
"requested": 5,
"delivered": 2,
"missing": 3,
"reason": {
"code": "NO_MAILS_AVAILABLE",
"message": "No inboxes available for this service right now, please try again later",
"retryable": true,
"retryAfterSec": 5
}
}
}UNAUTHORIZED, VALIDATION_ERROR, SERVICE_DISABLED, INSUFFICIENT_BALANCE, OUT_OF_STOCK, DOMAIN_UNAVAILABLE, WAREHOUSE_UNAVAILABLE, ALL_WAREHOUSES_EXHAUSTED, NO_MAILS_AVAILABLE, QUANTITY_EXCEEDED, WAITING_LIMIT_REACHED, RATE_LIMITED, DUPLICATE_REQUEST, PROVIDER_ERROR, MAINTENANCEGET/v1/orders/{id}
Bir siparişi kimliğine göre döndürür; şimdiye kadar alınan kodlar (otp[]) dahildir. Sipariş waiting_code durumundayken kodu yakalamak için bu uç noktayı her 3–5 saniyede bir sorgulayın.
otp[] dizisi geliş sırasına göre sıralanır: en eski ilk, EN YENİ SON — son kodu otp[otp.length - 1] ile okuyun. Her çağrıda sistem, hâlâ açık olan siparişler için sağlayıcıyı her kaynağın kendi temposunda (birkaç saniyede bir) kontrol eder — daha sık çağırmak yalnızca kayıtlı verileri döndürür. İlk koddan sonra sorgulamaya devam edin: sonraki kodlar (hizmet birden fazla gönderiyorsa) sipariş süresi içinde ek ücret olmadan otp[] dizisinin sonuna eklenir — sınır ve süre kiralamadan önce gösterilir (offers[] içindeki maxCodes ve fee); sistemin yeni bir kod beklediğinden emin olmak için POST /v1/orders/{id}/next-code çağırın (her kaynakta; yalnızca ücretsiz penceresi dışındaki kaynak 2 ücret alır). Hizmet gelen kutusu başına yalnızca bir koda izin veriyorsa otp[] o kodda durur — yanıtlar normal kalır, hata olmaz. warehouse alanı gelen kutusunu hangi kaynağın verdiğini bildirir (1–4); nextCodeFee ek kodların ücretidir (kaynak 2 ve 3 siparişleri; kaynak 1 ve 4 için null) — bkz. Kaynaklar. 2026-10-02 tarihinden itibaren siparişler ayrıca nextCodeBlocked (true = gelen kutusu artık kod alamaz) ve nextCodeBlockReason alanlarını taşır — nedeni: "email_banned" (e-posta hizmet tarafından kilitlendi — yenisini kiralayın), "activation_gone" (sağlayıcı gelen kutusunu kapattı), "hard_expired" (kod süresi sona erdi), "max_codes" (izin verilen en fazla kod sayısına ulaşıldı), null (engellenmedi / nedeni kaydedilmemiş eski sipariş). Bunlar eklenen alanlardır — mevcut istemcilerde değişiklik gerekmez. Çok sayıda siparişi mi sorguluyorsunuz? Her sipariş için ayrı bir GET yerine çağrı başına en fazla 100 kimliği POST /v1/orders/status adresine gönderin — aynı sipariş nesneleri, istek sınırına yalnızca tek istek.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | Sipariş kimliği (sipariş oluşturulurken dönen orderId) |
curl
Python
Node.js
curl "https://otpgmail.net/v1/orders/ORDER_ID" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"orderId": "abc123xyz",
"service": "ig",
"domain": "gmail.com",
"email": "[email protected]",
"status": "completed",
"price": 1060,
"otp": [
{
"code": "123456",
"receivedAt": 1753268500
},
{
"code": "789012",
"receivedAt": 1753269000
}
],
"codeDeadlineAt": 1753270000,
"rentExpiresAt": 1753356400,
"createdAt": 1753268200,
"warehouse": 1,
"nextCodeFee": null,
"listening": true,
"listenUntil": 1753270500,
"nextCodeBlocked": false,
"nextCodeBlockReason": null
}
}Olası hatalar: UNAUTHORIZED, NOT_FOUNDPOST/v1/orders/{id}/cancel
Siparişi iptal eder ve fiyatın %100'ünü iade eder. Yalnızca sipariş waiting_code durumundayken VE hiç kod alınmamışken izin verilir.
Kod almış bir sipariş (tek bir kod bile olsa) iptal edilemez veya iade edilemez — bu hem web sitesi hem de API için geçerlidir. rules.cancellable = false olan siparişler (Cointiply gibi kendi stokundan hizmetler) iptal edilemez: gelen kutusu atandıktan sonra iptal ve iade yoktur — iptal çağrısı ORDER_NOT_CANCELLABLE döndürür. Normal hizmetlerin kaynak 3 siparişleri (rules.cancellable = true), kod gelmeden önce diğer siparişler gibi iptal edilebilir.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | İptal edilecek siparişin kimliği |
curl
Python
Node.js
curl -X POST "https://otpgmail.net/v1/orders/ORDER_ID/cancel" \
-H "Authorization: Bearer og_xxx..." \
-H "Content-Type: application/json"{
"success": true,
"data": {
"orderId": "abc123xyz",
"service": "ig",
"domain": "gmail.com",
"email": "[email protected]",
"status": "cancelled",
"price": 1060,
"otp": [],
"codeDeadlineAt": 1753270000,
"rentExpiresAt": 1753356400,
"createdAt": 1753268200,
"warehouse": 1,
"nextCodeFee": null,
"listening": false,
"listenUntil": null,
"nextCodeBlocked": false,
"nextCodeBlockReason": null
}
}Olası hatalar: UNAUTHORIZED, NOT_FOUND, ORDER_NOT_CANCELLABLE, PROVIDER_ERRORPOST/v1/orders/{id}/rerent
Kendi stokundan bir hizmetin (provider = "inventory", örn. Cointiply) siparişi için AYNI gelen kutusunu yeniden kiralar: o gelen kutusunda yeni bir alma süresiyle YENİ bir sipariş oluşturur; fiyat eski siparişin rerentPriceVnd değeridir.
Yalnızca eski siparişin canRerent = true olduğu durumda çalışır (o gelen kutusunun en son siparişi; önceki süresi bitmiş veya tüm e-postaları almış). Başarılı olur olmaz ücret alınır — Idempotency-Key gönderin ve yeniden denerken aynısını kullanın; böylece iki kez ücret alınmaz. Yanıt { order, message } biçimindedir; order, GET /v1/orders/{id} ile aynı yapıdadır. Kaynak 2 (2026-10-09'dan itibaren): iptal edilmiş, süresi dolmuş veya bitmiş (gelen kutusu kapalı) bir sipariş —
ParametrelercanRerent = true olduğunda çağırın (o e-postanın en son siparişi ve e-postada başka etkin sipariş yok). Sistem AYNI e-postayı YENİ bir sipariş olarak (status = waiting_code) rerentPriceVnd fiyatıyla (şu anda fiyatınızın %100'ü) yeniden açar ve her Kaynak 2 siparişi gibi bir e-posta için 20 dakika bekler — e-posta gelmezse iptal edilir ve %100 iade edilir. E-posta hizmet tarafından kilitlendiyse ⇒ RERENT_EMAIL_BANNED; sağlayıcı artık yeniden açamıyorsa ⇒ RERENT_MAIL_GONE; Kaynak 2 geçici olarak kesintideyse ⇒ PROVIDER_ERROR — üçünde de ücret alınmaz.| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | Gelen kutusunun önceki siparişinin kimliği (canRerent = true olan) |
curl
Python
Node.js
# Zaman aşımından sonra yeniden denerken AYNI anahtarı tekrar kullanın (yinelenen siparişleri önler)
curl -X POST "https://otpgmail.net/v1/orders/ORDER_ID/rerent" \
-H "Authorization: Bearer og_xxx..." \
-H "Idempotency-Key: $(uuidgen)"{
"success": true,
"data": {
"order": {
"orderId": "def456uvw",
"service": "ctp",
"domain": "icloud.com",
"email": "[email protected]",
"status": "waiting_code",
"price": 3500,
"otp": [],
"codeDeadlineAt": 1753273500,
"rentExpiresAt": 1753273500,
"createdAt": 1753269000,
"provider": "inventory",
"rules": {
"windowMinutes": 75,
"maxCodes": 4,
"cancellable": false,
"refundOnTimeout": false,
"rerentRatio": 0.5
},
"windowEndsAt": 1753273500,
"canRerent": false,
"rerentPriceVnd": 3500,
"warehouse": 3,
"nextCodeFee": null,
"listening": false,
"listenUntil": null,
"nextCodeBlocked": false,
"nextCodeBlockReason": null
},
"message": "Inbox rented again — a new 75-minute message window has started"
}
}Olası hatalar: UNAUTHORIZED, NOT_FOUND, RERENT_NOT_AVAILABLE, RERENT_EMAIL_BANNED, RERENT_MAIL_GONE, INSUFFICIENT_BALANCE, WAITING_LIMIT_REACHED, RATE_LIMITED, DUPLICATE_REQUEST, PROVIDER_ERROR, MAINTENANCEPOST/v1/orders/{id}/next-code
AYNI gelen kutusunda bir sonraki kodu ister — ilk kodunu almış (status = completed) HER kaynaktaki (warehouse 1–4) siparişler için çalışır. Ücretsizdir; tek istisna, ücretsiz penceresi kapanmış kaynak 2 siparişleridir (nextCodeFee.feePriceVnd > 0): bu durumda ücreti ödemek ve bir kod penceresi daha açmak için confirmFee: true gönderin (nextCodeFee.hardUntil kesin sınırına kadar). Botunuzun kaynağı bilmesi gerekmez: GET /v1/orders/{id} adresini sorgulamaya devam edin — yeni kodlar otp[] dizisinin sonuna eklenir — ve sistemin yeni bir kod beklemesini istediğinizde bu uç noktayı çağırın.
Bu çağrı her kaynakta ne yapar
- Kaynak 1: sistem, sipariş süresi içinde (
rentExpiresAt) her koddan sonra bir sonrakini kendiliğinden bekler — çağrı 200 döner ve hiçbir şeyi değiştirmez; gelen kutusu artık kod alamıyorsa (kod sınırına ulaşıldı, gelen kutusu kapandı, süre doldu) ⇒nextCodeBlockReasonile birlikte 409. - Kaynak 2: gelen kutusunu sağlayıcıda yeniden açar (
reordered= true) ve bir e-posta için 20 dakika bekler; ücretsiz pencere içinde ücretsizdir (nextCodeFee.feePriceVnd= 0), pencere dışındaconfirmFee= true göndermeniz gerekir (eksikse ⇒ 409NEXT_CODE_FEE_CONFIRM, ücret alınmaz). Ücret yalnızca yeni bir kod gelirse alınmış kalır — 20 dakika içinde kod gelmezse ⇒ otomatik iade. Her koddan sonra sistem bir sonrakini 25 dakika daha kendiliğinden bekler (listening= true,listenUntil). - Kaynak 3 (normal hizmetler): kısa bir dinleme süresini yeniden açar, ücretsiz pencere içinde ücretsizdir (
nextCodeFee.freeUntil); pencere bitince ⇒ 409 —POST /v1/orders/{id}/rerentkullanın. Cointiply gibi özel envanter hizmetlerinde (rules.cancellable= false) bu çağrı yoktur (409): pencere boyunca her e-posta kendiliğinden görünür. - Kaynak 4: siparişi sağlayıcıda yeniden okur ve yeni bir kod bekler,
rentExpiresAtzamanına kadar ücretsizdir.
200 = sistem bu sipariş için yeni bir kod bekliyor (listening = true, listenUntil = beklemenin biteceği an; gelen kutusu az önce yeniden açıldıysa reordered = true; ücret alındıysa chargedVnd) ya da çağırdığınız anda yeni bir kod geldi (order.otp içinde zaten var). 409 = yeni bir bekleme açılamadı — error.code değerini okuyun; gelen kutusunun neden başka kod alamadığı order.nextCodeBlockReason içindedir (GET /v1/orders/{id}). Henüz ilk kodunu bekleyen sipariş (waiting_code) ⇒ 409, şimdilik çağırmanıza gerek yok. Ücretli çağrılarla bir Idempotency-Key gönderin (yeniden denerken aynısını kullanın; böylece iki kez ücret alınmaz). Sağlayıcıya ulaşılamazsa ⇒ 502 PROVIDER_ERROR, daha sonra tekrar deneyin. Bu çağrının 409 hata kodları: NEXT_CODE_FEE_CONFIRM (kaynak 2 ücret istiyor — confirmFee: true ile yeniden çağırın), EMAIL_BANNED (e-posta hizmet tarafından kilitlendi — yenisini kiralayın; error.details.blockReason = "email_banned"), ORDER_EXPIRED (süre doldu, gelen kutusu kapandı, kod sınırına ulaşıldı ya da hizmette "sonraki kod" yok — neden order.nextCodeBlockReason içinde), ORDER_NOT_CANCELLABLE (sipariş henüz ilk kodunu almadı). Bu çağrıdaki her 409'u "başka kod yok" sayan botlar değişiklik yapmadan çalışmaya devam eder. refresh: true (kaynak 2): önce yeni e-posta kontrol edilir (az önce gelen teslim edilir, yeniden açılmaz), sonra gelen kutusu sağlayıcıda yeniden açılır — ücretsiz pencere içinde bekleme 20 dakika yeniden başlar; pencere dışında bekleme bitiş zamanı (listenUntil) aynı kalır ve ücret alınmaz. Yanıta refreshed (true = şimdi yeniden açıldı) ve refreshAvailableAt (unix saniye; bu andan önce yenileme yalnızca e-posta kontrol eder; null = hemen yapılabilir) eklenir. Diğer kaynaklar: etkisi yok (refreshed = false). refresh gönderilmezse çağrı tam olarak eskisi gibi çalışır.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | Sipariş kimliği (orderId) — herhangi bir kaynak |
confirmFee | boolean | Hayır | true = başka bir kod penceresi açmak için nextCodeFee.feePriceVnd tutarını ödemeyi kabul edersiniz. feePriceVnd = 0 iken gerekmez. |
refresh | boolean | Hayır | true = kaynak 2, sipariş yeni kod bekliyor (listening = true) ama kod gelmiyor: gelen kutusunu sağlayıcıda hemen yeniden aç (beklemeyi yenile) — eski bekleme sağlayıcı tarafında e-posta almayı bırakmış olabilir. Ücretsiz; sipariş başına en fazla 5 sn'de bir. Sipariş beklemiyorsa ⇒ normal çağrıyla aynı. |
curl
Python
Node.js
# Ücretsiz (nextCodeFee null veya feePriceVnd = 0 — ücretsiz penceresi bitmiş kaynak 2 hariç her kaynak): confirmFee gerekmez
curl -X POST "https://otpgmail.net/v1/orders/ORDER_ID/next-code" \
-H "Authorization: Bearer og_xxx..."
# Ücretsiz penceresi bitmiş kaynak 2: nextCodeFee.feePriceVnd tutarını ödemek için confirmFee = true gönderin
curl -X POST "https://otpgmail.net/v1/orders/ORDER_ID/next-code" \
-H "Authorization: Bearer og_xxx..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"confirmFee":true}'{
"success": true,
"data": {
"order": {
"orderId": "ghi789rst",
"service": "dr",
"domain": "gmail.com",
"email": "[email protected]",
"status": "completed",
"price": 350,
"otp": [
{
"code": "482913",
"receivedAt": 1753268300
}
],
"codeDeadlineAt": 1753269700,
"rentExpiresAt": 1753354200,
"createdAt": 1753267800,
"warehouse": 2,
"nextCodeFee": {
"feePriceVnd": 0,
"freeUntil": 1753311000,
"hardUntil": 1753354200,
"paidPct": 50,
"freeHours": 6
},
"listening": true,
"listenUntil": 1753269500,
"nextCodeBlocked": false,
"nextCodeBlockReason": null
},
"message": "Another code window is open — waiting for a new code",
"listening": true,
"listenUntil": 1753269500,
"reordered": true
}
}Olası hatalar: UNAUTHORIZED, NOT_FOUND, VALIDATION_ERROR, NEXT_CODE_FEE_CONFIRM, INSUFFICIENT_BALANCE, EMAIL_BANNED, ORDER_EXPIRED, ORDER_NOT_CANCELLABLE, PROVIDER_ERROR, DUPLICATE_REQUEST, MAINTENANCEÇok sayıda siparişin durumu: tek çağrıda
Çok sayıda gelen kutusu kiralayan bayiler ve botlar her sipariş için ayrı bir
GET /v1/orders/{id} göndermemeli: POST /v1/orders/status aynı sipariş nesneleriyle çağrı başına en fazla 100 sipariş okur, GET /v1/orders ise siparişlerinizi kayıtlı verilerden listeler.POST /v1/orders/statusile her 3–5 saniyede bir sorgulayın, çağrı başına en fazla 100 sipariş kimliği — her çağrı istek sınırınıza tek istek olarak sayılır.- Her çağrıda sistem, listedeki açık siparişlerden en fazla 20 tanesi için sağlayıcıyı kontrol eder (önce ilk kodunu bekleyenler, sonra en uzun süredir kontrol edilmeyenler) ve kalanları kayıtlı verilerden döndürür; onlar sonraki çağrılarda kontrol edilir. Bir çağrı yaklaşık 3 saniye içinde yanıt verir.
- Sonuçlanan siparişi listenizden çıkarın: cancelled (iade edildi) ya da artık kod gerekmiyorsa completed.
- Var olmayan ya da başka bir hesaba ait kimlikler
missingiçinde döner (404 yok) — onları da çıkarın. - Yeniden başlattıktan sonra açık tüm siparişleri
GET /v1/orders?status=waiting_codeile geri alın (nextCursor'ı izleyin), ardındanPOST /v1/orders/statusile sorgulamaya devam edin.
POST/v1/orders/status
Tek çağrıda siparişlerinizden en fazla 100 tanesini döndürür. Her öğe, o sipariş için GET /v1/orders/{id} ne döndürüyorsa tam olarak odur (status, alınan tüm kodlarla otp[], warehouse…). Açık siparişlerin çoğunu aynı anda sorgulamak için kullanın.
data, ids sırasını korur; yinelenen kimlikler yok sayılır. Var olmayan ya da başka bir hesaba ait kimlikler missing içinde listelenir (404 yok). Açık siparişler için sistem, sağlayıcıyı GET /v1/orders/{id} gibi kontrol eder, ancak çağrı başına en fazla 20 sipariş için — önce ilk kodunu bekleyenler, sonra en uzun süredir kontrol edilmeyenler — diğerlerini kayıtlı verilerden döndürür (sonraki çağrılarda kontrol edilirler); bir çağrı yaklaşık 3 saniye içinde yanıt verir. Kaç kimlik içerirse içersin bir çağrı, istek sınırına tek istek olarak sayılır. 100'den fazla kimlik, boş liste veya metin olmayan kimlikler ⇒ 400 VALIDATION_ERROR.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
ids | string[] | Evet | Sipariş kimlikleri (orderId) — çağrı başına 1 ile 100 arası |
curl
Python
Node.js
# Beklediğiniz siparişlerin kimlikleri (POST /v1/orders'tan gelen orderId) — çağrı başına en fazla 100
curl -X POST "https://otpgmail.net/v1/orders/status" \
-H "Authorization: Bearer og_xxx..." \
-H "Content-Type: application/json" \
-d '{"ids":["ORDER_ID_1","ORDER_ID_2"]}'{
"success": true,
"data": [
{
"orderId": "abc123xyz",
"service": "ig",
"domain": "gmail.com",
"email": "[email protected]",
"status": "completed",
"price": 1060,
"otp": [
{
"code": "123456",
"receivedAt": 1753268500
}
],
"codeDeadlineAt": 1753270000,
"rentExpiresAt": 1753356400,
"createdAt": 1753268200,
"warehouse": 1,
"nextCodeFee": null,
"listening": false,
"listenUntil": null,
"nextCodeBlocked": false,
"nextCodeBlockReason": null
},
{
"orderId": "jkl012mno",
"service": "ig",
"domain": "gmail.com",
"email": "[email protected]",
"status": "waiting_code",
"price": 1060,
"otp": [],
"codeDeadlineAt": 1753270001,
"rentExpiresAt": 1753356401,
"createdAt": 1753268201,
"warehouse": 1,
"nextCodeFee": null,
"listening": false,
"listenUntil": null,
"nextCodeBlocked": false,
"nextCodeBlockReason": null
}
],
"missing": [
"zzz999qqq"
]
}Olası hatalar: UNAUTHORIZED, VALIDATION_ERROR, RATE_LIMITEDGET/v1/orders
Siparişlerinizi en yeniden eskiye, yalnızca kayıtlı verilerden listeler — yeni kodlar için sağlayıcıya sormaz (bunu POST /v1/orders/status yapar). Duruma ve oluşturulma zamanına göre filtreleyin; nextCursor ile sayfalayın.
Sonraki sayfa için nextCursor değerini cursor olarak gönderin; nextCursor = null ⇒ son sayfa. Aynı saniyede çok sayıda sipariş oluşturulmuş olsa bile sayfalar bir siparişi asla tekrarlamaz ya da atlamaz. İç durumlar hiçbir zaman listelenmez (yalnızca waiting_code, completed, cancelled ve queued). Botunuz yeniden başladıktan sonra: GET /v1/orders?status=waiting_code&limit=200, nextCursor'ı izleyin, ardından bu siparişleri POST /v1/orders/status ile sorgulayın.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
status | string | Hayır | Yalnızca bu durum: waiting_code | completed | cancelled | queued (gönderilmezse ⇒ hepsi) |
since | number | Hayır | Yalnızca bu unix zamanında (saniye) veya sonrasında oluşturulan siparişler |
limit | number | Hayır | Sayfa başına sipariş: 1–200 (varsayılan 50) |
cursor | string | Hayır | Önceki sayfanın nextCursor değeri, değiştirmeden |
curl
Python
Node.js
# Yeniden başlattıktan sonra: hâlâ kod bekleyen tüm siparişleri sayfa sayfa toplayın
curl "https://otpgmail.net/v1/orders?status=waiting_code&limit=200" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": [
{
"orderId": "jkl012mno",
"service": "ig",
"domain": "gmail.com",
"email": "[email protected]",
"status": "waiting_code",
"price": 1060,
"otp": [],
"codeDeadlineAt": 1753270001,
"rentExpiresAt": 1753356401,
"createdAt": 1753268201,
"warehouse": 1,
"nextCodeFee": null,
"listening": false,
"listenUntil": null,
"nextCodeBlocked": false,
"nextCodeBlockReason": null
},
{
"orderId": "abc123xyz",
"service": "ig",
"domain": "gmail.com",
"email": "[email protected]",
"status": "waiting_code",
"price": 1060,
"otp": [],
"codeDeadlineAt": 1753270000,
"rentExpiresAt": 1753356400,
"createdAt": 1753268200,
"warehouse": 1,
"nextCodeFee": null,
"listening": false,
"listenUntil": null,
"nextCodeBlocked": false,
"nextCodeBlockReason": null
}
],
"nextCursor": "1753268200:abc123xyz"
}Olası hatalar: UNAUTHORIZED, VALIDATION_ERROR, RATE_LIMITEDKaynaklar
Her
offers[] kaydı bir tekliftir = (hizmet, kaynak, gelen kutusu türü). Yalnızca şu anda satış yapan kaynaklar listelenir; geçici olarak stoğu tükenen bir kaynak stock = 0 ile listede kalır. Kaynak numaraları sabittir: 1, 2, 3, 4 — sipariş oluştururken aynı numarayı warehouse parametresinde gönderin.Mevcut istemcilerde değişiklik gerekmez.
warehouse belirtilmezse ⇒ eskisiyle aynı davranış (kaynak 1: 25 dakikalık bekleme; hizmet birden fazla kod gönderiyorsa ek kodlar 24 saatlik sipariş süresi içinde otomatik gelir); 0 gönderirseniz ⇒ stokta olan en ucuz kaynak; 99 gönderirseniz ⇒ otomatik kaynak, biri tükenince sonrakine geçer (hemen aşağıya bakın); mevcut her alan olduğu gibi kalır — yalnızca yeni alanlar eklenir (offers[], warehouse, nextCodeFee, listening, nextCodeBlocked…).Otomatik kaynak: warehouse = 99 (sık tükenen hizmetler için önerilir)
offers[] alanları"warehouse": 99 gönderin; sistem stokta olan en ucuz kaynaktan kiralar; o kaynağın stoğu tükenmişse veya hata veriyorsa aynı çağrı içinde bir sonrakine geçer. Facebook ve Instagram gibi sık tükenen hizmetler için idealdir — botunuzun artık offers[] dizisini okuyup kaynak kaynak yeniden denemesi gerekmez.- Deneme sırası: fiyat düşükten yükseğe (örn. 1.500 → 1.600 → 1.700 VND); fiyatlar eşitse ⇒ önce düşük kaynak numarası.
- Stoğu sıfır bildiren kaynaklar (
offers[]içindestock= 0) hiç çağrılmaz — zaman kaybı olmaz. - Mevcut kaynağın stoğu tükenmişse veya hata veriyorsa sonrakine geçer (
OUT_OF_STOCK,NO_MAILS_AVAILABLE,WAREHOUSE_UNAVAILABLE,PROVIDER_ERROR). - Diğer hatalar, sonraki kaynak denenmeden hemen döndürülür:
INSUFFICIENT_BALANCE,WAITING_LIMIT_REACHED,QUANTITY_EXCEEDED,MAINTENANCE,SERVICE_DISABLED,DOMAIN_UNAVAILABLE… quantity> 1: ilk kaynak yetmezse kalanı sonraki kaynaktan gelir — siparişler birkaç kaynağa yayılabilir; her sipariş, onu veren kaynağınwarehousevepricedeğerlerini taşır (ve o kaynağın kod kurallarına tabidir).- Her kaynak denendiği halde hiç gelen kutusu kiralanamadıysa ⇒
ALL_WAREHOUSES_EXHAUSTED(HTTP 409, ücret alınmaz) — daha sonra tekrar deneyin. Yalnızca bazı gelen kutuları kiralandıysa yine de bu siparişlerle 200 alırsınız.
curl
Python
Node.js
# warehouse: 99 — stokta olan en ucuz kaynak; stok yok veya hata varsa ⇒ otomatik olarak sonraki kaynak
curl -X POST "https://otpgmail.net/v1/orders" \
-H "Authorization: Bearer og_xxx..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"service":"fb","quantity":1,"domain":"gmail.com","warehouse":99}'¹ Yalnızca kendi stokundan satılan hizmetler (örn. Cointiply:
nextCodeFee — ek kodların ücreti (kaynak 2 ve 3 siparişleri)provider = "inventory", rules.cancellable = false) rules alanını izler: rules.windowMinutes dakika içinde en fazla rules.maxCodes e-posta, iptal yok ve e-posta gelmeden süre dolarsa iade yok.GET /v1/orders/{id} yanıtına ve her sipariş yanıtına dahildir; kaynak 1 ve 4 siparişlerinde null (ek kodlar ücretsizdir). Kaynak 2: başka bir koda ihtiyaç duyduğunuzda POST /v1/orders/{id}/next-code çağrısı yapın — feePriceVnd 0'dan büyükse confirmFee = true göndermeniz gerekir. Kaynak 3 (normal hizmetler): ücretsiz pencere bittiğinde feePriceVnd, aynı gelen kutusunu yeniden kiralamanın fiyatıdır (rerent).curl
Python
Node.js
# warehouse: 0 | 1–4 | 99 (isteğe bağlı — eskisi gibi kaynak 1 için belirtmeyin; 0 = stokta olan en ucuz kaynak; 99 = otomatik, bir kaynak tükenince sonrakine geçer; bkz. GET /v1/services içindeki offers[])
curl -X POST "https://otpgmail.net/v1/orders" \
-H "Authorization: Bearer og_xxx..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"service":"dr","quantity":1,"domain":"gmail.com","warehouse":2}'{
"success": true,
"data": {
"orderId": "ghi789rst",
"service": "dr",
"domain": "gmail.com",
"email": "[email protected]",
"status": "completed",
"price": 350,
"otp": [
{
"code": "482913",
"receivedAt": 1753268300
}
],
"codeDeadlineAt": 1753269700,
"rentExpiresAt": 1753354200,
"createdAt": 1753267800,
"warehouse": 2,
"nextCodeFee": {
"feePriceVnd": 175,
"freeUntil": 1753289400,
"hardUntil": 1753354200,
"paidPct": 50,
"freeHours": 6
},
"listening": false,
"listenUntil": null,
"nextCodeBlocked": false,
"nextCodeBlockReason": null
}
}Toplu kiralama (toplu siparişler)
Toplu siparişler web'de (Toplu kiralama sayfası) satın alınır — API ile toplu siparişleri listeleyip kodları okuyabilirsiniz. E-posta alan adı kaynağı belirler: Gmail = Kaynak 1, iCloud = Kaynak 3 (özel gelen kutuları).
- Toplu sipariş, satın almadan itibaren 24 saat saklanır — bu sürede kodları ücretsiz okuyun, kod sayısında sınır yoktur.
- Kod almayan gelen kutuları için iade yapılmaz; yalnızca adetteki eksiklik (otomatik olarak) iade edilir.
- Kaynak 1 (Gmail): her gelen kutusunun bir
proxyUrlalanı vardır — birGET, API anahtarı olmadan{"status":1,"code":"482913","all_codes":[...]}döndürür (bağlantının kendisi gizli bilgidir — özel tutun). Aşağıdaki kod uç noktası da çalışır. - Kaynak 3 (iCloud):
proxyUrl=null— kodları aşağıdaki uç noktayla okuyun veyareadUrladresini (web sayfası) açın. Her gelen kutusu o hizmet için hesabınıza bağlıdır; süre dolduktan sonra yine de web'de yeniden kiralayabilirsiniz. - Ayıklanabilir kodu olmayan e-postalar (karşılama e-postaları, bültenler…)
isRaw: trueilecodeiçinde aynen gelir (HTML veya metin, en fazla 20.000 karakter).
GET/v1/batches
Toplu siparişleriniz, en yeniden eskiye (page / pageSize ile sayfalanır, en fazla 100). Her toplu sipariş warehouse (1 = Gmail, 3 = iCloud), status (active | expired | failed), expiresAt, codeCount ve readUrl alanlarına sahiptir.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
page | number | Hayır | Sayfa (varsayılan 1) |
pageSize | number | Hayır | Sayfa başına toplu sipariş (varsayılan 20, en fazla 100) |
curl
Python
Node.js
curl "https://otpgmail.net/v1/batches?page=1&pageSize=20" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"items": [
{
"id": "k3v9m2x7q1w8e5r4",
"serviceCode": "lf",
"serviceName": "Tiktok",
"domain": "icloud.com",
"warehouse": 3,
"status": "active",
"countRequested": 3,
"countReceived": 3,
"countDuplicate": 0,
"countCharged": 3,
"unitPriceVnd": 600,
"quotedVnd": 1800,
"chargedVnd": 1800,
"refundVnd": 0,
"holdHours": 24,
"expiresAt": 1753354200,
"createdAt": 1753267800,
"readUrl": "https://otpgmail.net/app/batch/k3v9m2x7q1w8e5r4",
"codeCount": 1,
"rerentPriceVnd": null
}
],
"total": 1,
"page": 1,
"pageSize": 20
}
}Olası hatalar: UNAUTHORIZEDGET/v1/batches/{id}
mails[] dizisiyle birlikte tek bir toplu sipariş — kodlarını okumak için her gelen kutusunun id değerini alın.
Gmail toplu siparişleri (kaynak 1): her gelen kutusunun proxyUrl değeri betiklerinizde eskisi gibi çalışır. iCloud toplu siparişleri (kaynak 3): proxyUrl = null, kodları aşağıdaki uç noktayla okuyun. Süresi dolmuş iCloud toplu siparişleri rerentPriceVnd değerini taşır — bir gelen kutusunu tek tek yeniden kiralamanın fiyatı (web'de yapılır).
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | Toplu sipariş kimliği (Toplu kiralama sayfasında ve readUrl içinde görünür) |
curl
Python
Node.js
curl "https://otpgmail.net/v1/batches/BATCH_ID" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"id": "k3v9m2x7q1w8e5r4",
"serviceCode": "lf",
"serviceName": "Tiktok",
"domain": "icloud.com",
"warehouse": 3,
"status": "active",
"countRequested": 3,
"countReceived": 3,
"countDuplicate": 0,
"countCharged": 3,
"unitPriceVnd": 600,
"quotedVnd": 1800,
"chargedVnd": 1800,
"refundVnd": 0,
"holdHours": 24,
"expiresAt": 1753354200,
"createdAt": 1753267800,
"readUrl": "https://otpgmail.net/app/batch/k3v9m2x7q1w8e5r4",
"codeCount": 1,
"rerentPriceVnd": null,
"mails": [
{
"id": 812,
"email": "[email protected]",
"url": "https://otpgmail.net/app/batch/k3v9m2x7q1w8e5r4",
"proxyUrl": null,
"readUrl": "https://otpgmail.net/app/batch/k3v9m2x7q1w8e5r4",
"fresh": true,
"codeCount": 1,
"lastCode": "482913",
"lastCodeAt": 1753268500,
"lastIsRaw": false,
"checkedAt": 1753268507
}
]
}
}Olası hatalar: UNAUTHORIZED, NOT_FOUNDGET/v1/batches/{id}/mails/{mailId}/codes
Bir toplu siparişteki tek bir gelen kutusunun kodlarını okuyun: gelen kutusunun sırası geldiyse sistem sağlayıcıyı kontrol eder, ardından alınan HER kodu en eskiden başlayarak döndürür — en yeni kod codes[] içinde sondadır.
Beklerken her 5–10 saniyede bir sorgulayın (daha sık çağırmak yalnızca saklanan veriyi döndürür — polledAt değişmez). Ayıklanabilir kodu olmayan e-postalar, isRaw: true ile code içinde aynen gelir. Süresi dolmuş toplu siparişler saklanan kodlarını yine döndürür ancak artık kontrol edilmez.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | Toplu sipariş kimliği |
mailId | number | Evet | Gelen kutusu kimliği (mails[].id) |
poll | 0 | 1 | Hayır | 0 = yalnızca saklanan kodları oku, sağlayıcıyı kontrol etme (varsayılan 1) |
curl
Python
Node.js
# Beklerken her 5–10 saniyede bir yeniden çağırın; en yeni kod codes[] içinde sondadır
curl "https://otpgmail.net/v1/batches/BATCH_ID/mails/MAIL_ID/codes" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"mailId": 812,
"codes": [
{
"code": "482913",
"receivedAt": 1753268500,
"isRaw": false
}
],
"polledAt": 1753268507,
"mail": {
"id": 812,
"email": "[email protected]",
"url": "https://otpgmail.net/app/batch/k3v9m2x7q1w8e5r4",
"proxyUrl": null,
"readUrl": "https://otpgmail.net/app/batch/k3v9m2x7q1w8e5r4",
"fresh": true,
"codeCount": 1,
"lastCode": "482913",
"lastCodeAt": 1753268500,
"lastIsRaw": false,
"checkedAt": 1753268507
}
}
}Olası hatalar: UNAUTHORIZED, NOT_FOUND, RATE_LIMITEDBuy live Gmail accounts (2 warehouses)
Buy short-lived Gmail accounts outright: you are charged when you order and the accounts arrive within seconds. There are two mail-shop warehouses (numbered separately from the OTP-rental warehouses 1–4), each with ONE price for any quantity. Prices returned by the API are YOUR account's prices (custom price if the admin set one) — exactly what you are charged.
Warehouses- Kaynak 1 (
gm_cookie) hesapları kurtarma e-postası olmadan gelir — e-posta, şifre, çerezler ve gelen kutusu bağlantısını (inboxUrl/inboxJsonUrl) alırsınız, fazlasını değil. - Önerilen giriş yolu: çerezleri içe aktarın (
cookies, JSON) — bir çerez içe aktarma eklentisiyle ya da antidetect tarayıcınızın çerez içe aktarma özelliğiyle — ardından Gmail'i açın: oturum zaten açıktır, genellikle şifre sorulmaz ve doğrulama istenmez. - Yalnızca kodlara veya e-postalara mı ihtiyacınız var? Bunları
inboxUrl(web sayfası) veyainboxJsonUrl(JSON) ile okuyun — API anahtarı ve Google girişi gerekmez. - Yeni bir cihazda veya IP'de şifreyle giriş yapmak Google'ın doğrulama istemesine (kurtarma e-postası, telefon veya kod) yol açabilir — bu hesaplarda bunu geçecek hiçbir şey yoktur; bunun yerine çerezleri veya gelen kutusu bağlantısını kullanın.
- Yeniden mi satıyorsunuz? Müşterilerinize çerezleri ve gelen kutusu bağlantısını verin — .txt indirmesi (
GET /v1/mail-shop/orders/{id}/download) tek satırdaemail|password|cookies|inboxUrliçerir — ve onlara şifreyle değil çerezlerle giriş yapmalarını söyleyin. - Kaynak 2 (
gm_login) hesapları bunun yerine hızlı giriş bağlantısıyla (loginUrl) gelir — giriş yapmak için bağlantıyı masaüstü tarayıcıda açın.
- See warehouses & prices:
GET /v1/mail-shop/products⇒products[](per warehouse:priceVnd,stock,available,maxQty) +auto(warehouse 99:order,priceVnd). To see the total first, callGET /v1/mail-shop/quote. - Buy:
POST /v1/mail-shop/orderswith{"warehouse": 1 | 2 | 99, "quantity": N}+ headerIdempotency-Key(a new UUID per purchase). The response is the order, usually alreadycompletedwithitems[]. - Get the accounts: read
items[](table below) or download the TXTGET /v1/mail-shop/orders/{id}/download.status=pending⇒ pollGET /v1/mail-shop/orders/{id}every 5 seconds untilcompleted/partial/failed.
curl
Python
Node.js
# 1) warehouses, your prices, stock
curl "https://otpgmail.net/v1/mail-shop/products" -H "Authorization: Bearer og_xxx..."
# 2) buy (warehouse 1 | 2 | 99) — a NEW Idempotency-Key per purchase
curl -X POST "https://otpgmail.net/v1/mail-shop/orders" \
-H "Authorization: Bearer og_xxx..." -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" --max-time 60 \
-d '{"warehouse":99,"quantity":2}'
# 3) status "pending"? read the order again (or download the .txt)
curl "https://otpgmail.net/v1/mail-shop/orders/ORDER_ID" -H "Authorization: Bearer og_xxx..."GET {inboxJsonUrl} (= inboxUrl + ?json) returns the same JSON as GET /api/mailbox/{code}: email, letters[] (≤ max latest emails: from, subject, receivedAt, code — extracted code / link, content — sanitized HTML), total, etag, nextAt. No API key needed (the code in the link is the key — keep it private), CORS is open. Add &max=20|50|100|200 for more emails (default 10), &etag={previous etag} ⇒ unchanged emails come back as empty letters + unchanged: true. Reading one link faster than every 10 seconds ⇒ 429 (retryAfter); link off / wrong / expired ⇒ 404; account locked ⇒ 410.curl "https://otpgmail.net/mail/Q7xK2mP9vL4tR8wN3cB6yH1d?json&max=20"{
"success": true,
"data": {
"email": "[email protected]",
"letters": [
{
"key": "h:9f2c4e1a7b3d5c80",
"from": "Instagram [email protected]",
"subject": "350038 is your Instagram code",
"receivedAt": 1760000520,
"code": "350038",
"content": "<html><body><p>Enter this confirmation code in the app: 350038</p></body></html>"
}
],
"max": 10,
"total": 8,
"fetchedAt": 1760000530,
"cached": false,
"etag": "f1c2a9d4e0b37a65",
"unchanged": false,
"nextAt": 1760000540,
"expiresAt": 1762592400,
"serverTime": 1760000530
}
}Read the Vinted OTP code (otpUrl)A warehouse-2 account with
otpUrl ⇒ open it in a browser to see the latest Vinted code (the page refreshes itself); GET {otpUrl}?json returns {status, code, service, email, checkedAt, retryAfter}: status = waiting (no code yet — ask again after retryAfter seconds) · ok (code = the latest code) · dead (codes can no longer be read for this account) · error (temporarily unreadable — ask again). No API key needed (the code in the link is the key — keep it private), CORS is open; the server reads the source at most every few seconds per account; more than 120 calls / minute / IP ⇒ 429.curl "https://otpgmail.net/api/mail-shop/otp/p3x9k2m7q1w8e5r4.2.Zx8Kq2Lm4Np6Rt0Vw3Yb5c?json"{
"success": true,
"data": {
"status": "ok",
"code": "4829",
"service": "vinted",
"email": "[email protected]",
"checkedAt": 1760000530,
"retryAfter": 5
}
}The 2FA code (twoFaUrl)Some warehouse-1 accounts have 2-step verification (2FA) on — a password sign-in makes Google ask for a 6-digit code.
GET {twoFaUrl} (or open it in a browser) returns text/plain with JUST the current 6 digits (no newline), a Refresh header = seconds until the next code + 1 (browsers reload by themselves), Cache-Control: no-store, open CORS — you can hand the link to your customers. Account without 2FA ⇒ 404 no 2fa; wrong / off / expired link ⇒ 404 not found; locked account ⇒ 410 gone; too fast / source hiccup ⇒ 429 / 502 retry (Retry-After header). With an API key: GET /v1/mail-shop/orders/{id}/items/{lineNo}/2fa ⇒ {none, code, expiresIn}. The server caches the code until it expires. The .txt file (GET /v1/mail-shop/orders/{id}/download): add ?twofa=1 ⇒ a last twoFaUrl column (off by default — the old layout is unchanged).curl "https://otpgmail.net/2fa/Q7xK2mP9vL4tR8wN3cB6yH1d"
# 424819Order statuses- Money:
chargedVnd= Σroute[].quantity×unitPriceVnd(a 99 order split across warehouses ⇒ two legs inroute). Shortfalls are refunded automatically (refundVnd). Delivered accounts are not refunded — the only warranty is the warehouse'sterms(read them first). - Idempotency-Key is required (400 without it): retrying with the SAME key after a timeout returns the same order and charges nothing more; a new key buys again. Use a client timeout of at least 60 seconds.
- Limits: at most 500 accounts per order (and the warehouse's
maxQty), 10 purchases per minute for your account (web + API share it), 180 inbox reads per hour. Above ⇒ 429RATE_LIMITED. - Common errors:
MAILSHOP_OUT_OF_STOCK409 (details.stock= how many you can buy now) ·MAILSHOP_QTY_LIMIT400 (details.max) ·INSUFFICIENT_BALANCE402 ·MAILSHOP_DISABLED503 (warehouse / section paused) ·MAILSHOP_SUPPLIER_ERROR502 (the source refused at once — a failed order was recorded and refunded,details.orderId) ·VALIDATION_ERROR400 (warehouse not 1 | 2 | 99, warehouse and product disagree, missing Idempotency-Key…). - Terms (warranty only for the first sign-in within 2 hours, accounts last ~6–24 hours) are in each warehouse's
terms; the API does not ask you to accept them (the web asks once). API orders show up in your web history (channel=api) and vice versa.
GET/v1/mail-shop/products
The two mail-shop warehouses + automatic warehouse 99. products[]: warehouse (1 | 2), code (gm_cookie | gm_login), delivers (fields of every account), priceVnd (YOUR price), listPriceVnd (list price), stock, available, maxQty (most one order can take now). auto: order (the order warehouse 99 buys in), priceVnd (cheapest warehouse), available.
Warehouse 1 stock = what the source publishes (refreshed every minute; the source checks accounts are live at purchase time, so you may get fewer — the shortfall is refunded). Warehouse 2 = a reference number from a source sharing the same stock, may be off by a few (null = could not be read — just buy); a shortfall becomes a partial order with the rest refunded. available = false ⇒ do not buy from that warehouse (out of stock / paused). Prices can change — read the catalog again before a large purchase.
Örnekcurl
Python
Node.js
curl "https://otpgmail.net/v1/mail-shop/products" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"products": [
{
"warehouse": 1,
"code": "gm_cookie",
"name": "Short-lived live Gmail — with cookies + inbox link",
"description": "Short-lived personal Gmail account. You get the email · password · login cookies · an inbox link (add ?json to read the emails as JSON).",
"terms": "• Warranty covers ONLY the first successful sign-in, within 2 hours of purchase.\n• These Gmail accounts typically last 6–24 hours: use them right after purchase.",
"delivers": [
"email",
"password",
"cookies",
"inboxUrl",
"inboxJsonUrl"
],
"priceVnd": 3300,
"listPriceVnd": 3300,
"stock": 1840,
"available": true,
"maxQty": 500
},
{
"warehouse": 2,
"code": "gm_login",
"name": "Short-lived live Gmail — with a quick login link",
"description": "Short-lived personal Gmail account that has been used on a few services. You get the email · password · a quick login link.",
"terms": "• Warranty covers ONLY the first successful sign-in, within 2 hours of purchase.\n• Sign in with the link in a DESKTOP BROWSER.",
"delivers": [
"email",
"password",
"loginUrl"
],
"priceVnd": 6000,
"listPriceVnd": 6000,
"stock": 141,
"available": true,
"maxQty": 100
}
],
"auto": {
"warehouse": 99,
"priceVnd": 3300,
"available": true,
"order": [
1,
2
]
}
}
}Olası hatalar: UNAUTHORIZEDGET/v1/mail-shop/quote
Call quote to see the total first (nothing is reserved). Warehouse 99 ⇒ route[] = planned split by known stock; available = false ⇒ that quantity cannot be bought right now.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
warehouse | 1 | 2 | 99 | Hayır | Mail-shop warehouse: 1 = email + password + cookies + inbox link · 2 = email + password + login link · 99 = automatic, cheapest first. Send warehouse OR product |
product | string | Hayır | Instead of warehouse: gm_cookie (= warehouse 1) | gm_login (= warehouse 2) |
quantity | number | Hayır | Number of accounts (default 1) |
curl
Python
Node.js
curl "https://otpgmail.net/v1/mail-shop/quote?warehouse=99&quantity=10" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"warehouse": 99,
"quantity": 10,
"unitPriceVnd": 3300,
"totalVnd": 38400,
"available": true,
"stock": null,
"maxQty": 500,
"route": [
{
"warehouse": 1,
"quantity": 8,
"unitPriceVnd": 3300
},
{
"warehouse": 2,
"quantity": 2,
"unitPriceVnd": 6000
}
]
}
}Olası hatalar: UNAUTHORIZED, VALIDATION_ERROR, MAILSHOP_PRODUCT_NOT_FOUNDPOST/v1/mail-shop/orders
Buy: you are charged at once, then the system buys from the source and delivers. The response is the order — usually already completed with items[]; status = pending ⇒ poll GET /v1/mail-shop/orders/{id} every 5 seconds. The call waits up to about 16 seconds for the delivery.
Idempotency-Key is required (400 without it). Not enough stock ⇒ MAILSHOP_OUT_OF_STOCK (error.details.stock = how many you can buy now, nothing charged); over the per-order limit ⇒ MAILSHOP_QTY_LIMIT (error.details.max). 502 MAILSHOP_SUPPLIER_ERROR = the source refused at once: a failed order was recorded and fully refunded (error.details.orderId) — retry with a new key.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
warehouse | 1 | 2 | 99 | Hayır | Mail-shop warehouse: 1 = email + password + cookies + inbox link · 2 = email + password + login link · 99 = automatic, cheapest first. Send warehouse OR product |
product | string | Hayır | Instead of warehouse: gm_cookie (= warehouse 1) | gm_login (= warehouse 2) |
quantity | number | Hayır | Number of accounts (default 1) |
Idempotency-Key | string | Evet | Header: a new UUID for every new purchase — reuse it only to retry that same purchase |
curl
Python
Node.js
# Idempotency-Key zorunludur: her satın alma için yeni bir UUID — aynı anahtarı yalnızca zaman aşımından sonra yeniden denerken kullanın
# warehouse: 1 = cookies + inbox link · 2 = login link · 99 = cheapest first
curl -X POST "https://otpgmail.net/v1/mail-shop/orders" \
-H "Authorization: Bearer og_xxx..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
--max-time 60 \
-d '{"warehouse":99,"quantity":5}'{
"success": true,
"data": {
"id": "p3x9k2m7q1w8e5r4",
"requestedWarehouse": 99,
"warehouse": 1,
"productCode": "gm_cookie",
"quantity": 2,
"deliveredCount": 2,
"unitPriceVnd": 3300,
"chargedVnd": 9300,
"refundVnd": 0,
"status": "completed",
"channel": "api",
"route": [
{
"warehouse": 1,
"quantity": 1,
"unitPriceVnd": 3300
},
{
"warehouse": 2,
"quantity": 1,
"unitPriceVnd": 6000
}
],
"message": null,
"createdAt": 1760000400,
"completedAt": 1760000409,
"items": [
{
"lineNo": 1,
"warehouse": 1,
"email": "[email protected]",
"password": "Pw7Xq!k3d",
"rawLine": "[email protected]|Pw7Xq!k3d||[{\"domain\":\".google.com\",\"name\":\"SID\",\"value\":\"g.a000…\"}]",
"cookies": "[{\"domain\":\".google.com\",\"name\":\"SID\",\"value\":\"g.a000…\"}]",
"inboxUrl": "https://otpgmail.net/mail/Q7xK2mP9vL4tR8wN3cB6yH1d",
"inboxJsonUrl": "https://otpgmail.net/mail/Q7xK2mP9vL4tR8wN3cB6yH1d?json",
"twoFaUrl": "https://otpgmail.net/2fa/Q7xK2mP9vL4tR8wN3cB6yH1d",
"inboxLinkExpiresAt": 1762592400
},
{
"lineNo": 2,
"warehouse": 2,
"email": "[email protected]",
"password": "Qp9!rT2",
"rawLine": "[email protected]!rT2----no----https://login.example/google/login?uid=s2c38a3b",
"loginUrl": "https://login.example/google/login?uid=s2c38a3b",
"otpUrl": "https://otpgmail.net/api/mail-shop/otp/p3x9k2m7q1w8e5r4.2.Zx8Kq2Lm4Np6Rt0Vw3Yb5c",
"otpService": "vinted"
}
]
}
}Olası hatalar: UNAUTHORIZED, VALIDATION_ERROR, MAILSHOP_PRODUCT_NOT_FOUND, MAILSHOP_DISABLED, MAILSHOP_QTY_LIMIT, MAILSHOP_OUT_OF_STOCK, INSUFFICIENT_BALANCE, MAILSHOP_SUPPLIER_ERROR, RATE_LIMITED, DUPLICATE_REQUEST, MAINTENANCEGET/v1/mail-shop/orders
Your mail-shop orders, newest first (page / pageSize, up to 100 per page) — without items[]: fetch an order to get its accounts. Orders bought on the web are listed too (channel = web).
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
page | number | Hayır | Page (default 1) |
pageSize | number | Hayır | Orders per page (default 20, max 100) |
curl
Python
Node.js
curl "https://otpgmail.net/v1/mail-shop/orders?page=1&pageSize=20" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"items": [
{
"id": "p3x9k2m7q1w8e5r4",
"requestedWarehouse": 99,
"warehouse": 1,
"productCode": "gm_cookie",
"quantity": 2,
"deliveredCount": 2,
"unitPriceVnd": 3300,
"chargedVnd": 9300,
"refundVnd": 0,
"status": "completed",
"channel": "api",
"route": [
{
"warehouse": 1,
"quantity": 1,
"unitPriceVnd": 3300
},
{
"warehouse": 2,
"quantity": 1,
"unitPriceVnd": 6000
}
],
"message": null,
"createdAt": 1760000400,
"completedAt": 1760000409
}
],
"total": 1,
"page": 1,
"pageSize": 20
}
}Olası hatalar: UNAUTHORIZEDGET/v1/mail-shop/orders/{id}
One order with every account delivered so far (an order still delivering already shows what has arrived). route[] = which warehouse, how many, at what price.
Poll every 5 seconds while status = pending; completed / partial / failed / refunded are final. An order of many warehouse-1 accounts (cookies) can weigh several MB — stop polling once it is final.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | Order ID (data.id returned by the purchase) |
curl
Python
Node.js
curl "https://otpgmail.net/v1/mail-shop/orders/ORDER_ID" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"id": "p3x9k2m7q1w8e5r4",
"requestedWarehouse": 99,
"warehouse": 1,
"productCode": "gm_cookie",
"quantity": 2,
"deliveredCount": 2,
"unitPriceVnd": 3300,
"chargedVnd": 9300,
"refundVnd": 0,
"status": "completed",
"channel": "api",
"route": [
{
"warehouse": 1,
"quantity": 1,
"unitPriceVnd": 3300
},
{
"warehouse": 2,
"quantity": 1,
"unitPriceVnd": 6000
}
],
"message": null,
"createdAt": 1760000400,
"completedAt": 1760000409,
"items": [
{
"lineNo": 1,
"warehouse": 1,
"email": "[email protected]",
"password": "Pw7Xq!k3d",
"rawLine": "[email protected]|Pw7Xq!k3d||[{\"domain\":\".google.com\",\"name\":\"SID\",\"value\":\"g.a000…\"}]",
"cookies": "[{\"domain\":\".google.com\",\"name\":\"SID\",\"value\":\"g.a000…\"}]",
"inboxUrl": "https://otpgmail.net/mail/Q7xK2mP9vL4tR8wN3cB6yH1d",
"inboxJsonUrl": "https://otpgmail.net/mail/Q7xK2mP9vL4tR8wN3cB6yH1d?json",
"twoFaUrl": "https://otpgmail.net/2fa/Q7xK2mP9vL4tR8wN3cB6yH1d",
"inboxLinkExpiresAt": 1762592400
},
{
"lineNo": 2,
"warehouse": 2,
"email": "[email protected]",
"password": "Qp9!rT2",
"rawLine": "[email protected]!rT2----no----https://login.example/google/login?uid=s2c38a3b",
"loginUrl": "https://login.example/google/login?uid=s2c38a3b",
"otpUrl": "https://otpgmail.net/api/mail-shop/otp/p3x9k2m7q1w8e5r4.2.Zx8Kq2Lm4Np6Rt0Vw3Yb5c",
"otpService": "vinted"
}
]
}
}Olası hatalar: UNAUTHORIZED, NOT_FOUNDGET/v1/mail-shop/orders/{id}/download
The delivered accounts as .txt (text/plain), separated by |. The FIRST LINE is the column header: warehouse 1 email|password|cookies|inboxUrl · warehouse 2 email|password|loginUrl · a 99 order with both warehouses ⇒ email|password|cookies|inboxUrl|loginUrl (missing cells empty).
cookies is one-line JSON and may contain | — split email and password at the first two |, the link at the last | (with extra columns ⇒ the links after cookies at the last | separators — links never contain |; read the header line for their order). Nothing delivered yet ⇒ 409 VALIDATION_ERROR. Add <c>?otp=1</c> ⇒ warehouse 2 gets a LAST column <c>otpUrl</c> (the Vinted OTP link — empty when the account has none): email|password|loginUrl|otpUrl. Without it ⇒ exactly the columns above. Add <c>?twofa=1</c> ⇒ warehouse 1 gets a LAST column <c>twoFaUrl</c> (the 2FA link — same code as inboxUrl; GET ⇒ just the 6 digits; empty when the link is off / expired): email|password|cookies|inboxUrl|twoFaUrl. Combines with <c>otp=1</c> — fixed column order: …|loginUrl|otpUrl|twoFaUrl (a 99 order with both warehouses). Without it ⇒ the default layout above.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | Order ID (data.id returned by the purchase) |
curl
Python
Node.js
curl "https://otpgmail.net/v1/mail-shop/orders/ORDER_ID/download" \
-H "Authorization: Bearer og_xxx..." \
-o mail-ORDER_ID.txtemail|password|cookies|inboxUrl
[email protected]|Pw7Xq!k3d|[{"domain":".google.com","name":"SID","value":"g.a000…"}]|https://otpgmail.net/mail/Q7xK2mP9vL4tR8wN3cB6yH1dOlası hatalar: UNAUTHORIZED, NOT_FOUND, VALIDATION_ERRORGET/v1/mail-shop/orders/{id}/items/{lineNo}/inbox
Latest emails of a WAREHOUSE-1 account (sender, subject, time, extracted code / link, sanitized full email). Without an API key: GET the account's inboxJsonUrl (same emails, JSON).
max = 10 (default) | 20 | 50 | 100 | 200 — more emails take longer (up to about a minute). Cached for 15 seconds; every real read counts toward the hourly limit. 409 VALIDATION_ERROR = a warehouse-2 account (no inbox reading); 409 PROVIDER_ERROR with details.dead = the account was locked or removed.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | Order ID (data.id returned by the purchase) |
lineNo | number | Evet | Account number within the order (items[].lineNo) |
max | number | Hayır | Number of latest emails: 10 (default), 20, 50, 100 or 200 |
curl
Python
Node.js
# Warehouse 1 accounts only; max = 10 | 20 | 50 | 100 | 200
curl "https://otpgmail.net/v1/mail-shop/orders/ORDER_ID/items/1/inbox?max=20" \
-H "Authorization: Bearer og_xxx..." \
--max-time 70
# Same emails without an API key: GET the account's inboxJsonUrl
curl "https://otpgmail.net/mail/Q7xK2mP9vL4tR8wN3cB6yH1d?json&max=20"{
"success": true,
"data": {
"email": "[email protected]",
"letters": [
{
"key": "h:9f2c4e1a7b3d5c80",
"from": "Instagram [email protected]",
"subject": "350038 is your Instagram code",
"receivedAt": 1760000520,
"code": "350038",
"content": "<html><body><p>Enter this confirmation code in the app: 350038</p></body></html>"
}
],
"max": 10,
"total": 8,
"fetchedAt": 1760000530,
"cached": false
}
}Olası hatalar: UNAUTHORIZED, NOT_FOUND, VALIDATION_ERROR, RATE_LIMITED, PROVIDER_ERRORPOST/v1/mail-shop/orders/{id}/items/{lineNo}/inbox-link
Manage the inbox link (inboxUrl + inboxJsonUrl + twoFaUrl — one shared code) of a warehouse-1 account: action "regenerate" = NEW link (the old one stops working immediately; also re-enables a link you turned off), "off" = turn it off (inboxUrl / inboxJsonUrl / twoFaUrl become null). Returns the account (an element of items[]).
At most 60 changes per 10 minutes for your account.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | Order ID (data.id returned by the purchase) |
lineNo | number | Evet | Account number within the order (items[].lineNo) |
action | string | Evet | "regenerate" = new link (the old one stops working immediately) · "off" = turn the link off |
curl
Python
Node.js
# Yeni bağlantı (eskisi hemen çalışmaz hale gelir); kapatmak için {"action":"off"} gönderin
curl -X POST "https://otpgmail.net/v1/mail-shop/orders/ORDER_ID/items/1/inbox-link" \
-H "Authorization: Bearer og_xxx..." \
-H "Content-Type: application/json" \
-d '{"action":"regenerate"}'{
"success": true,
"data": {
"lineNo": 1,
"warehouse": 1,
"email": "[email protected]",
"password": "Pw7Xq!k3d",
"rawLine": "[email protected]|Pw7Xq!k3d||[{\"domain\":\".google.com\",\"name\":\"SID\",\"value\":\"g.a000…\"}]",
"cookies": "[{\"domain\":\".google.com\",\"name\":\"SID\",\"value\":\"g.a000…\"}]",
"inboxUrl": "https://otpgmail.net/mail/Hn4Vw8Zr2Lk6Tq9Pm3Xs7Bd1",
"inboxJsonUrl": "https://otpgmail.net/mail/Hn4Vw8Zr2Lk6Tq9Pm3Xs7Bd1?json",
"twoFaUrl": "https://otpgmail.net/2fa/Hn4Vw8Zr2Lk6Tq9Pm3Xs7Bd1",
"inboxLinkExpiresAt": 1762592400
}
}Olası hatalar: UNAUTHORIZED, NOT_FOUND, VALIDATION_ERROR, RATE_LIMITEDGET/v1/mail-shop/orders/{id}/items/{lineNo}/status
Is a bought warehouse-1 account still alive: live = true / false, or null when it cannot be determined. Counts toward the hourly inbox-read limit.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | Order ID (data.id returned by the purchase) |
lineNo | number | Evet | Account number within the order (items[].lineNo) |
curl
Python
Node.js
curl "https://otpgmail.net/v1/mail-shop/orders/ORDER_ID/items/1/status" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"email": "[email protected]",
"live": true,
"reason": null,
"checkedAt": 1760000600
}
}Olası hatalar: UNAUTHORIZED, NOT_FOUND, VALIDATION_ERROR, RATE_LIMITED, PROVIDER_ERRORGET/v1/mail-shop/orders/{id}/items/{lineNo}/2fa
The current 2FA code (6-digit TOTP, changes every 30 seconds) of a warehouse-1 account — some warehouse-1 accounts have 2-step verification on (Google asks for a code at a password sign-in). none = true ⇒ the account has no 2FA (code / expiresIn null). expiresIn = seconds the code stays valid — ask again after that. Without an API key: GET the account's twoFaUrl (the body is just the 6 digits).
The server caches the code until it expires (every call within those 30 seconds gets the same code) — it does NOT count toward the hourly inbox-read limit. Calling too fast ⇒ 429 (retryAfterSec); a warehouse-2 account ⇒ 409; a locked account ⇒ 409 (details.dead).
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | Order ID (data.id returned by the purchase) |
lineNo | number | Evet | Account number within the order (items[].lineNo) |
curl
Python
Node.js
curl "https://otpgmail.net/v1/mail-shop/orders/ORDER_ID/items/1/2fa" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"none": false,
"code": "424819",
"expiresIn": 24
}
}Olası hatalar: UNAUTHORIZED, NOT_FOUND, VALIDATION_ERROR, RATE_LIMITED, PROVIDER_ERRORSipariş yaşam döngüsü
Önemli notlar:
- Sipariş waiting_code durumundayken kodu hemen yakalamak için
GET /v1/orders/{id}adresini her 3–5 saniyede bir sorgulayın. - İlk kod gelir gelmez durum hemen completed olur.
codeDeadlineAtzamanına kadar kod gelmezse (en fazla 25 dakika; kaynak 2: 20 dakika; kaynak 4'ün bazı tedarikçilerinde daha kısa) ⇒ sistem siparişi iptal eder ve %100 iade eder (status = cancelled).otp[]dizisi en eski ilk, en yeni son sıralıdır. Son koduotp[otp.length - 1]ile okuyun (Python:otp[-1]).- completed bir sipariş kod almaya otomatik olarak devam eder:
GET /v1/orders/{id}adresini sorgulamaya devam edin, her yeni kodotp[]dizisinin sonunda görünür. Hizmet birden fazla kod gönderiyorsa ek kodlar sipariş süresi içinde ücretsizdir; sınır ve süre kiralamadan önce gösterilir (offers[]içindekimaxCodesvefee; kaynak 1'de gelen kutusu genellikle son koddan sonra yaklaşık 25 dakika açık kalır). Açıkça başka bir kod istemek için (ör. kayıttan sonra giriş yaparken):POST /v1/orders/{id}/next-code— her kaynakta çalışır ve yalnızca ücretsiz penceresi dışındaki kaynak 2 ücret alır. - Hizmet gelen kutusu başına yalnızca bir koda izin veriyorsa
otp[]o kodda durur. Yanıtlar normal kalır, hata olmaz — sorgulamayı ne zaman bırakacağınıza siz karar verirsiniz. otp[].codegenellikle kısa bir koddur (rakam / harf) ya da bir bağlantıdır. Kodu ayıklanamayan bir e-posta (hoş geldin e-postaları, bültenler, alışılmadık kod biçimleri…)otp[].codeiçinde olduğu gibi (HTML veya metin) teslim edilir — 80 karakterden uzunsa, satır sonu içeriyorsa ya da HTML ise tam e-posta sayın ve kodu ya da bağlantıyı içinde kendiniz arayın.POST /v1/orders, sağlayıcının bir gelen kutusu atamasını bekler; bu yüzden genellikle ~0,3 saniye sürer ancak yoğun saatlerde (nadiren) 10 saniyeye kadar çıkabilir. 5 saniye sonra vazgeçip erken yeniden denemek yerine istemci zaman aşımını ≈ 15 saniyeye ayarlayın — yeniden denediğinizde de aynıIdempotency-Keydeğerini kullanın.- Kod almış bir sipariş iptal edilemez ve iade edilemez — iptal çağrısı
ORDER_NOT_CANCELLABLEdöndürür. - Bir @icloud.com gelen kutusu kiralamak için sipariş oluştururken
"domain": "icloud.com"gönderin (Gmail için belirtmeyin; mevcut botlarda değişiklik gerekmez). Hizmet iCloud'u desteklemiyorsa veya iCloud geçici olarak devre dışıysaDOMAIN_UNAVAILABLEalırsınız — Gmail'e geçin, kiralama hemen gerçekleşir. Yaşam döngüsü, iptal ve iade kuralları ile kodları okuma biçimi Gmail ile tamamen aynıdır. - Kendi stokundan hizmetler (
provider="inventory", örn. Cointiply — bkz.GET /v1/services) yalnızca iCloud'dur; her e-postaotp[].codeiçinde bir bağlantı olarak,kind,labelvetextiçindeki tam e-posta metniyle birlikte gelir. Bir sipariş,rules.windowMinutesdakika içinde (windowEndsAtanına kadar) en fazlarules.maxCodese-posta alır, iptal edilemez (ORDER_NOT_CANCELLABLE) ve e-posta gelmeden süre dolarsa iade yapılmadan cancelled olur. Aynı gelen kutusunda almaya devam etmek içincanRerenttrue ikenPOST /v1/orders/{id}/rerentçağrısı yapın (fiyat:rerentPriceVnd). Diğer tüm hizmetlerde / siparişlerdeprovider="standard"olur — 2026-10-24 itibarıylaprovideryalnızca iki değer alır:"standard"|"inventory"(gerçek depowarehousealanındadır); yalnızca"inventory"ile karşılaştırın. - Kaynak 2 siparişleri (
warehouse= 2): kodlarfee.freeHourssaat boyunca ücretsizdir; ücretsiz pencere kapandığında yeni kodlar gelmez — bir pencere daha açmak içinconfirmFee= true ilePOST /v1/orders/{id}/next-codeçağrısı yapın (nextCodeFee.feePriceVndödenir),nextCodeFee.hardUntilsınırına kadar. Normal hizmetlerin Kaynak 3 siparişleri: 24 saat ücretsiz kod, kod gelmeden önce iptal edilebilir, sonrasındarerentkullanın. Kaynak 4 siparişleri: yeni kodlar siparişi okuduğunuzdaotp[]dizisine düşer,rentExpiresAtzamanına kadar ücretsizdir; tek kod veren kaynakta ilk koddan sonranextCodeBlockReason="max_codes"olur. - Aynı anda çok sayıda sipariş mi var?
POST /v1/orders/statusile çağrı başına en fazla 100 tanesini sorgulayın — Çok sayıda siparişin durumu bölümüne bakın.
İstek sınırları
Sınırlar her API anahtarı için geçerlidir (bir hesabın kendine özel sınırları olabilir; yoksa sitenin varsayılan sınırları uygulanır):
- saniyede 100 istek — birkaç saniyelik kısa yoğunluklar
- dakikada 3000 istek — dakika başına toplam trafik
Bir sınırın aşılması,
Retry-After: <seconds> başlığı ve {"success":false,"error":{"code":"RATE_LIMITED",...}} gövdesiyle birlikte HTTP 429 döndürür. Yeniden denemeden önce başlıkta verilen saniye kadar bekleyin. Hata gövdesi aynı saniye sayısını error.retryAfterSec içinde de taşır (error.retryable = true ile birlikte).Hata kodları
Her hatanın biçimi aynıdır:
{"success":false,"error":{"code":"...","message":"...","retryable":false,"retryAfterSec":null}}2026-10-17 tarihinden itibaren her /v1 hatasında ayrıca
Örnek hata yanıtlarıerror.retryable ve error.retryAfterSec bulunur (eklenen alanlar — mevcut istemcilerin değişmesi gerekmez; details aynı kalır). retryable = true ⇒ aynı çağrı daha sonra başarılı olabilir: retryAfterSec saniye (≥ 1 tam sayı) bekleyip yeniden gönderin — stok yok / gelen kutusu yok / kaynak duraklatıldı / sağlayıcı hatası ⇒ 5 sn; 429 RATE_LIMITED ⇒ Retry-After başlığı; aynı Idempotency-Key ile ilk istek hâlâ sürerken 409 DUPLICATE_REQUEST ⇒ 2 sn. retryable = false (retryAfterSec = null) ⇒ nedeni düzeltmedikçe (bakiye, bekleyen sipariş sınırı, parametreler, API anahtarı…) yeniden çağırmak işe yaramaz. POST /v1/orders yanıtındaki partial.reason da aynı kuralları izler. Stok yok anlamındaki 409 yanıtında (OUT_OF_STOCK, WAREHOUSE_UNAVAILABLE, ALL_WAREHOUSES_EXHAUSTED) yeniden denemeden önce retryAfterSec saniyenin tamamını bekleyin — daha erken denemek genellikle aynı yanıtı döndürür — ve yeniden kiralamadan önce GET /v1/services içindeki stock / offers[].stock değerine bakın; zaten kiraladığınız siparişleri sık sık sorgulamak yerine webhook ile izleyin.HTTP/1.1 409 Conflict
{
"success": false,
"error": {
"code": "OUT_OF_STOCK",
"message": "This service is currently out of stock",
"retryable": true,
"retryAfterSec": 5
}
}
HTTP/1.1 429 Too Many Requests
Retry-After: 1
{
"success": false,
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded, retry after 1s",
"retryable": true,
"retryAfterSec": 1
}
}
HTTP/1.1 402 Payment Required
{
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient balance to rent an inbox",
"retryable": false,
"retryAfterSec": null
}
}Webhook'lar (anlık bildirim)
Hesap başına bir URL kaydedin; bir sipariş yeni kod aldığında (
3 adımda kurulumorder.code) ya da iptal edildiğinde / iade edildiğinde (order.cancelled) bu URL'ye imzalı bir JSON olayı POST ederiz. Webhook'lar isteğe bağlıdır ve hesabınızın tüm siparişlerini kapsar (web ve API). Gönderim en iyi çaba esaslıdır — yedek olarak seyrek sorgulamaya devam edin (aşağıya bakın).- URL'nizle (isteğe bağlı olarak
eventsile)PUT /v1/webhookçağırın —data.secretdeğerini (64 onaltılık karakter) saklayın: her gönderimi doğrulamak için gerekir. PUT'u tekrar çağırmak aynı secret'ı korur. POST /v1/webhook/test— hemen birpingolayı göndeririz ve sunucunuzun ne yanıt verdiğini döndürürüz (ok,httpStatus,error).- Uç noktanız 5 saniye içinde herhangi bir 2xx ile yanıt vermelidir — önce yanıtlayın, olayı sonra işleyin. Diğer her şey (3xx, 4xx, 5xx, zaman aşımı, bağlantı hatası) başarısız sayılır ve yeniden denenir.
URL
İstek biçimihttp:// veya https:// ile başlamalı (geçerli sertifika) ve internetten erişilebilir olmalıdır: localhost, özel, link-local, multicast ve ayrılmış adresler (10.x, 172.16–31.x, 192.168.x, 169.254.x, fc00::/7, fe80::/10…) ile OTPGmail'in kendi sunucuları VALIDATION_ERROR ile reddedilir. Alan adı her gönderimden önce yeniden çözümlenir. Yönlendirmeler izlenmez — son URL'yi kaydedin.Her gönderim, URL'nize JSON gövdeli (UTF-8) bir HTTP POST isteğidir ve şu başlıkları taşır:
Anahtar olarak secret'ınızı kullanıp
Alıcı örnekleri (Python ve Node yalnızca standart kütüphaneyi kullanır; curl komutu kendi alıcınıza doğru imzalı bir deneme gönderimi yapar)X-OTPGmail-Timestamp + . + ham istek gövdesi üzerinde HMAC-SHA256'yı küçük harfli hex olarak hesaplayın ve sha256= sonrasındaki değerle sabit zamanlı karşılaştırın. Anahtar, 64 karakterlik secret dizesinin kendisidir (UTF-8 baytları — hex olarak çözmeyin). Ham baytları kullanın: JSON'u ayrıştırıp yeniden serileştirmek baytları değiştirir. Saatinizden 5 dakikadan fazla sapan zaman damgalarını reddedin (tekrar oynatma koruması).curl
Python
Node.js
# Yerel test: alıcınıza bizimkiyle birebir aynı şekilde imzalanmış bir gönderim yollayın
SECRET="9f2c6d1e8b7a4f3c5e0d2b1a6c9e8f7d3b5a1c2e4f6a8b0d9c7e5f3a1b2c4d6e"
TS=$(date +%s)
BODY='{"event":"ping","deliveryId":"6f1d2c3b-8a9e-4f70-b1c2-d3e4f5a6b7c8","sentAt":'$TS'}'
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')
curl -X POST "http://localhost:8080/" \
-H "Content-Type: application/json" \
-H "X-OTPGmail-Event: ping" \
-H "X-OTPGmail-Delivery: 6f1d2c3b-8a9e-4f70-b1c2-d3e4f5a6b7c8" \
-H "X-OTPGmail-Timestamp: $TS" \
-H "X-OTPGmail-Signature: sha256=$SIG" \
-d "$BODY"{
"event": "order.code",
"deliveryId": "6f1d2c3b-8a9e-4f70-b1c2-d3e4f5a6b7c8",
"sentAt": 1760700125,
"orderId": "k3m9x2p7q1w8e5r4",
"service": "fb",
"warehouse": 1,
"domain": "gmail.com",
"email": "[email protected]",
"code": "482913",
"receivedAt": 1760700124,
"status": "completed",
"otp": [
{
"code": "482913",
"receivedAt": 1760700124
}
]
}Örnek gövde — order.cancelled{
"event": "order.cancelled",
"deliveryId": "0b7e4c2a-5d1f-4e8b-9a3c-2f6d8e1b4a7c",
"sentAt": 1760701630,
"orderId": "p8v2n5c1x7z3m9k4",
"service": "ig",
"warehouse": 2,
"domain": "gmail.com",
"email": "[email protected]",
"reason": "timeout",
"refundVnd": 1500,
"status": "cancelled"
}Örnek gövde — ping{
"event": "ping",
"deliveryId": "3c9a1e7f-2b4d-4c6e-8f0a-5d7b9c1e3a2f",
"sentAt": 1760700000
}Yeniden deneme, duraklatma ve geçmiş- Başarısız bir gönderim 10 sn, 1 dk, 5 dk, 30 dk ve 2 saat sonra yeniden denenir (5 deneme); son deneme de başarısız olursa olay bırakılır (
failed). - Arka arkaya 50 başarısız deneme (tüm olaylar genelinde) webhook'u duraklatır:
GET /v1/webhookpausedAtgösterir, hiçbir şey gönderilmez ve yeni olaylar kuyruğa alınmaz. - Devam ettirmek için:
PUT /v1/webhookçağrısını tekrarlayın (aynı URL olabilir) veya başarılı birPOST /v1/webhook/testalın — kuyrukta bekleyen olaylar ardından gönderilir. GET /v1/webhook/deliveriesson 100 gönderimi durumu, deneme sayısı ve son hatasıyla listeler; geçmiş 7 gün saklanır.
Aynı olay birden fazla kez gelebilir (örneğin 2xx yanıtınız kaybolduğunda) ve olaylar sırasız gelebilir (birkaçı paralel gönderilir). İşlenmiş
Yedek olarak sorgulamaya devam edindeliveryId değerlerini saklayın ve tekrarları atlayın; bir sipariş için varış sırasına değil en yeni verisine (otp, status) güvenin.Webhook'lar gecikebilir (yeniden denemeler) veya kaçırılabilir (webhook duraklatıldı, sunucunuz kapalı). Seyrek bir sorgulama sürdürün — örneğin hâlâ
waiting_code olan siparişler için 30–60 sn'de bir GET /v1/orders/{id} — ve API'den gelen sipariş nesnesini doğru kaynak kabul edin.PUT/v1/webhook
Hesabınızın webhook'unu kaydeder veya günceller. İlk çağrı oluşturur ve yeni bir secret döndürür; sonraki çağrılar secret'ı korur, webhook'u yeniden açar ve duraklatılmışsa devam ettirir. events gönderilmezse: yeni webhook için her iki olay, mevcut webhook için değişmez. URL herkese açık bir adres olmalıdır — aksi halde 400 VALIDATION_ERROR (nedeni error.details.problem içinde).
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
url | string | Evet | Uç noktanız (http:// veya https://, herkese açık adres, en fazla 2048 karakter) |
events | string[] | Hayır | Gönderilecek olaylar: ["order.code", "order.cancelled"] (varsayılan ikisi de) |
curl
Python
Node.js
# data.secret değerini saklayın — her gönderimi doğrulamak için gerekir
curl -X PUT "https://otpgmail.net/v1/webhook" \
-H "Authorization: Bearer og_xxx..." \
-H "Content-Type: application/json" \
-d '{"url":"https://your-server.example/otpgmail-webhook","events":["order.code","order.cancelled"]}'{
"success": true,
"data": {
"url": "https://your-server.example/otpgmail-webhook",
"events": [
"order.code",
"order.cancelled"
],
"enabled": true,
"secret": "9f2c6d1e8b7a4f3c5e0d2b1a6c9e8f7d3b5a1c2e4f6a8b0d9c7e5f3a1b2c4d6e",
"pausedAt": null,
"consecutiveFailures": 0,
"createdAt": 1760699000,
"updatedAt": 1760699000
}
}Olası hatalar: UNAUTHORIZED, VALIDATION_ERRORGET/v1/webhook
Hesabınızın webhook'u; secret, pausedAt ve consecutiveFailures dahil. Kayıtlı webhook yoksa data null olur.
Örnekcurl
Python
Node.js
curl "https://otpgmail.net/v1/webhook" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"url": "https://your-server.example/otpgmail-webhook",
"events": [
"order.code",
"order.cancelled"
],
"enabled": true,
"secret": "9f2c6d1e8b7a4f3c5e0d2b1a6c9e8f7d3b5a1c2e4f6a8b0d9c7e5f3a1b2c4d6e",
"pausedAt": 1760705400,
"consecutiveFailures": 50,
"createdAt": 1760699000,
"updatedAt": 1760705400
}
}Olası hatalar: UNAUTHORIZEDDELETE/v1/webhook
Webhook'u kaldırır; kuyrukta bekleyen olaylar bırakılır. Her zaman 200 — kaldırılacak bir şey yoksa data.deleted false olur.
Örnekcurl
Python
Node.js
curl -X DELETE "https://otpgmail.net/v1/webhook" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"deleted": true
}
}Olası hatalar: UNAUTHORIZEDPOST/v1/webhook/test
URL'nize hemen bir ping olayı gönderir ve sonucu bildirir: ok (sunucunuz 2xx yanıt verdi), httpStatus, durationMs, error. Başarılı bir test duraklatılmış webhook'u devam ettirir. Dakikada en fazla 10 test; webhook'lar sistem genelinde kapalıyken 503 MAINTENANCE.
Örnekcurl
Python
Node.js
curl -X POST "https://otpgmail.net/v1/webhook/test" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": {
"ok": true,
"httpStatus": 200,
"durationMs": 143,
"error": null,
"deliveryId": "3c9a1e7f-2b4d-4c6e-8f0a-5d7b9c1e3a2f"
}
}Sunucunuz 2xx yanıt vermediğinde 200 yanıtı
Olası hatalar: {
"success": true,
"data": {
"ok": false,
"httpStatus": 500,
"durationMs": 88,
"error": "HTTP 500",
"deliveryId": "7d2b9f4e-1c6a-4e3b-8d5f-0a9c2e7b1f4d"
}
}UNAUTHORIZED, NOT_FOUND, RATE_LIMITED, MAINTENANCEGET/v1/webhook/deliveries
En yeni gönderimler, en yenisi önce (7 gün saklanır): status = queued (sonraki deneme nextAt anında) | delivered | failed | paused; attempts, lastHttpStatus ve lastError ile birlikte. Olay gövdeleri döndürülmez.
Parametreler| Ad | Tür | Zorunlu | Açıklama |
|---|---|---|---|
limit | number | Hayır | Gönderim sayısı, 1–100 (varsayılan 100) |
curl
Python
Node.js
curl "https://otpgmail.net/v1/webhook/deliveries?limit=20" \
-H "Authorization: Bearer og_xxx..."{
"success": true,
"data": [
{
"id": "0b7e4c2a-5d1f-4e8b-9a3c-2f6d8e1b4a7c",
"event": "order.cancelled",
"orderId": "p8v2n5c1x7z3m9k4",
"status": "queued",
"attempts": 1,
"lastHttpStatus": 503,
"lastError": "HTTP 503",
"nextAt": 1760701640,
"createdAt": 1760701630,
"deliveredAt": null
},
{
"id": "6f1d2c3b-8a9e-4f70-b1c2-d3e4f5a6b7c8",
"event": "order.code",
"orderId": "k3m9x2p7q1w8e5r4",
"status": "delivered",
"attempts": 1,
"lastHttpStatus": 200,
"lastError": null,
"nextAt": null,
"createdAt": 1760700124,
"deliveredAt": 1760700125
}
]
}Olası hatalar: UNAUTHORIZED