বিশেষ ছাড় প্রয়োগ করুনযেসব ব্যবহারকারী যেকোনো সার্ভিসের জন্য (Facebook, Instagram এবং Apple বাদে) প্রতিদিন ২০০০ টির বেশি Gmail এর OTP ভাড়া নেন এবং স্পেশাল ডিসকাউন্ট চান, তারা নির্দ্বিধায় আমাকে মেসেজ করতে পারেন! যারা পর্যাপ্ত পরিমাণে অ্যাকাউন্ট রেজিস্টার করছেন তাদের জন্য মূল মূল্যের উপর 50% পর্যন্ত ছাড় হতে পারে।
New update 29/09I have just added 4 new warehouses for all services + short-live accounts shop (24h) with email + pass for you to log in, feel free to check them out when you have time

API ডকুমেন্টেশন

পাবলিক API /v1 — API key দিয়ে অথেন্টিকেট করে নিজের সফটওয়্যার থেকে ইনবক্স ভাড়া অটোমেট করুন

আপনার API key
আপনি লগইন করেননি — নিজের API key পেতে লগইন করুন।
এই key-টি Authorization: Bearer <key> হেডারে বা ?api_key=<key> কোয়েরি প্যারামিটারে পাঠান। পুরো key দেখতে চোখের আইকনে ক্লিক করুন; বদলাতে হলে নতুন key তৈরি করুন-এ ক্লিক করুন (পুরোনো key সঙ্গে সঙ্গে কাজ করা বন্ধ করবে)।

ওভারভিউ

Base URL
https://otpgmail.net
অথেন্টিকেশন
প্রতিটি অনুরোধে আপনার API key যোগ করুন — Authorization: Bearer og_xxx... হেডারে (প্রস্তাবিত) অথবা ?api_key=og_xxx... কোয়েরি স্ট্রিংয়ে।
Idempotency-Key (ডুপ্লিকেট অর্ডার ঠেকায়)
প্রতিটি POST /v1/orders অনুরোধে Idempotency-Key: <প্রতিটি অর্ডারের জন্য নতুন UUID> হেডার থাকা উচিত। অনুরোধ টাইমআউট হলে বা সংযোগ কেটে গেলে একই key দিয়ে আবার পাঠান — সার্ভার নতুন অর্ডার না বানিয়ে আগের রেসপন্সটিই ফেরত দেবে। প্রতিটি নতুন অর্ডারের জন্য নতুন UUID বানান, আর শুধু রিট্রাইয়ের সময়ই আগের UUID ব্যবহার করুন।
একসাথে অনেক অর্ডার: এক কলে স্ট্যাটাস
দশ বা শত শত ইনবক্স ভাড়া নিচ্ছেন? সেগুলোর স্ট্যাটাস একসাথে পড়ুন: POST /v1/orders/status প্রতি কলে সর্বোচ্চ 100টি অর্ডার ফেরত দেয় (আপনার রেট লিমিটে একটিই অনুরোধ হিসেবে গোনা হয়), আর GET /v1/orders আপনার অর্ডারের তালিকা দেয় — রিস্টার্টের পর ?status=waiting_code সেই সব অর্ডার ফেরত দেয় যেগুলো এখনও কোডের অপেক্ষায়। প্রতিটি ত্রুটিও জানায় আবার চেষ্টা করা উচিত কি না (error.retryable, error.retryAfterSec)। বিস্তারিত: অনেক অর্ডারের স্ট্যাটাস অংশ।
ইনবক্সের ধরন: Gmail বা iCloud
ডিফল্টে আপনি একটি @gmail.com ইনবক্স পান। @icloud.com ইনবক্স ভাড়া নিতে POST /v1/orders-এর বডিতে "domain": "icloud.com" যোগ করুন। domain না দিলে ধরা হয় gmail.com — বিদ্যমান ইন্টিগ্রেশন কোনো পরিবর্তন ছাড়াই চলবে। iCloud শুধু সেসব সার্ভিসের জন্য পাওয়া যায়, GET /v1/services-এ যাদের icloud ফিল্ড null নয়; iCloud-এর দাম Gmail-এর দামের চেয়ে আলাদা হতে পারে (icloud.price দেখুন)। প্রতিটি অর্ডারের রেসপন্সে একটি domain ফিল্ড থাকে, যা জানায় অর্ডারটি কোন ধরনের ইনবক্স ব্যবহার করছে। কিছু সার্ভিস @gmx.com ইনবক্সও দেয় (এখন শুধু Pokemon, কোড pkm, গুদাম 2): "domain": "gmx.com" পাঠান — কোনো সার্ভিস এটি দেয় যদি GET /v1/services-এ তার offers[]-এ domain = "gmx.com" সহ একটি এন্ট্রি থাকে; অন্য যেকোনো সার্ভিসে ⇒ DOMAIN_UNAVAILABLE। ব্যাচের জন্য gmx.com পাওয়া যায় না।
গুদাম: একটি সার্ভিস, ইনবক্সের একাধিক উৎস
একটি সার্ভিস একাধিক গুদাম থেকে বিক্রি হতে পারে; প্রতিটির নিজস্ব দাম, স্টক ও কোডের নিয়ম আছে (GET /v1/services-এর offers[] অ্যারে)। অর্ডার তৈরির সময় "warehouse": 2 পাঠিয়ে একটি বেছে নিন; "warehouse": 99 ⇒ সিস্টেম স্টক আছে এমন সবচেয়ে কম দামের গুদামটি বেছে নেয়, শেষ হয়ে গেলে পরেরটিতে চলে যায় (Facebook ও Instagram-এর মতো যেসব সার্ভিসের স্টক প্রায়ই শেষ হয়, তাদের জন্য আদর্শ); 0 ⇒ স্টক আছে এমন সবচেয়ে কম দামের গুদাম। বিদ্যমান ক্লায়েন্টদের কিছু বদলাতে হবে না: warehouse না দিলে ⇒ আগের মতোই গুদাম 1, আর price, stock ও icloud গুদাম 1-এর তথ্য দেয় (যেসব সার্ভিসে গুদাম 1 নেই ⇒ স্টক আছে এমন সবচেয়ে কম দামের গুদাম)। বিস্তারিত: গুদাম অংশ দেখুন।
বাল্ক ভাড়া (ব্যাচ)
ব্যাচ ওয়েবে কিনতে হয় (বাল্ক ভাড়া পেজ); API দিয়ে ব্যাচের তালিকা দেখা ও কোড পড়া যায়। Gmail (গুদাম 1): প্রতিটি ইনবক্সের একটি proxyUrl আছে — API key ছাড়াই কাজ করে এমন কোড লিংক। iCloud (গুদাম 3): ব্যক্তিগত ইনবক্স; GET /v1/batches/{id}/mails/{mailId}/codes দিয়ে কোড পড়ুন বা ওয়েবে readUrl খুলুন। বিস্তারিত: বাল্ক ভাড়া অংশ।
স্বল্পস্থায়ী Gmail অ্যাকাউন্ট কিনুন (mail shop)
ইনবক্স ভাড়ার পাশাপাশি আপনি 2টি গুদাম থেকে পুরো Gmail অ্যাকাউন্ট কিনে নিতে পারেন — গুদাম 1: ইমেইল, পাসওয়ার্ড, কুকিজ + ইনবক্স লিংক (JSON হিসেবেও); গুদাম 2: ইমেইল, পাসওয়ার্ড + কুইক লগইন লিংক; গুদাম 99 সবচেয়ে সস্তাটি আগে নেয় (ওয়েবের স্বল্পস্থায়ী Gmail কিনুন পেজ)। ওই পেজে যা কিছু করা যায়, API দিয়েও তার সবই করা যায়: গুদাম, দাম ও স্টক দেখা, কেনা (Idempotency-Key বাধ্যতামূলক), ডেলিভারির অগ্রগতি দেখা, অ্যাকাউন্ট ডাউনলোড করা এবং সেগুলোর ইমেইল পড়া। বিস্তারিত: স্বল্পস্থায়ী Gmail কিনুন অংশ।
আপনার গ্রাহকরা নিজেরাই কোড দেখুক (/otp পেজ)
ভাড়া নেওয়া ইনবক্স (ওয়েবে বা API দিয়ে) আবার বিক্রি করেন? অ্যাকাউন্ট পেজে একটি শেয়ার কোড চালু করুন, তারপর গ্রাহককে https://otpgmail.net/bn/otp#k7m2q9:[email protected] লিংকটি পাঠান (k7m2q9 = আপনার শেয়ার কোড) — তারা লগইন না করেই ওই ইমেলের সর্বশেষ কোড দেখেন, দাম বা আপনার ব্যালান্স কখনো দেখেন না; পেজটি শুধু বিনামূল্যের কাজ করে (কখনো আপনার টাকা কাটে না)।
টুল / বটের জন্য JSON লিংক (আপনার বা আপনার গ্রাহকের): পাথ-আকারের লিংক https://otpgmail.net/bn/otp/k7m2q9:[email protected] নিন (এটি # লিংকের মতোই /otp পেজ খোলে) এবং শেষে ?json যোগ করুন ⇒ সার্ভার পেজে যা দেখায় ঠিক সেই ডেটাই JSON-এ ফেরত দেয়: cards[] — ওই ইমেইলে ভাড়া নেওয়া প্রতিটি সার্ভিসের জন্য একটি কার্ড (email, serviceName, state, items[] = নতুনটি আগে রেখে সর্বোচ্চ ৫টি সর্বশেষ কোড / লিংক) — আর serverTime। state: waiting প্রথম কোডের অপেক্ষা · listening নতুন কোডের অপেক্ষা · received কোড এসেছে · needs_owner বিক্রেতাকে মেয়াদ বাড়াতে হবে · expired মেয়াদ শেষ · banned ইনবক্স লক। একাধিক ইমেইল: কমা দিয়ে আলাদা করুন (সর্বোচ্চ ৫০)। API কি বা কুকি লাগে না, CORS খোলা; শুধু পড়ার জন্য (“নতুন OTP লোড করুন” / “এই ইমেইল আবার ভাড়া নিন” /otp পেজেই থাকে)। অনুমান ঠেকানোর সীমা পেজের মতোই: ভুল কোড / ইমেইলে দেখানোর মতো অর্ডার নেই ⇒ 404 NOT_FOUND; বারবার ভুল বা একটি ইমেইলের জন্য মিনিটে ৩০ বারের বেশি পড়া ⇒ 429 RATE_LIMITED সঙ্গে retryAfter (সেকেন্ড)। /otp#… লিংকে ?json যোগ করলে JSON আসে না: ব্রাউজার #-এর পরের অংশ কখনো সার্ভারে পাঠায় না।
curl "https://otpgmail.net/bn/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-এ সম্পূর্ণ নমুনা কোড
চালানোর জন্য প্রস্তুত ক্লায়েন্ট Python, Node.js, PHP, C# (.NET) ও curl-এ — ইনবক্স ভাড়া, কোডের অপেক্ষা, রিফান্ডের জন্য স্বয়ংক্রিয় বাতিল, আর স্টক শেষ হলে iCloud ও Gmail-এর মধ্যে বদল: github.com/letoan0902/otpgmail-email-otp-api (ইংরেজি) · thue-otp-gmail (ভিয়েতনামী)। Python-এর নোট: খালি urllib-এর বদলে requests ব্যবহার করুন (এর ডিফল্ট User-Agent CDN থেকে 403 পায়)।
ওয়েবহুক
প্রতিটি অর্ডার বারবার জিজ্ঞেস করার বদলে একটি URL রেজিস্টার করুন এবং কোনো অর্ডারে নতুন কোড এলে বা সেটি বাতিল / রিফান্ড হলে সঙ্গে সঙ্গে স্বাক্ষরিত POST পান — দেখুন ওয়েবহুক।

এন্ডপয়েন্ট

GET/v1/balance
অনুরোধে ব্যবহৃত API key-এর অ্যাকাউন্টের ব্যালেন্স (VND-এ) ফেরত দেয়।
উদাহরণ
curl "https://otpgmail.net/v1/balance" \
  -H "Authorization: Bearer og_xxx..."
নমুনা রেসপন্স
{
  "success": true,
  "data": {
    "balance": 25000
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED
GET/v1/services
চালু সার্ভিসের তালিকা দেয় — কোড, নাম, Gmail-এর দাম (VND-এ) ও বর্তমান Gmail স্টক; @icloud.com ইনবক্সের দাম ও স্টকসহ একটি icloud ব্লক; এবং একটি offers[] অ্যারে: সার্ভিসটি যেসব গুদাম থেকে বিক্রি হয় সেগুলোর প্রতিটির জন্য গুদাম × ইনবক্সের ধরন অনুযায়ী একটি এন্ট্রি (দাম, স্টক, কোডের সংখ্যা, নিয়ম)। ডেটা ক্যাশ করা: স্টক প্রায় প্রতি 30–60 সেকেন্ডে রিফ্রেশ হয়, দাম আরও কম ঘন ঘন।
icloud = null মানে সার্ভিসটি এখনও iCloud সমর্থন করে না (সরবরাহকারী দেয় না, অথবা সাময়িকভাবে বন্ধ) — শুধু Gmail ভাড়া নেওয়া যায়। যেসব সার্ভিসে icloud ব্লক আছে, সেখানে অর্ডার তৈরির সময় "domain": "icloud.com" পাঠালে icloud.price-এ একটি @icloud.com ইনবক্স পাবেন। price / stock / icloud.price গুদাম 1-এর তথ্য দেয় — warehouse ছাড়া অর্ডার যেখানে যায় (যেসব সার্ভিসে গুদাম 1 নেই ⇒ স্টক আছে এমন সবচেয়ে কম দামের গুদাম); প্রতিটি গুদামের দাম ও স্টক offers[]-এ আছে (গুদাম অংশ দেখুন)। stock হলো উৎস যে সংখ্যা প্রকাশ করে (গুদাম 1: প্রায় প্রতি 30 সেকেন্ডে হালনাগাদ হয়), এক কলে ততগুলো ভাড়া পাওয়ার প্রতিশ্রুতি নয়: ইনবক্স একটি একটি করে বরাদ্দ হয় এবং উৎস মাঝপথে ফুরিয়ে যেতে পারে — তখন POST /v1/orders কম অর্ডার আর একটি partial ফিল্ড ফেরত দেয়। গুদাম 2 ও 4-ও নিজ নিজ উৎসের সংখ্যা দেখায়।
উদাহরণ
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
    }
  ]
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED
POST/v1/orders
ভেরিফিকেশন কোড পাওয়ার ইনবক্সের জন্য একটি অর্ডার তৈরি করে — ডিফল্টে Gmail, অথবা domain: "icloud.com" পাঠালে iCloud। সরবরাহকারী ইনবক্স বরাদ্দ করামাত্র আপনার ব্যালেন্স থেকে দাম কাটা হয়। অর্ডারের একটি তালিকা ফেরত দেয় (একটি, অথবা quantity > 1 হলে একাধিক)।
আংশিক ডেলিভারি: quantity হলো সর্বোচ্চ সীমা
  • ইনবক্স একটি একটি করে বরাদ্দ হয়। সরবরাহকারীর ইনবক্স মাঝপথে ফুরিয়ে গেলে (যেমন সেই মুহূর্তে গুদাম 1-এ ওই সার্ভিসের জন্য আর ইনবক্স নেই), কল থেমে যায় এবং এ পর্যন্ত তৈরি অর্ডারগুলোসহ HTTP 200 ফেরত দেয় — data quantity-এর চেয়ে ছোট হতে পারে, আর টাকা কাটা হয় শুধু data-র অর্ডারগুলোর জন্য। GET /v1/services-এর stock এক কলে কতগুলো মিলবে তার নিশ্চয়তা দেয় না।
  • তখন উত্তরে data-র পাশে শীর্ষ স্তরের একটি partial ফিল্ডও থাকে (সব ডেলিভারি হলে থাকে না — যে বট শুধু data পড়ে, সেগুলো কোনো পরিবর্তন ছাড়াই চলে): requested, delivered, missing এবং reason = {code, message, retryable, retryAfterSec}, যেখানে code হলো সেই এরর যা কলটি থামিয়েছে (NO_MAILS_AVAILABLE, OUT_OF_STOCK, ALL_WAREHOUSES_EXHAUSTED, INSUFFICIENT_BALANCE, WAITING_LIMIT_REACHED…)।
  • ইনবক্স ফুরিয়ে যাওয়া সাধারণত সাময়িক — গুদাম 1-এ কয়েক সেকেন্ড পরে সরবরাহকারীর কাছে প্রায়ই আবার ইনবক্স চলে আসে। reason.retryable = true হলে reason.retryAfterSec সেকেন্ড (3–5 সেকেন্ড) অপেক্ষা করুন, তারপর বাকি ইনবক্সগুলো (missing) নতুন Idempotency-Key দিয়ে আবার চান (পুরোনো key শুধু এই একই উত্তর আবার ফেরত দেয়); সবগুলো না পাওয়া পর্যন্ত চালিয়ে যান।
  • আংশিক ডেলিভারির ঠিক পরের কলে 409 WAREHOUSE_UNAVAILABLE / OUT_OF_STOCK বা 503 NO_MAILS_AVAILABLE আসতে পারে — এটা স্বাভাবিক: কলের মাঝে 3–5 সেকেন্ড বিরতি দিতে থাকুন এবং কেবল পরপর অনেকগুলো কল ব্যর্থ হলে থামুন (যেমন 10 বার চেষ্টা, প্রায় এক মিনিট); তারপর পরে আবার চেষ্টা করুন, অথবা "warehouse": 99 পাঠান যাতে সিস্টেম অন্য গুদামে চলে যায়। retryable = false (INSUFFICIENT_BALANCE, WAITING_LIMIT_REACHED…) ⇒ আগে কারণটি ঠিক করুন (ব্যালান্স রিচার্জ করুন, অথবা খোলা অর্ডারগুলো শেষ হওয়া পর্যন্ত অপেক্ষা করুন)।
  • ত্রুটির উত্তরেও এই দুটি ফিল্ড error-এর ভেতরে থাকে: error.retryable ও error.retryAfterSec (যেমন 409 OUT_OF_STOCK ⇒ true, 5; 402 INSUFFICIENT_BALANCE ⇒ false, null) — এরর কোড দেখুন।
Idempotency-Key হেডার (একটি UUID) বাধ্যতামূলক। প্রতিটি নতুন ভাড়ার জন্য নতুন UUID বানান; টাইমআউটের পর রিট্রাই করার সময় ডুপ্লিকেট অর্ডার এড়াতে একই key আবার ব্যবহার করুন। এই কল সরবরাহকারীর ইনবক্স বরাদ্দের জন্য অপেক্ষা করে, তাই সাধারণত প্রায় 0.3 সেকেন্ড লাগে, তবে ব্যস্ত সময়ে (বিরল) 10 সেকেন্ড পর্যন্ত লাগতে পারে — 5 সেকেন্ড পরে ছেড়ে দিয়ে আগেভাগে রিট্রাই করার বদলে আপনার ক্লায়েন্টের টাইমআউট প্রায় 15 সেকেন্ড রাখুন।
প্যারামিটার
নামধরনআবশ্যকবিবরণ
servicestringহ্যাঁসার্ভিসের কোড (GET /v1/services থেকে, যেমন "ig", "tg", "fb")
quantitynumberনাসর্বোচ্চ কতগুলো ইনবক্স ভাড়া নেবেন (ডিফল্ট 1; প্রতি অনুরোধে সর্বোচ্চ 200) — গুদাম মাঝপথে ফুরিয়ে গেলে কম পাবেন: data[] গুনুন এবং partial পড়ুন
domainstringনাইনবক্সের ধরন: "gmail.com" (ডিফল্ট), "icloud.com" বা "gmx.com"। না দিলে gmail.com — বিদ্যমান ইন্টিগ্রেশনে কোনো পরিবর্তন লাগবে না। iCloud শুধু সেসব সার্ভিসে ভাড়া নেওয়া যায় যাদের icloud ফিল্ড GET /v1/services-এ null নয়; "gmx.com" শুধু offers[].domain = "gmx.com" আছে এমন সার্ভিসে (বর্তমানে শুধু Pokemon, কোড pkm) — নইলে কল DOMAIN_UNAVAILABLE দিয়ে ব্যর্থ হয়। অন্য যেকোনো মান ⇒ VALIDATION_ERROR।
warehousenumberনাযে গুদাম থেকে ভাড়া নেবেন। না দিলে = গুদাম 1, ঠিক বহু-গুদাম চালুর আগের মতো (যেসব সার্ভিসে গুদাম 1 নেই সেগুলো সবচেয়ে কম দামেরটিতে যায়) — বিদ্যমান ক্লায়েন্টদের কিছু বদলাতে হবে না। 0 = স্টক আছে এমন সবচেয়ে কম দামের গুদাম (শুধু একটি গুদাম চেষ্টা করা হয়)। 1–4 = ঠিক সেই গুদাম (GET /v1/services-এর offers[].warehouse থেকে); সেটি এই সার্ভিস/ইনবক্সের ধরন বিক্রি না করলে, বন্ধ থাকলে বা স্টক শেষ হলে ⇒ WAREHOUSE_UNAVAILABLE। 99 = স্বয়ংক্রিয়: স্টক আছে এমন গুদামগুলো সবচেয়ে কম থেকে সবচেয়ে বেশি দামের ক্রমে চেষ্টা করা হয়, একটি স্টক শেষ বা ব্যর্থ হলে পরেরটিতে যায়; একটিও না থাকলে ⇒ ALL_WAREHOUSES_EXHAUSTED — যেসব সার্ভিসের স্টক প্রায়ই শেষ হয় (Facebook, Instagram…) তাদের জন্য প্রস্তাবিত। গুদাম অংশ দেখুন।
উদাহরণ
# প্রতিটি নতুন অর্ডারের জন্য এলোমেলোভাবে তৈরি নতুন একটি Idempotency-Key ব্যবহার করুন
# টাইমআউটের পর রিট্রাই করার সময় একই key আবার ব্যবহার করুন (ডুপ্লিকেট অর্ডার ঠেকায়)
# domain: "gmail.com" (ডিফল্ট, ঐচ্ছিক) | "icloud.com" (@icloud.com ইনবক্স ভাড়া) | "gmx.com" (শুধু যেসব সার্ভিসে আছে, যেমন Pokemon)
# warehouse: 0 | 1–4 | 99 (ঐচ্ছিক — আগের মতো গুদাম 1 রাখতে এটি বাদ দিন; 0 = স্টক আছে এমন সবচেয়ে কম দামের গুদাম; 99 = স্বয়ংক্রিয়, একটি শেষ হলে পরেরটিতে যায়; GET /v1/services-এর 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
    }
  ]
}
নমুনা উত্তর — আংশিক ডেলিভারি (quantity 5, 2টি ইনবক্স ডেলিভারি হয়েছে)
{
  "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, MAINTENANCE
GET/v1/orders/{id}
ID দিয়ে একটি অর্ডার ফেরত দেয়, এ পর্যন্ত পাওয়া কোডসহ (otp[])। অর্ডার waiting_code অবস্থায় থাকাকালে কোড ধরতে প্রতি 3–5 সেকেন্ডে এই এন্ডপয়েন্ট পোল করুন।
otp[] অ্যারে আসার ক্রমে সাজানো: সবচেয়ে পুরোনোটি আগে, সবচেয়ে নতুনটি শেষে — সর্বশেষ কোড পড়ুন otp[otp.length - 1] দিয়ে। প্রতিটি কলে সিস্টেম এখনও খোলা অর্ডারের জন্য প্রতিটি গুদামের নিজস্ব গতিতে (কয়েক সেকেন্ড পরপর) সরবরাহকারীর কাছে খোঁজ নেয় — এর চেয়ে ঘন ঘন কল করলে শুধু সংরক্ষিত ডেটাই ফেরত আসে। প্রথম কোডের পর পোল করতে থাকুন: পরের কোডগুলো (সার্ভিস একাধিক পাঠালে) অর্ডারের মেয়াদের মধ্যে বাড়তি খরচ ছাড়াই otp[]-এর শেষে যোগ হয় — সীমা ও সময় ভাড়ার আগেই দেখানো হয় (offers[]-এর maxCodes ও fee); সিস্টেম নতুন কোডের অপেক্ষা করছে কি না নিশ্চিত হতে POST /v1/orders/{id}/next-code কল করুন (যেকোনো গুদামে; ফি নেয় শুধু গুদাম 2, তার বিনামূল্যের সময়ের বাইরে)। সার্ভিস প্রতি ইনবক্সে একটিই কোড দিলে otp[] ওই কোডেই থেমে যায় — রেসপন্স স্বাভাবিক থাকে, কোনো ত্রুটি আসে না। warehouse ফিল্ড জানায় ইনবক্সটি কোন গুদাম দিয়েছে (1–4); nextCodeFee হলো আরও কোডের ফি (গুদাম 2 ও 3-এর অর্ডারে; গুদাম 1 ও 4-এ null) — গুদাম অংশ দেখুন। 2026-10-02 থেকে অর্ডারে nextCodeBlocked (true = ইনবক্সে আর কোনো কোড আসবে না) এবং nextCodeBlockReason-ও থাকে — কারণ: "email_banned" (সার্ভিস ইমেইলটি লক করেছে — নতুন একটি ভাড়া নিন), "activation_gone" (সরবরাহকারী ইনবক্স বন্ধ করেছে), "hard_expired" (কোড পাওয়ার সময় শেষ), "max_codes" (কোডের সর্বোচ্চ সংখ্যা এসে গেছে), null (ব্লক হয়নি / কারণ রেকর্ড করা নেই এমন পুরোনো অর্ডার)। এগুলো নতুন যোগ করা ফিল্ড — বিদ্যমান ক্লায়েন্টদের কিছু বদলাতে হবে না। অনেক অর্ডার পোল করছেন? প্রতিটি অর্ডারের জন্য আলাদা GET-এর বদলে প্রতি কলে সর্বোচ্চ 100টি ID POST /v1/orders/status-এ পাঠান — একই অর্ডার অবজেক্ট, রেট লিমিটে একটিই অনুরোধ।
প্যারামিটার
নামধরনআবশ্যকবিবরণ
idstringহ্যাঁঅর্ডার আইডি (অর্ডার তৈরির সময় পাওয়া orderId)
উদাহরণ
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
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, NOT_FOUND
POST/v1/orders/{id}/cancel
অর্ডার বাতিল করে দামের 100% ফেরত দেয়। শুধু তখনই করা যায় যখন অর্ডার waiting_code অবস্থায় আছে এবং কোনো কোড আসেনি।
যে অর্ডার একটি কোডও (একটিই হলেও) পেয়েছে তা বাতিল বা রিফান্ড করা যায় না — ওয়েবসাইট ও API দুটোর ক্ষেত্রেই এটি প্রযোজ্য। rules.cancellable = false থাকা অর্ডার (নিজস্ব ইনভেন্টরির সার্ভিস, যেমন Cointiply) বাতিল করা যায় না: ইনবক্স বরাদ্দ হয়ে গেলে বাতিল বা রিফান্ড নেই — বাতিলের কল ORDER_NOT_CANCELLABLE ফেরত দেয়। সাধারণ সার্ভিসের গুদাম-3 অর্ডার (rules.cancellable = true) কোড আসার আগে অন্য যেকোনো অর্ডারের মতোই বাতিল করা যায়।
প্যারামিটার
নামধরনআবশ্যকবিবরণ
idstringহ্যাঁযে অর্ডার বাতিল করবেন তার ID
উদাহরণ
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
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, NOT_FOUND, ORDER_NOT_CANCELLABLE, PROVIDER_ERROR
POST/v1/orders/{id}/rerent
নিজস্ব ইনভেন্টরির সার্ভিসের (provider = "inventory", যেমন Cointiply) অর্ডারের জন্য একই ইনবক্স আবার ভাড়া নেয়: ওই ইনবক্সে নতুন গ্রহণ-সময়সহ একটি নতুন অর্ডার তৈরি করে, দাম পুরোনো অর্ডারের rerentPriceVnd।
শুধু তখনই কাজ করে যখন পুরোনো অর্ডারের canRerent = true (ওই ইনবক্সের সর্বশেষ অর্ডার, যার আগের সময় শেষ হয়েছে বা সব ইমেইল এসে গেছে)। সফল হওয়ামাত্র দাম কাটা হয় — Idempotency-Key পাঠান এবং রিট্রাইয়ের সময় সেটি আবার ব্যবহার করুন, যাতে দুবার কখনো না কাটে। রেসপন্স হলো { order, message }; order-এর গঠন GET /v1/orders/{id}-এর মতোই। গুদাম 2 (2026-10-09 থেকে): যে অর্ডার বাতিল হয়েছে, সময় শেষ হয়েছে বা মেয়াদ পেরিয়েছে (ইনবক্স বন্ধ) — canRerent = true হলে কল করুন (ওই ইমেইলের সর্বশেষ অর্ডার, এবং ইমেইলে আর কোনো চালু অর্ডার নেই)। সিস্টেম ঠিক সেই ইমেইলটিকে একটি নতুন অর্ডার হিসেবে আবার খোলে (status = waiting_code), দাম rerentPriceVnd (এখন আপনার দামের 100%), এবং যেকোনো গুদাম 2 অর্ডারের মতো ইমেইলের জন্য 20 মিনিট অপেক্ষা করে — ইমেইল না এলে অর্ডার বাতিল হয়ে 100% ফেরত। সার্ভিস ইমেইল লক করলে ⇒ RERENT_EMAIL_BANNED; সরবরাহকারী আর খুলতে না পারলে ⇒ RERENT_MAIL_GONE; গুদাম 2 সাময়িকভাবে বন্ধ ⇒ PROVIDER_ERROR — তিনটির কোনোটিতেই টাকা কাটা হয় না।
প্যারামিটার
নামধরনআবশ্যকবিবরণ
idstringহ্যাঁইনবক্সের আগের অর্ডারের ID (যেটির canRerent = true)
উদাহরণ
# টাইমআউটের পর রিট্রাই করার সময় একই key আবার ব্যবহার করুন (ডুপ্লিকেট অর্ডার ঠেকায়)
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"
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, NOT_FOUND, RERENT_NOT_AVAILABLE, RERENT_EMAIL_BANNED, RERENT_MAIL_GONE, INSUFFICIENT_BALANCE, WAITING_LIMIT_REACHED, RATE_LIMITED, DUPLICATE_REQUEST, PROVIDER_ERROR, MAINTENANCE
POST/v1/orders/{id}/next-code
একই ইনবক্সে পরের কোড চায় — যেকোনো গুদামের (warehouse 1–4) সেই অর্ডারগুলোর জন্য কাজ করে যেগুলোতে প্রথম কোড এসে গেছে (status = completed)। বিনামূল্যে, শুধু গুদাম-2-এর যে অর্ডারের বিনামূল্যের সময় শেষ হয়েছে সেগুলো বাদে (nextCodeFee.feePriceVnd > 0): তখন ফি দিতে ও আরেকটি কোড-সময় খুলতে confirmFee: true পাঠান (সর্বোচ্চ nextCodeFee.hardUntil পর্যন্ত)। আপনার বটকে গুদাম জানতে হবে না: GET /v1/orders/{id} পোল করতে থাকুন — নতুন কোড otp[]-এর শেষে যোগ হয় — আর সিস্টেম যেন নতুন কোডের অপেক্ষা করে এমন চাইলে এই কল করুন।
প্রতিটি গুদামে এই কল কী করে
  • গুদাম 1: অর্ডারের মেয়াদের মধ্যে (rentExpiresAt) প্রতিটি কোডের পর সিস্টেম নিজেই পরের কোডের অপেক্ষা করে — কলটি 200 ফেরত দেয় এবং কিছুই বদলায় না; ইনবক্সে আর কোড আসা সম্ভব না হলে (কোডের সীমা পূর্ণ, ইনবক্স বন্ধ, মেয়াদ শেষ) ⇒ nextCodeBlockReason সহ 409।
  • গুদাম 2: সরবরাহকারীর কাছে ইনবক্স আবার খোলে (reordered = true) এবং ইমেলের জন্য 20 মিনিট অপেক্ষা করে; বিনামূল্যের সময়ের মধ্যে কোনো ফি নেই (nextCodeFee.feePriceVnd = 0), তার বাইরে confirmFee = true পাঠাতে হবে (না পাঠালে ⇒ 409 NEXT_CODE_FEE_CONFIRM, কিছুই কাটা হয় না)। নতুন কোড এলেই কেবল ফি রাখা হয় — 20 মিনিটে কোড না এলে ⇒ স্বয়ংক্রিয় ফেরত। প্রতিটি কোডের পর সিস্টেম আরও 25 মিনিট পরের কোডের অপেক্ষা করে (listening = true, listenUntil)।
  • গুদাম 3 (সাধারণ সার্ভিস): অল্প সময়ের অপেক্ষা আবার চালু করে, বিনামূল্যের সময়ের মধ্যে কোনো ফি নেই (nextCodeFee.freeUntil); তারপর ⇒ 409 — POST /v1/orders/{id}/rerent ব্যবহার করুন। Cointiply-এর মতো নিজস্ব-ইনভেন্টরি সার্ভিসে (rules.cancellable = false) এই কল নেই (409): সময়ের মধ্যে প্রতিটি ইমেল নিজে থেকেই দেখা যায়।
  • গুদাম 4: সরবরাহকারীর কাছে অর্ডারটি আবার পড়ে এবং নতুন কোডের অপেক্ষা করে, rentExpiresAt পর্যন্ত বিনামূল্যে।
200 = সিস্টেম এই অর্ডারের জন্য নতুন কোডের অপেক্ষা করছে (listening = true, listenUntil = অপেক্ষা কখন শেষ হবে; ইনবক্স সবে আবার খোলা হলে reordered = true; ফি কাটা হলে chargedVnd), অথবা কল করার মুহূর্তেই নতুন কোড এসেছে (তা order.otp-এ আছে)। 409 = নতুন অপেক্ষা খোলা যায়নি — error.code পড়ুন; ইনবক্সে কেন আর কোড আসবে না তা order.nextCodeBlockReason-এ (GET /v1/orders/{id}) আছে। যে অর্ডার এখনও প্রথম কোডের অপেক্ষায় (waiting_code) ⇒ 409, এখনই কল করার দরকার নেই। ফি-যুক্ত কলে Idempotency-Key পাঠান (আবার চেষ্টা করলে একই key দিন, যাতে দুবার টাকা না কাটে)। সরবরাহকারীর সাথে যোগাযোগ না হলে ⇒ 502 PROVIDER_ERROR, পরে আবার চেষ্টা করুন। এই কলের 409 ত্রুটি কোড: NEXT_CODE_FEE_CONFIRM (গুদাম 2-এ ফি লাগবে — confirmFee: true দিয়ে আবার কল করুন), EMAIL_BANNED (সার্ভিস ইমেলটি লক করেছে — নতুন একটি ভাড়া নিন; error.details.blockReason = "email_banned"), ORDER_EXPIRED (মেয়াদ শেষ, ইনবক্স বন্ধ, কোডের সীমা পূর্ণ, অথবা সার্ভিসে "পরের কোড" নেই — কারণ order.nextCodeBlockReason-এ), ORDER_NOT_CANCELLABLE (অর্ডারে এখনও প্রথম কোড আসেনি)। যে বট এই কলের যেকোনো 409-কে “আর কোড নেই” ধরে, সেগুলো কোনো পরিবর্তন ছাড়াই চলবে। refresh: true (গুদাম 2): প্রথমে নতুন ইমেল দেখা হয় (এইমাত্র আসা ইমেল সঙ্গে সঙ্গে দেওয়া হয়, আবার খোলা হয় না), তারপর সরবরাহকারীর কাছে ইনবক্স আবার খোলা হয় — বিনামূল্যের সময়ের মধ্যে অপেক্ষা আবার 20 মিনিটের জন্য শুরু হয়; সময়ের বাইরে অপেক্ষার শেষ সময় (listenUntil) একই থাকে এবং কোনো টাকা কাটা হয় না। উত্তরে refreshed (true = এইমাত্র আবার খোলা হয়েছে) ও refreshAvailableAt (unix সেকেন্ড; এর আগে আবার রিফ্রেশ করলে শুধু ইমেল দেখা হয়; null = এখনই করা যাবে) যোগ হয়। অন্য গুদাম: কোনো প্রভাব নেই (refreshed = false)। refresh না পাঠালে কল ঠিক আগের মতোই কাজ করে।
প্যারামিটার
নামধরনআবশ্যকবিবরণ
idstringহ্যাঁঅর্ডার ID (orderId) — যেকোনো গুদাম
confirmFeebooleanনাtrue = আরেকটি কোড-সময় খুলতে nextCodeFee.feePriceVnd দিতে রাজি। feePriceVnd = 0 থাকলে লাগে না।
refreshbooleanনাtrue = গুদাম 2, অর্ডার নতুন কোডের অপেক্ষায় (listening = true) কিন্তু কোড আসছে না: সরবরাহকারীর কাছে এখনই ইনবক্সটি আবার খুলুন (অপেক্ষা রিফ্রেশ) — পুরোনো অপেক্ষাটি সরবরাহকারীর দিকে ইমেল নেওয়া বন্ধ করে দিয়ে থাকতে পারে। বিনামূল্যে; প্রতি অর্ডারে 5 সেকেন্ডে সর্বোচ্চ একবার। অর্ডার অপেক্ষায় না থাকলে ⇒ সাধারণ কলের মতোই।
উদাহরণ
# বিনামূল্যে (nextCodeFee null অথবা feePriceVnd = 0 — বিনামূল্যের সময় শেষ হওয়া গুদাম 2 ছাড়া সব গুদাম): confirmFee লাগবে না
curl -X POST "https://otpgmail.net/v1/orders/ORDER_ID/next-code" \
  -H "Authorization: Bearer og_xxx..."

# বিনামূল্যের সময় শেষ হওয়া গুদাম 2: nextCodeFee.feePriceVnd দিতে confirmFee = true পাঠান
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
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, NOT_FOUND, VALIDATION_ERROR, NEXT_CODE_FEE_CONFIRM, INSUFFICIENT_BALANCE, EMAIL_BANNED, ORDER_EXPIRED, ORDER_NOT_CANCELLABLE, PROVIDER_ERROR, DUPLICATE_REQUEST, MAINTENANCE

এক কলে অনেক অর্ডারের স্ট্যাটাস

যেসব রিসেলার ও বট অনেক ইনবক্স ভাড়া নেয়, তাদের প্রতিটি অর্ডারের জন্য আলাদা GET /v1/orders/{id} পাঠানো উচিত নয়: POST /v1/orders/status একই অর্ডার অবজেক্টসহ প্রতি কলে সর্বোচ্চ 100টি অর্ডার পড়ে, আর GET /v1/orders সংরক্ষিত ডেটা থেকে আপনার অর্ডারের তালিকা দেয়।
  • POST /v1/orders/status দিয়ে প্রতি 3–5 সেকেন্ডে পোল করুন, প্রতি কলে সর্বোচ্চ 100টি অর্ডার ID — প্রতিটি কল রেট লিমিটে একটিই অনুরোধ।
  • প্রতিটি কলে সিস্টেম তালিকার সর্বোচ্চ 20টি খোলা অর্ডারের জন্য সরবরাহকারীর কাছে খোঁজ নেয় (আগে যেগুলো প্রথম কোডের অপেক্ষায়, তারপর যেগুলোর সবচেয়ে বেশি সময় খোঁজ নেওয়া হয়নি) আর বাকিগুলো সংরক্ষিত ডেটা থেকে ফেরত দেয়; সেগুলোর খোঁজ পরের কলগুলোতে নেওয়া হয়। একটি কল প্রায় 3 সেকেন্ডের মধ্যে উত্তর দেয়।
  • অর্ডার চূড়ান্ত হলে তালিকা থেকে সরিয়ে দিন: cancelled (টাকা ফেরত হয়েছে), অথবা আর কোড না লাগলে completed।
  • যেসব ID নেই বা অন্য অ্যাকাউন্টের, সেগুলো missing-এ ফেরত আসে (404 নয়) — সেগুলোও সরিয়ে দিন।
  • রিস্টার্টের পর GET /v1/orders?status=waiting_code দিয়ে সব খোলা অর্ডার আবার নিন (nextCursor ধরে এগোন), তারপর POST /v1/orders/status দিয়ে পোল চালিয়ে যান।
POST/v1/orders/status
এক কলে আপনার সর্বোচ্চ 100টি অর্ডার ফেরত দেয়। প্রতিটি উপাদান হুবহু সেটিই, যা ওই অর্ডারের জন্য GET /v1/orders/{id} ফেরত দেয় (status, পাওয়া সব কোডসহ otp[], warehouse…)। একসাথে অনেক খোলা অর্ডার পোল করতে এটি ব্যবহার করুন।
data, ids-এর ক্রম বজায় রাখে; পুনরাবৃত্ত ID উপেক্ষা করা হয়। যেসব ID নেই বা অন্য অ্যাকাউন্টের, সেগুলো missing-এ থাকে (404 নয়)। খোলা অর্ডারের জন্য সিস্টেম GET /v1/orders/{id}-এর মতোই সরবরাহকারীর কাছে খোঁজ নেয়, তবে প্রতি কলে সর্বোচ্চ 20টি অর্ডারের জন্য — আগে যেগুলো প্রথম কোডের অপেক্ষায়, তারপর যেগুলোর সবচেয়ে বেশি সময় খোঁজ নেওয়া হয়নি — বাকিগুলো সংরক্ষিত ডেটা থেকে ফেরত দেয় (সেগুলোর খোঁজ পরের কলগুলোতে নেওয়া হয়); একটি কল প্রায় 3 সেকেন্ডের মধ্যে উত্তর দেয়। যত ID-ই থাকুক, একটি কল রেট লিমিটে একটিই অনুরোধ। 100-এর বেশি ID, খালি তালিকা বা স্ট্রিং নয় এমন ID ⇒ 400 VALIDATION_ERROR।
প্যারামিটার
নামধরনআবশ্যকবিবরণ
idsstring[]হ্যাঁঅর্ডার ID (orderId) — প্রতি কলে 1 থেকে 100টি
উদাহরণ
# যেসব অর্ডারের অপেক্ষায় আছেন সেগুলোর ID (POST /v1/orders থেকে পাওয়া orderId) — প্রতি কলে সর্বোচ্চ 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"
  ]
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, VALIDATION_ERROR, RATE_LIMITED
GET/v1/orders
আপনার অর্ডারের তালিকা, নতুনটি আগে, শুধু সংরক্ষিত ডেটা থেকে — নতুন কোডের জন্য সরবরাহকারীর কাছে জানতে চায় না (সেটি করে POST /v1/orders/status)। স্ট্যাটাস ও তৈরির সময় অনুযায়ী ফিল্টার করুন; nextCursor দিয়ে পেজ বদলান।
পরের পেজ পেতে nextCursor-কে cursor হিসেবে পাঠান; nextCursor = null ⇒ শেষ পেজ। একই সেকেন্ডে অনেক অর্ডার তৈরি হলেও পেজগুলো কখনও কোনো অর্ডার পুনরাবৃত্তি করে না বা বাদ দেয় না। অভ্যন্তরীণ স্ট্যাটাস কখনও তালিকায় আসে না (শুধু waiting_code, completed, cancelled ও queued)। বট রিস্টার্টের পর: GET /v1/orders?status=waiting_code&limit=200, nextCursor ধরে এগোন, তারপর সেই অর্ডারগুলো POST /v1/orders/status দিয়ে পোল করুন।
প্যারামিটার
নামধরনআবশ্যকবিবরণ
statusstringনাশুধু এই স্ট্যাটাস: waiting_code | completed | cancelled | queued (না দিলে ⇒ সবগুলো)
sincenumberনাশুধু এই unix সময়ে (সেকেন্ড) বা তার পরে তৈরি অর্ডার
limitnumberনাপ্রতি পেজে অর্ডার: 1–200 (ডিফল্ট 50)
cursorstringনাআগের পেজের nextCursor, অপরিবর্তিত অবস্থায়
উদাহরণ
# রিস্টার্টের পর: এখনও কোডের অপেক্ষায় থাকা সব অর্ডার পেজ ধরে ধরে সংগ্রহ করুন
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"
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, VALIDATION_ERROR, RATE_LIMITED

গুদাম

প্রতিটি offers[] এন্ট্রি একটি অফার = (সার্ভিস, গুদাম, ইনবক্সের ধরন)। শুধু বর্তমানে বিক্রি করছে এমন গুদামই তালিকায় থাকে; সাময়িকভাবে স্টক শেষ হওয়া গুদাম stock = 0 নিয়ে তালিকায় থেকে যায়। গুদামের নম্বর স্থির: 1, 2, 3, 4 — অর্ডার তৈরির সময় warehouse প্যারামিটারে একই নম্বর দিন।
বিদ্যমান ক্লায়েন্টদের কিছু বদলাতে হবে না। warehouse না দিলে ⇒ আগের মতোই আচরণ (গুদাম 1: 25 মিনিট অপেক্ষা, সার্ভিস একাধিক কোড পাঠালে 24 ঘণ্টার অর্ডার-মেয়াদের মধ্যে অতিরিক্ত কোড নিজে থেকেই আসে); 0 পাঠালে ⇒ স্টক আছে এমন সবচেয়ে কম দামের গুদাম; 99 পাঠালে ⇒ স্বয়ংক্রিয় গুদাম, একটি শেষ হলে পরেরটিতে যায় (ঠিক নিচে দেখুন); বিদ্যমান প্রতিটি ফিল্ড আগের মতোই থাকে — শুধু নতুন ফিল্ড যোগ হয় (offers[], warehouse, nextCodeFee, listening, nextCodeBlocked…)।
স্বয়ংক্রিয় গুদাম: warehouse = 99 (যেসব সার্ভিসের স্টক প্রায়ই শেষ হয় তাদের জন্য প্রস্তাবিত)
"warehouse": 99 পাঠালে সিস্টেম স্টক আছে এমন সবচেয়ে কম দামের গুদাম থেকে ভাড়া নেয়; সেই গুদামের স্টক শেষ বা সেটি ব্যর্থ হলে একই কলের মধ্যেই পরেরটিতে চলে যায়। Facebook ও Instagram-এর মতো যেসব সার্ভিসের স্টক প্রায়ই শেষ হয়, তাদের জন্য আদর্শ — আপনার বটকে আর offers[] পড়ে গুদামে গুদামে রিট্রাই করতে হয় না।
  • চেষ্টার ক্রম: দাম কম থেকে বেশি (যেমন 1,500 → 1,600 → 1,700 VND); দাম সমান হলে ⇒ কম নম্বরের গুদাম আগে।
  • যে গুদাম শূন্য স্টক জানায় (offers[]-এ stock = 0) তাতে কখনো কল করা হয় না — সময় নষ্ট হয় না।
  • বর্তমান গুদামের স্টক শেষ বা ব্যর্থ হলে পরেরটিতে যায় (OUT_OF_STOCK, NO_MAILS_AVAILABLE, WAREHOUSE_UNAVAILABLE, PROVIDER_ERROR)।
  • অন্য ত্রুটিগুলো পরের গুদাম চেষ্টা না করে সঙ্গে সঙ্গে ফেরত দেওয়া হয়: INSUFFICIENT_BALANCE, WAITING_LIMIT_REACHED, QUANTITY_EXCEEDED, MAINTENANCE, SERVICE_DISABLED, DOMAIN_UNAVAILABLE…
  • quantity > 1: প্রথম গুদামে কম পড়লে বাকিটা পরের গুদাম থেকে আসে — অর্ডার একাধিক গুদামে ভাগ হতে পারে; প্রতিটি অর্ডারে যে গুদাম দিয়েছে তার warehouse ও price থাকে (এবং সেই গুদামের কোডের নিয়ম মেনে চলে)।
  • সব গুদাম চেষ্টা করেও কোনো ইনবক্স ভাড়া নেওয়া না গেলে ⇒ ALL_WAREHOUSES_EXHAUSTED (HTTP 409, কিছুই কাটা হয় না) — পরে আবার চেষ্টা করুন। শুধু কিছু ইনবক্স ভাড়া হলে সেই অর্ডারগুলোসহ 200-ই পাবেন।
উদাহরণ: warehouse = 99 দিয়ে Facebook Gmail ভাড়া নেওয়া
# warehouse: 99 — স্টক আছে এমন সবচেয়ে কম দামের গুদাম; স্টক শেষ বা ব্যর্থ হলে ⇒ নিজে থেকেই পরের গুদাম
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}'
offers[]-এর ফিল্ড
ফিল্ডধরনবিবরণ
warehouse1 | 2 | 3 | 4গুদামের নম্বর: 1, 2, 3 বা 4।
domainstringঅফারের ইনবক্সের ধরন: gmail.com, icloud.com বা gmx.com (অতিরিক্ত ডোমেইন — শুধু কিছু সার্ভিসে, বর্তমানে Pokemon)।
pricenumberএই গুদাম থেকে একটি ইনবক্সের দাম (VND)।
stocknumberবাকি ইনবক্স। 0 = স্টক শেষ — গুদাম 1 বা 2 থেকে ভাড়া নিলে WAREHOUSE_UNAVAILABLE ফেরত আসে; গুদাম 4 তবুও চেষ্টা করা হয় (এর উৎসগুলো 0 জানালেও প্রায়ই মেইল দেয়) এবং কিছু না থাকলে OUT_OF_STOCK ফেরত দেয়।
maxCodesnumber | nullএকটি ইনবক্সে সর্বোচ্চ কয়টি কোড আসতে পারে; null = সীমা নেই / অজানা (fee দেখুন)।
rulesobject | nullগুদাম 3-এর সময়ের নিয়ম (windowMinutes, maxCodes, cancellable, refundOnTimeout, rerentRatio); গুদাম 1, 2 ও 4-এ null।
feeobject | nullঅতিরিক্ত কোডের সময়: ভাড়া থেকে freeHours ঘণ্টা বিনামূল্যে, তারপর প্রতিটি বাড়তি সময়ের জন্য ভাড়ার দামের paidPct%, ভাড়া থেকে সর্বোচ্চ maxHours ঘণ্টা পর্যন্ত (null = সীমা নেই)। fee = null: কোনো ফি নেই — সার্ভিস একাধিক কোড পাঠালে অর্ডারের মেয়াদের মধ্যে অতিরিক্ত কোডের জন্য কিছুই লাগে না (সর্বোচ্চ maxCodes পর্যন্ত), গুদাম 1-এর মতো।
isDefaultbooleanস্টক আছে এমন সবচেয়ে কম দামের গুদামের জন্য true (দাম সমান হলে ⇒ কম নম্বরের গুদাম) — warehouse = 0-তে এটিই ব্যবহার হয়, আর 99-তে এটিই প্রথমে চেষ্টা করা হয়।
গুদাম অনুযায়ী নিয়ম
নিয়মগুদাম 1গুদাম 2গুদাম 3গুদাম 4
প্রথম কোডের জন্য অপেক্ষা25 মিনিট20 মিনিট25 মিনিট ¹সর্বোচ্চ 25 মিনিট (কিছু উৎসে কম — আসল সময়সীমা অর্ডারের codeDeadlineAt)
কোড না এলেনিজে বাতিল, 100% রিফান্ডনিজে বাতিল, 100% রিফান্ডনিজে বাতিল, 100% রিফান্ড ¹নিজে বাতিল, 100% রিফান্ড
কোড আসার আগে বাতিলহ্যাঁহ্যাঁহ্যাঁ ¹হ্যাঁ
প্রতি ইনবক্সে কোডmaxCodes অনুযায়ীসীমা নেইসীমা নেই ¹maxCodes অনুযায়ী (সাধারণত null = সীমা নেই; কিছু অফারে 1)
আরও কোডসার্ভিস আরও কোড পাঠালে 24 ঘণ্টার অর্ডার-মেয়াদের মধ্যে বাড়তি চার্জ নেই; স্বয়ংক্রিয় (আলাদা কল লাগে না)। শেষ কোডের পর ইনবক্স সাধারণত প্রায় 25 মিনিট খোলা থাকে।fee.freeHours ঘণ্টা বিনামূল্যে (বর্তমানে Gmail 6 ঘণ্টা, iCloud 12 ঘণ্টা); তারপর প্রতিটি বাড়তি সময়ের জন্য next-code-এর মাধ্যমে দামের fee.paidPct%, সর্বোচ্চ fee.maxHours পর্যন্ত (Gmail 24 ঘণ্টা, iCloud 10 দিন)24 ঘণ্টা বাড়তি চার্জ নেই; তারপর একই ইনবক্স দামের 50%-এ আবার ভাড়া নিন (rerent)গুদাম 1-এর মতোই 24 ঘণ্টার অর্ডার-মেয়াদের মধ্যে বাড়তি চার্জ নেই — অর্ডার পড়ার সময় নতুন কোড দেখা যায়; next-code সঙ্গে সঙ্গে আবার পড়ে।
¹ শুধু নিজস্ব ইনভেন্টরি থেকে বিক্রি হওয়া সার্ভিস, যেমন Cointiply (provider = "inventory", rules.cancellable = false), rules মেনে চলে: rules.windowMinutes মিনিটের মধ্যে সর্বোচ্চ rules.maxCodesটি ইমেইল, বাতিল নেই, এবং ইমেইল ছাড়া সময় শেষ হলে রিফান্ড নেই।
nextCodeFee — আরও কোডের ফি (গুদাম 2 ও 3-এর অর্ডার)
GET /v1/orders/{id} ও প্রতিটি অর্ডার রেসপন্সে থাকে; গুদাম 1 ও 4-এর অর্ডারে null (আরও কোড বিনামূল্যে)। গুদাম 2: আরেকটি কোড দরকার হলে POST /v1/orders/{id}/next-code কল করুন — feePriceVnd 0-এর বেশি হলে confirmFee = true পাঠাতেই হবে। গুদাম 3 (সাধারণ সার্ভিস): বিনামূল্যের সময় শেষ হলে feePriceVnd হলো একই ইনবক্স আবার ভাড়া নেওয়ার (rerent) দাম।
ফিল্ডধরনবিবরণ
feePriceVndnumberএখনই next-code কল করলে যত কাটা হবে; 0 = এখনও বিনামূল্যের সময়ের মধ্যে।
freeUntilnumber | nullবর্তমান বিনামূল্যের সময়ের শেষ (ইউনিক্স সেকেন্ড)।
hardUntilnumber | nullচূড়ান্ত সীমা (ইউনিক্স সেকেন্ড) — এর পরে আর কোড আসে না।
paidPctnumberপ্রতিটি বাড়তি সময়ের জন্য ভাড়ার দামের যত % কাটা হয়।
freeHoursnumberএকটি কোড-সময়ের বিনামূল্যের ঘণ্টা (গুদাম 2: Gmail 6, iCloud 12; গুদাম 3: 24)।
উদাহরণ: গুদামের তালিকা দেখে একটি থেকে ভাড়া নেওয়া
# warehouse: 0 | 1–4 | 99 (ঐচ্ছিক — আগের মতো গুদাম 1 রাখতে এটি বাদ দিন; 0 = স্টক আছে এমন সবচেয়ে কম দামের গুদাম; 99 = স্বয়ংক্রিয়, একটি শেষ হলে পরেরটিতে যায়; GET /v1/services-এর 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}'
নমুনা গুদাম-2 অর্ডার (GET /v1/orders/{id})
{
  "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
  }
}

বাল্ক ভাড়া (ব্যাচ)

ব্যাচ ওয়েবে কেনা হয় (বাল্ক ভাড়া পেজ) — API দিয়ে ব্যাচের তালিকা দেখা ও কোড পড়া যায়। ইমেইলের ডোমেইনই গুদাম ঠিক করে: Gmail = গুদাম 1, iCloud = গুদাম 3 (ব্যক্তিগত ইনবক্স)।
  • কেনার সময় থেকে একটি ব্যাচ 24 ঘণ্টা রাখা হয় — এই সময়ে বিনামূল্যে কোড পড়ুন, কোডের সংখ্যায় কোনো সীমা নেই।
  • যে ইনবক্সে কোড আসে না তার রিফান্ড নেই; শুধু সংখ্যায় কম পড়লে সেটুকু ফেরত যায় (স্বয়ংক্রিয়ভাবে)।
  • গুদাম 1 (Gmail): প্রতিটি ইনবক্সের একটি proxyUrl আছে — API key ছাড়াই GET করলে {"status":1,"code":"482913","all_codes":[...]} ফেরত আসে (লিংকটিই এখানে গোপন তথ্য — এটি আর কাউকে দেবেন না)। নিচের কোড এন্ডপয়েন্টও কাজ করে।
  • গুদাম 3 (iCloud): proxyUrl = null — নিচের এন্ডপয়েন্ট দিয়ে কোড পড়ুন বা readUrl (ওয়েব পেজ) খুলুন। প্রতিটি ইনবক্স ওই সার্ভিসের জন্য আপনার অ্যাকাউন্টে বাঁধা থাকে; মেয়াদ শেষের পরেও ওয়েবে আবার ভাড়া নিতে পারবেন।
  • যে ইমেইল থেকে কোড আলাদা করা যায় না (ওয়েলকাম ইমেইল, নিউজলেটার…) সেগুলো isRaw: true সহ code-এ হুবহু ফেরত আসে (HTML বা টেক্সট, সর্বোচ্চ 20,000 অক্ষর)।
ব্যাচের ইনবক্সের ফিল্ড (mails[])
ফিল্ডধরনবিবরণ
idnumberইনবক্স ID — কোড এন্ডপয়েন্টের {mailId} প্যারামিটার
emailstringইমেইল ঠিকানা
urlstringগুদাম 1: = proxyUrl · গুদাম 3: = readUrl (পুরোনো স্ক্রিপ্ট / এক্সপোর্ট ফাইলের জন্য রাখা)
proxyUrlstring | nullগুদাম 1: লগইন ছাড়া কোড লিংক · গুদাম 3: null
readUrlstringব্যাচের কোড পড়ার ওয়েব পেজ
codeCountnumberপাওয়া কোডের সংখ্যা
lastCodestring | nullসবচেয়ে নতুন কোড (মূল ইমেইল হলে: প্রথম 300 অক্ষর — পূর্ণ লেখা কোড এন্ডপয়েন্টে)
lastIsRawbooleantrue = সবচেয়ে নতুন কোডটি একটি মূল ইমেইল
checkedAtnumber | nullসিস্টেম এই ইনবক্সের জন্য সরবরাহকারীর কাছে সর্বশেষ কখন যাচাই করেছে (ইউনিক্স সেকেন্ড; null = কখনো নয়)
GET/v1/batches
আপনার ব্যাচগুলো, নতুনটি আগে (page / pageSize দিয়ে পেজ করা, সর্বোচ্চ 100)। প্রতিটি ব্যাচে আছে warehouse (1 = Gmail, 3 = iCloud), status (active | expired | failed), expiresAt, codeCount ও readUrl।
প্যারামিটার
নামধরনআবশ্যকবিবরণ
pagenumberনাপেজ (ডিফল্ট 1)
pageSizenumberনাপ্রতি পেজে ব্যাচের সংখ্যা (ডিফল্ট 20, সর্বোচ্চ 100)
উদাহরণ
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
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED
GET/v1/batches/{id}
একটি ব্যাচ তার mails[] সহ — কোড পড়তে প্রতিটি ইনবক্সের id নিন।
Gmail ব্যাচ (গুদাম 1): প্রতিটি ইনবক্সের proxyUrl আপনার স্ক্রিপ্টে আগের মতোই কাজ করে। iCloud ব্যাচ (গুদাম 3): proxyUrl = null, নিচের এন্ডপয়েন্ট দিয়ে কোড পড়ুন। মেয়াদ শেষ হওয়া iCloud ব্যাচে rerentPriceVnd থাকে — একটি ইনবক্স আলাদাভাবে আবার ভাড়া নেওয়ার দাম (ওয়েবে করতে হয়)।
প্যারামিটার
নামধরনআবশ্যকবিবরণ
idstringহ্যাঁব্যাচ আইডি (বাল্ক ভাড়া পেজে ও readUrl-এ দেখানো থাকে)
উদাহরণ
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
      }
    ]
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, NOT_FOUND
GET/v1/batches/{id}/mails/{mailId}/codes
ব্যাচের একটি ইনবক্সের কোড পড়ুন: ইনবক্সের যাচাইয়ের সময় হলে সিস্টেম সরবরাহকারীর কাছে যাচাই করে, তারপর পাওয়া প্রতিটি কোড ফেরত দেয়, পুরোনোটি আগে — সবচেয়ে নতুন কোডটি codes[]-এর শেষে।
অপেক্ষার সময় প্রতি 5–10 সেকেন্ডে পোল করুন (এর চেয়ে ঘন ঘন কল করলে শুধু সংরক্ষিত ডেটা ফেরত আসে — polledAt বদলায় না)। যে ইমেইল থেকে কোড আলাদা করা যায় না সেগুলো isRaw: true-সহ code-এ হুবহু ফেরত আসে। মেয়াদ শেষ হওয়া ব্যাচও সংরক্ষিত কোড ফেরত দেয়, তবে আর যাচাই করা হয় না।
প্যারামিটার
নামধরনআবশ্যকবিবরণ
idstringহ্যাঁব্যাচ আইডি
mailIdnumberহ্যাঁইনবক্স আইডি (mails[].id)
poll0 | 1না0 = শুধু সংরক্ষিত কোড পড়ুন, সরবরাহকারীর কাছে যাচাই করবেন না (ডিফল্ট 1)
উদাহরণ
# অপেক্ষার সময় প্রতি 5–10 সেকেন্ডে আবার কল করুন; সবচেয়ে নতুন কোডটি codes[]-এর শেষে থাকে
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
    }
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, NOT_FOUND, RATE_LIMITED

Buy 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
WarehouseEach account deliversDefault priceStock
1gm_cookieemail · password · cookies · inboxUrl (inbox link) · inboxJsonUrl (emails as JSON) · twoFaUrl (2FA link — just the 6 digits)3,300 VNDA number — published by the source, refreshed every minute. The source checks that accounts are live at purchase time, so you may get fewer — the shortfall is refunded (a partial order; warehouse 99: the rest goes to the next warehouse)
2gm_loginemail · password · loginUrl (quick login link — open it in a desktop browser) · otpUrl (Vinted OTP link — when delivers lists it)6,000 VNDA REFERENCE number from a source sharing the same stock (refreshed every minute; null when it cannot be read) — may be off by a few, never blocks a purchase; a shortfall becomes a partial order with the rest refunded
99As the warehouse that supplied each account (items[].warehouse)Price of the cheapest warehouse on sale (auto.priceVnd)Buys the cheapest warehouse first (auto.order); if it runs out midway the rest goes to the next warehouse at that warehouse's price (the difference is charged — refunded instead if your balance is short); every warehouse out ⇒ MAILSHOP_OUT_OF_STOCK, nothing charged
গুদাম 1-এর অ্যাকাউন্টে লগইন (রিকভারি ইমেইল নেই)
  • গুদাম 1 (gm_cookie)-এর অ্যাকাউন্ট আসে রিকভারি ইমেইল ছাড়া — আপনি পান ইমেইল, পাসওয়ার্ড, কুকিজ আর ইনবক্স লিংক (inboxUrl / inboxJsonUrl), এর বেশি কিছু নয়।
  • লগইনের প্রস্তাবিত উপায়: কুকিজ ইমপোর্ট করুন (cookies, JSON) ব্রাউজারে — কুকি-ইমপোর্ট এক্সটেনশন দিয়ে বা আপনার antidetect ব্রাউজারের কুকি ইমপোর্ট দিয়ে — তারপর Gmail খুলুন: সেশন আগে থেকেই লগইন করা থাকে, সাধারণত পাসওয়ার্ড বা যাচাই চাওয়া হয় না।
  • শুধু কোড বা ইমেইল দরকার? সেগুলো inboxUrl (ওয়েব পেজ) বা inboxJsonUrl (JSON) দিয়ে পড়ুন — API key বা Google লগইন লাগে না।
  • নতুন ডিভাইস বা IP থেকে পাসওয়ার্ড দিয়ে লগইন করলে Google যাচাই চাইতে পারে (রিকভারি ইমেইল, ফোন বা কোড) — এই অ্যাকাউন্টগুলোর কাছে তা পার হওয়ার কিছু নেই, তাই কুকিজ বা ইনবক্স লিংক ব্যবহার করুন।
  • আবার বিক্রি করছেন? আপনার গ্রাহকদের কুকিজ এবং ইনবক্স লিংক দুটোই দিন — .txt ডাউনলোডে (GET /v1/mail-shop/orders/{id}/download) এক লাইনে email|password|cookies|inboxUrl থাকে — আর তাদের বলুন পাসওয়ার্ড নয়, কুকিজ দিয়ে লগইন করতে।
  • গুদাম 2 (gm_login)-এর অ্যাকাউন্ট এর বদলে একটি কুইক লগইন লিংক (loginUrl) সহ আসে — লগইন করতে এটি কম্পিউটারের ব্রাউজারে খুলুন।
3 steps
  1. 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, call GET /v1/mail-shop/quote.
  2. Buy: POST /v1/mail-shop/orders with {"warehouse": 1 | 2 | 99, "quantity": N} + header Idempotency-Key (a new UUID per purchase). The response is the order, usually already completed with items[].
  3. Get the accounts: read items[] (table below) or download the TXT GET /v1/mail-shop/orders/{id}/download. status = pending ⇒ poll GET /v1/mail-shop/orders/{id} every 5 seconds until completed / partial / failed.
# 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..."
Fields of an account (items[])
ফিল্ডধরনবিবরণ
lineNonumberPosition in the order (1, 2, …) — the {lineNo} of the inbox endpoints
warehouse1 | 2Warehouse that supplied this account
emailstringGmail address
passwordstringPassword
recoverystring?Recovery email — only when the source provides one; warehouse 1 (gm_cookie) accounts have NONE (sign in with the cookies, see the sign-in notes above)
cookiesstring | nullWarehouse 1: login cookies (JSON)
inboxUrlstring | nullWarehouse 1: inbox page without an API key (https://otpgmail.net/mail/{code}); null = link turned off
inboxJsonUrlstring | nullWarehouse 1: the same link + ?json ⇒ emails as JSON (section below)
twoFaUrlstring | nullWarehouse 1: the 2FA LINK (https://otpgmail.net/2fa/{code} — same code + expiry as inboxUrl): GET / open it in a browser ⇒ JUST the 6-digit 2FA code (section below). null = link turned off. The .txt file has this column when downloaded with ?twofa=1
inboxLinkExpiresAtnumber | nullWarehouse 1: when the link expires (unix seconds); null = no limit
loginUrlstring | nullWarehouse 2: quick login link
otpUrlstring | nullWarehouse 2: the account's Vinted OTP link — open it in a browser to see the code, ?json ⇒ JSON (section below). null = this account has no link
otpService"vinted" | nullWarehouse 2: the service of otpUrl
rawLinestringThe whole account on one line (cookies compacted) — copy it as is
Read the inbox as JSON (inboxJsonUrl)
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"
# 424819
Order statuses
অবস্থাবিবরণ
pendingBeing delivered — accounts that arrived are in items[]; poll again in 5 seconds
completedFully delivered. Final.
partialDelivered short — the shortfall was refunded (refundVnd; message = the reason + the source's own words when it gave any). Final.
failedNothing delivered — fully refunded (message as above). Final.
refundedRefunded by an admin (refundVnd). Final.
Rules
  • Money: chargedVnd = Σ route[].quantity × unitPriceVnd (a 99 order split across warehouses ⇒ two legs in route). Shortfalls are refunded automatically (refundVnd). Delivered accounts are not refunded — the only warranty is the warehouse's terms (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 ⇒ 429 RATE_LIMITED.
  • Common errors: MAILSHOP_OUT_OF_STOCK 409 (details.stock = how many you can buy now) · MAILSHOP_QTY_LIMIT 400 (details.max) · INSUFFICIENT_BALANCE 402 · MAILSHOP_DISABLED 503 (warehouse / section paused) · MAILSHOP_SUPPLIER_ERROR 502 (the source refused at once — a failed order was recorded and refunded, details.orderId) · VALIDATION_ERROR 400 (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.
উদাহরণ
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
      ]
    }
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED
GET/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.
প্যারামিটার
নামধরনআবশ্যকবিবরণ
warehouse1 | 2 | 99নাMail-shop warehouse: 1 = email + password + cookies + inbox link · 2 = email + password + login link · 99 = automatic, cheapest first. Send warehouse OR product
productstringনাInstead of warehouse: gm_cookie (= warehouse 1) | gm_login (= warehouse 2)
quantitynumberনাNumber of accounts (default 1)
উদাহরণ
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
      }
    ]
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, VALIDATION_ERROR, MAILSHOP_PRODUCT_NOT_FOUND
POST/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.
প্যারামিটার
নামধরনআবশ্যকবিবরণ
warehouse1 | 2 | 99নাMail-shop warehouse: 1 = email + password + cookies + inbox link · 2 = email + password + login link · 99 = automatic, cheapest first. Send warehouse OR product
productstringনাInstead of warehouse: gm_cookie (= warehouse 1) | gm_login (= warehouse 2)
quantitynumberনাNumber of accounts (default 1)
Idempotency-Keystringহ্যাঁHeader: a new UUID for every new purchase — reuse it only to retry that same purchase
উদাহরণ
# Idempotency-Key বাধ্যতামূলক: প্রতিটি কেনার জন্য নতুন UUID — শুধু টাইমআউটের পর রিট্রাই করতে একই key আবার ব্যবহার করুন
# 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"
      }
    ]
  }
}
সম্ভাব্য ত্রুটি: 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, MAINTENANCE
GET/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).
প্যারামিটার
নামধরনআবশ্যকবিবরণ
pagenumberনাPage (default 1)
pageSizenumberনাOrders per page (default 20, max 100)
উদাহরণ
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
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED
GET/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.
প্যারামিটার
নামধরনআবশ্যকবিবরণ
idstringহ্যাঁOrder ID (data.id returned by the purchase)
উদাহরণ
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"
      }
    ]
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, NOT_FOUND
GET/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.
প্যারামিটার
নামধরনআবশ্যকবিবরণ
idstringহ্যাঁOrder ID (data.id returned by the purchase)
উদাহরণ
curl "https://otpgmail.net/v1/mail-shop/orders/ORDER_ID/download" \
  -H "Authorization: Bearer og_xxx..." \
  -o mail-ORDER_ID.txt
নমুনা রেসপন্স
email|password|cookies|inboxUrl
[email protected]|Pw7Xq!k3d|[{"domain":".google.com","name":"SID","value":"g.a000…"}]|https://otpgmail.net/mail/Q7xK2mP9vL4tR8wN3cB6yH1d
সম্ভাব্য ত্রুটি: UNAUTHORIZED, NOT_FOUND, VALIDATION_ERROR
GET/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.
প্যারামিটার
নামধরনআবশ্যকবিবরণ
idstringহ্যাঁOrder ID (data.id returned by the purchase)
lineNonumberহ্যাঁAccount number within the order (items[].lineNo)
maxnumberনাNumber of latest emails: 10 (default), 20, 50, 100 or 200
উদাহরণ
# 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
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, NOT_FOUND, VALIDATION_ERROR, RATE_LIMITED, PROVIDER_ERROR
GET/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.
প্যারামিটার
নামধরনআবশ্যকবিবরণ
idstringহ্যাঁOrder ID (data.id returned by the purchase)
lineNonumberহ্যাঁAccount number within the order (items[].lineNo)
উদাহরণ
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
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, NOT_FOUND, VALIDATION_ERROR, RATE_LIMITED, PROVIDER_ERROR
GET/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).
প্যারামিটার
নামধরনআবশ্যকবিবরণ
idstringহ্যাঁOrder ID (data.id returned by the purchase)
lineNonumberহ্যাঁAccount number within the order (items[].lineNo)
উদাহরণ
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
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, NOT_FOUND, VALIDATION_ERROR, RATE_LIMITED, PROVIDER_ERROR

অর্ডারের লাইফসাইকেল

অবস্থাবিবরণ
কোডের অপেক্ষায়নতুন তৈরি অর্ডার, প্রথম কোডের অপেক্ষায়। প্রতি 3–5 সেকেন্ডে GET /v1/orders/{id} পোল করুন।
সম্পন্নপ্রথম কোড এসে গেছে — অবস্থা সঙ্গে সঙ্গে বদলায়। সার্ভিস একাধিক কোড পাঠালে আরও কোড আসতে পারে (অর্ডারের মেয়াদের মধ্যে বাড়তি চার্জ নেই; সীমা ও সময় গুদাম অনুযায়ী); পোল করতে থাকুন, প্রতিটি নতুন কোড otp[]-এর শেষে দেখা যাবে।
বাতিল100% ফেরত। এটা ঘটে যখন আপনি /cancel কল করেন (কোড আসার আগে), অথবা codeDeadlineAt (সর্বোচ্চ 25 মিনিট) পর্যন্ত কোনো কোড আসে না।
গুরুত্বপূর্ণ নোট:
  • অর্ডার waiting_code অবস্থায় থাকার সময় প্রতি 3–5 সেকেন্ডে GET /v1/orders/{id} পোল করুন, যাতে কোড দ্রুত ধরতে পারেন।
  • প্রথম কোড আসামাত্র অবস্থা সঙ্গে সঙ্গে completed হয়ে যায়।
  • codeDeadlineAt-এর মধ্যে কোড না এলে (সর্বোচ্চ 25 মিনিট; গুদাম 2: 20 মিনিট; গুদাম 4-এর কিছু উৎসে কম) ⇒ সিস্টেম অর্ডার বাতিল করে 100% ফেরত দেয় (status = cancelled)।
  • otp[] অ্যারে পুরোনোটি আগে, নতুনটি শেষে সাজানো। সর্বশেষ কোড পড়ুন otp[otp.length - 1] দিয়ে (Python: otp[-1])।
  • একটি completed অর্ডার নিজে থেকেই কোড পেতে থাকে: GET /v1/orders/{id} পোল করতে থাকুন, প্রতিটি নতুন কোড otp[]-এর শেষে দেখা যাবে। সার্ভিস একাধিক কোড পাঠালে অর্ডারের মেয়াদের মধ্যে অতিরিক্ত কোডের জন্য কিছুই লাগে না; সীমা ও সময় ভাড়ার আগেই দেখানো হয় (offers[]-এর maxCodes ও fee; গুদাম 1-এ শেষ কোডের পর ইনবক্স সাধারণত প্রায় 25 মিনিট খোলা থাকে)। স্পষ্টভাবে আরেকটি কোড চাইতে (যেমন সাইন-আপের পর লগইন): POST /v1/orders/{id}/next-code — যেকোনো গুদামে কাজ করে, আর ফি নেয় শুধু গুদাম 2, তার বিনামূল্যের সময়ের বাইরে।
  • সার্ভিস প্রতি ইনবক্সে একটিই কোড দিলে otp[] ওই কোডেই থেমে যায়। রেসপন্স স্বাভাবিক থাকে, কোনো ত্রুটি আসে না — কখন পোল বন্ধ করবেন তা আপনিই ঠিক করেন।
  • otp[].code সাধারণত একটি ছোট কোড (অঙ্ক / অক্ষর) বা একটি লিংক। যে ইমেল থেকে কোড বের করা যায়নি (স্বাগত ইমেল, নিউজলেটার, অস্বাভাবিক ফরম্যাটের কোড…) সেটি otp[].code-এ হুবহু (HTML বা টেক্সট) দেওয়া হয় — 80 অক্ষরের বেশি লম্বা হলে, লাইন-ব্রেক থাকলে বা HTML হলে পুরো ইমেল ধরে নিন এবং কোড বা লিংক নিজেই খুঁজে নিন।
  • POST /v1/orders সরবরাহকারীর ইনবক্স বরাদ্দের জন্য অপেক্ষা করে, তাই সাধারণত ~0.3 সেকেন্ড লাগে, তবে ব্যস্ত সময়ে (বিরল) 10 সেকেন্ড পর্যন্ত লাগতে পারে। 5 সেকেন্ড পরে ছেড়ে দিয়ে আগেভাগে রিট্রাই না করে ক্লায়েন্টের টাইমআউট ≈ 15 সেকেন্ড রাখুন — আর রিট্রাই করলে একই Idempotency-Key ব্যবহার করুন।
  • যে অর্ডার কোড পেয়ে গেছে তা বাতিল করা যায় না বা রিফান্ড হয় না — বাতিলের কল ORDER_NOT_CANCELLABLE ফেরত দেয়।
  • @icloud.com ইনবক্স ভাড়া নিতে অর্ডার তৈরির সময় "domain": "icloud.com" পাঠান (Gmail-এর জন্য বাদ দিন; বিদ্যমান বটগুলোর কিছু বদলাতে হবে না)। সার্ভিসটি iCloud সমর্থন না করলে, বা iCloud সাময়িকভাবে বন্ধ থাকলে DOMAIN_UNAVAILABLE পাবেন — Gmail-এ বদলালে ভাড়া সঙ্গে সঙ্গে হয়ে যায়। লাইফসাইকেল, বাতিল ও রিফান্ডের নিয়ম এবং কোড পড়ার পদ্ধতি Gmail-এর সঙ্গে হুবহু এক।
  • নিজস্ব ইনভেন্টরির সার্ভিস (provider = "inventory", যেমন Cointiply — GET /v1/services দেখুন) শুধু iCloud-এ; প্রতিটি ইমেইল otp[].code-এ একটি লিংক হিসেবে আসে, সঙ্গে kind, label এবং text-এ ইমেইলের পূর্ণ লেখা। একটি অর্ডার rules.windowMinutes মিনিটের মধ্যে (windowEndsAt পর্যন্ত) সর্বোচ্চ rules.maxCodesটি ইমেইল পায়, বাতিল করা যায় না (ORDER_NOT_CANCELLABLE), এবং ইমেইল ছাড়া সময় শেষ হলে রিফান্ড ছাড়াই cancelled হয়ে যায়। একই ইনবক্সে পেতে থাকতে canRerent true থাকা অবস্থায় POST /v1/orders/{id}/rerent কল করুন (দাম: rerentPriceVnd)। অন্য সব সার্ভিস / অর্ডারে provider = "standard" — 2026-10-24 থেকে provider-এর মাত্র দুটি মান: "standard" | "inventory" (আসল ওয়্যারহাউস warehouse-এ); শুধু "inventory"-এর সাথে তুলনা করুন।
  • গুদাম 2-এর অর্ডার (warehouse = 2): fee.freeHours ঘণ্টা কোড বিনামূল্যে; বিনামূল্যের সময় শেষ হলে নতুন কোড আসা বন্ধ হয় — আরেকটি সময় খুলতে confirmFee = true দিয়ে POST /v1/orders/{id}/next-code কল করুন (nextCodeFee.feePriceVnd দিয়ে), সর্বোচ্চ nextCodeFee.hardUntil পর্যন্ত। সাধারণ সার্ভিসের গুদাম 3 অর্ডার: 24 ঘণ্টা বিনামূল্যে কোড, কোড আসার আগে বাতিল করা যায়, তারপর rerent ব্যবহার করুন। গুদাম 4-এর অর্ডার: অর্ডার পড়লেই নতুন কোড otp[]-এ চলে আসে, rentExpiresAt পর্যন্ত বিনামূল্যে; একটিমাত্র কোড দেওয়া উৎসে প্রথম কোডের পর nextCodeBlockReason = "max_codes" হয়।
  • একসাথে অনেক অর্ডার? POST /v1/orders/status দিয়ে প্রতি কলে সর্বোচ্চ 100টি পোল করুন — এক কলে অনেক অর্ডারের স্ট্যাটাস দেখুন।

রেট লিমিট

সীমা প্রতিটি API key-এর জন্য প্রযোজ্য (কোনো অ্যাকাউন্টের নিজস্ব সীমা থাকতে পারে; না থাকলে সাইটের ডিফল্ট সীমা প্রযোজ্য):
  • 100টি অনুরোধ/সেকেন্ড — কয়েক সেকেন্ডের ছোট বার্স্ট
  • 3000টি অনুরোধ/মিনিট — প্রতি মিনিটের মোট ট্রাফিক
কোনো সীমা ছাড়ালে HTTP 429 ফেরত আসে, সঙ্গে Retry-After: <seconds> হেডার এবং বডি {"success":false,"error":{"code":"RATE_LIMITED",...}}। আবার চেষ্টা করার আগে হেডারে দেওয়া সংখ্যক সেকেন্ড অপেক্ষা করুন। ত্রুটির বডিতে একই সংখ্যক সেকেন্ড error.retryAfterSec-এও থাকে (error.retryable = true সহ)।

এরর কোড

প্রতিটি ত্রুটির গঠন একই: {"success":false,"error":{"code":"...","message":"...","retryable":false,"retryAfterSec":null}}
2026-10-17 থেকে /v1-এর প্রতিটি ত্রুটিতে error.retryable ও error.retryAfterSec-ও থাকে (যোগ করা ফিল্ড — বিদ্যমান ক্লায়েন্টে কিছু বদলাতে হবে না; details অপরিবর্তিত)। retryable = true ⇒ একই কল পরে সফল হতে পারে: retryAfterSec সেকেন্ড (≥ 1 পূর্ণসংখ্যা) অপেক্ষা করে আবার পাঠান — স্টক নেই / ইনবক্স নেই / গুদাম সাময়িক বন্ধ / সরবরাহকারীর ত্রুটি ⇒ 5 সেকেন্ড; 429 RATE_LIMITED ⇒ Retry-After হেডার; একই Idempotency-Key-এর প্রথম অনুরোধ এখনও চলাকালে 409 DUPLICATE_REQUEST ⇒ 2 সেকেন্ড। retryable = false (retryAfterSec = null) ⇒ কারণটি ঠিক না করা পর্যন্ত (ব্যালেন্স, অপেক্ষমাণ অর্ডারের সীমা, প্যারামিটার, API key…) আবার কল করে লাভ নেই। POST /v1/orders-এর partial.reason-ও একই নিয়ম মানে। স্টক শেষ বোঝানো 409 উত্তর (OUT_OF_STOCK, WAREHOUSE_UNAVAILABLE, ALL_WAREHOUSES_EXHAUSTED) পেলে আবার চেষ্টার আগে পুরো retryAfterSec সেকেন্ড অপেক্ষা করুন — আগে চেষ্টা করলে সাধারণত একই উত্তর আসে — এবং আবার ভাড়া নেওয়ার আগে GET /v1/services-এ stock / offers[].stock দেখুন; আগে থেকে নেওয়া অর্ডারগুলো বারবার জিজ্ঞেস না করে webhook দিয়ে অনুসরণ করুন।
ত্রুটির উত্তরের নমুনা
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
  }
}
এরর কোডHTTPretryable · retryAfterSecঅর্থ
UNAUTHORIZED401false · nullAPI key ভুল বা নেই।
ACCOUNT_LOCKED403false · nullঅ্যাকাউন্টটি লক করা — এর key দিয়ে করা প্রতিটি অনুরোধ প্রত্যাখ্যাত হয়। সাপোর্টে যোগাযোগ করুন।
FORBIDDEN403false · nullভাড়া প্রক্রিয়ার সময় অ্যাকাউন্টটি আর সক্রিয় ছিল না (এইমাত্র লক করা হয়েছে)।
NOT_FOUND404false · nullআপনার অ্যাকাউন্টে এই ID-র কোনো অর্ডার / ব্যাচ / ইনবক্স নেই (অন্য অ্যাকাউন্টের অর্ডারেও 404 আসে)।
VALIDATION_ERROR400false · nullঅনুরোধের প্যারামিটার সঠিক নয় (ভুল টাইপ, আবশ্যক ফিল্ড নেই ইত্যাদি)।
INSUFFICIENT_BALANCE402false · nullঅর্ডারের দাম দেওয়ার মতো ব্যালেন্স অ্যাকাউন্টে নেই।
SERVICE_DISABLED409false · nullসার্ভিস কোডটি নেই অথবা সার্ভিস সাময়িকভাবে বন্ধ। সঠিক কোড GET /v1/services থেকে নিন।
OUT_OF_STOCK409true · 5অনুরোধের সময় সার্ভিসটিতে (নির্বাচিত ইনবক্সের ধরনে) কোনো ইনবক্স নেই।
DOMAIN_UNAVAILABLE409false · nullসার্ভিসটি নির্বাচিত ইনবক্সের ধরন দেয় না — iCloud এখনও সমর্থিত নয় / সাময়িকভাবে বন্ধ, অথবা সার্ভিসটিতে gmx.com ইনবক্স নেই। Gmail ভাড়া নিতে domain "gmail.com" পাঠান (বা ফিল্ডটি বাদ দিন)।
WAREHOUSE_UNAVAILABLE409true · 5 / falseবেছে নেওয়া গুদাম এই সার্ভিস/ইনবক্সের ধরন বিক্রি করে না, বন্ধ আছে বা এইমাত্র স্টক শেষ হয়েছে। offers[] থেকে অন্য একটি গুদাম বেছে নিন, অথবা সিস্টেম যেন স্টক আছে এমন একটি বেছে নেয় সেজন্য warehouse = 99 পাঠান। সেই গুদাম (বা এই সার্ভিস বিক্রি করা সব গুদাম) আপনার অ্যাকাউন্টের জন্য উপলব্ধ না হলে retryable = false — আবার কল করে লাভ নেই, অন্য গুদাম ব্যবহার করুন।
ALL_WAREHOUSES_EXHAUSTED409true · 5শুধু warehouse = 99-এ: স্টক আছে এমন প্রতিটি গুদাম (সবচেয়ে কম দামেরটি আগে) চেষ্টা করা হয়েছে এবং সবগুলোর স্টক শেষ বা ব্যর্থ — অথবা প্রতিটি গুদাম শূন্য স্টক জানাচ্ছে। কিছুই কাটা হয়নি; পরে আবার চেষ্টা করুন।
NO_MAILS_AVAILABLE503true · 5সরবরাহকারীর কাছে এই সার্ভিসের জন্য আর কোনো ইনবক্স নেই (সাময়িকভাবে শেষ)।
QUANTITY_EXCEEDED400false · nullquantity প্রতি অনুরোধের সর্বোচ্চ সীমা (বর্তমানে 200) ছাড়িয়ে গেছে।
WAITING_LIMIT_REACHED429false · nullএকসাথে অনেক বেশি অর্ডার কোডের অপেক্ষায় আছে (আপনার অ্যাকাউন্টে একসাথে waiting_code অর্ডারের সীমা পেরিয়ে গেছে) — কয়েকটি শেষ হওয়া পর্যন্ত অপেক্ষা করে আবার ভাড়া নিন।
ORDER_NOT_CANCELLABLE409false · nullঅর্ডারটি বাতিল করা যায় না — এতে হয়তো কোড এসে গেছে, অথবা এটি আর waiting_code অবস্থায় নেই। অর্ডারে এখনও প্রথম কোড না এলে next-code-ও এই কোড ফেরত দেয়।
RERENT_NOT_AVAILABLE409false · nullঅর্ডারটি আবার ভাড়া নেওয়া যায় না। গুদাম 3: এটি ইনবক্সের সর্বশেষ অর্ডার নয়, ইনবক্সটি আর আপনার অ্যাকাউন্টে বরাদ্দ নেই, অথবা আগের গ্রহণ-সময় এখনও চালু আছে। গুদাম 2: অর্ডার এখনও বন্ধ হয়নি (এখনও কোড পেতে পারে — next-code ব্যবহার করুন), আবার ভাড়ার জন্য খুব পুরোনো, ইমেইলে আরেকটি চালু অর্ডার আছে, অথবা সার্ভিস থেমে আছে। গুদাম 1 ও 4-এ আবার ভাড়া নেই।
RERENT_EMAIL_BANNED409false · nullগুদাম 2-এ আবার ভাড়া: সরবরাহকারী জানায় সার্ভিস ইমেইলটি লক করেছে (email banned) — আবার ভাড়া নেওয়া যাবে না; টাকা কাটা হয় না।
RERENT_MAIL_GONE409false · nullগুদাম 2-এ আবার ভাড়া: সরবরাহকারী এই ইমেইল আর খুলতে পারে না — নতুন একটি ভাড়া নিন; টাকা কাটা হয় না।
NEXT_CODE_FEE_CONFIRM409false · nullগুদাম-2 অর্ডারের বিনামূল্যের সময় শেষ — ফি (nextCodeFee.feePriceVnd) দিতে confirmFee: true দিয়ে আবার next-code কল করুন। কিছুই কাটা হয়নি।
EMAIL_BANNED409false · nullসার্ভিস ইমেইলটি লক করেছে (সরবরাহকারী email banned জানায়) — এতে আর কোড আসতে পারে না; নতুন একটি ভাড়া নিন। 2026-10-02 থেকে (আগে ORDER_EXPIRED, একই HTTP 409)।
ORDER_EXPIRED409false · nullঅর্ডারে আর কোড আসতে পারে না — এর সময়সীমা পেরিয়ে গেছে (rentExpiresAt / nextCodeFee.hardUntil), সরবরাহকারী ইনবক্স বন্ধ করেছে, কোডের সীমা (maxCodes) পূর্ণ হয়েছে, অথবা সার্ভিসে "পরের কোড" নেই। কারণ order.nextCodeBlockReason-এ আছে।
RATE_LIMITED429true · = Retry-Afterআপনার API key-তে প্রতি সেকেন্ডে 100টির বেশি বা প্রতি মিনিটে 3000টির বেশি অনুরোধ (কোনো অ্যাকাউন্টের নিজস্ব সীমা থাকতে পারে)। Retry-After হেডার জানায় কত সেকেন্ড অপেক্ষা করতে হবে। গুদাম 2-এ অ্যাকাউন্টটি গত 60 মিনিটে গুদাম 2-এর অনেক অর্ডার কোড ছাড়াই বাতিল করলে এবং খুব কম অর্ডারে কোড এলে POST /v1/orders ও /rerent-ও এই কোড ফেরত দেয় — বাতিলের হার না কমা পর্যন্ত গুদাম 2 থেকে ভাড়া স্থগিত থাকে ("warehouse": 99-ও এই ত্রুটি নিয়ে সেখানে থেমে যায় — ততক্ষণ অন্য গুদাম বেছে নিন)। Facebook / Instagram (fb, fbb, ig) এর আওতামুক্ত।
DUPLICATE_REQUEST409true · 2 / falseএই Idempotency-Key আগেই অন্য payload বা endpoint-এর সাথে ব্যবহৃত হয়েছে, অথবা এই key-র প্রথম অনুরোধটি এখনও চলছে (একটু পরে আবার চেষ্টা করুন)। অন্য অর্ডার তৈরি করতে নতুন key বানান।
PROVIDER_ERROR502true · 5ইনবক্স সরবরাহকারীর দিক থেকে ত্রুটি (সাময়িক — কয়েক সেকেন্ড পরে আবার চেষ্টা করুন)।
MAINTENANCE503false · nullসিস্টেমে রক্ষণাবেক্ষণ চলছে — অর্ডার তৈরি ও বাতিল সাময়িকভাবে বন্ধ।
MAILSHOP_DISABLED503false · nullস্বল্পস্থায়ী Gmail কেনা সাময়িকভাবে বন্ধ, অথবা এই প্রোডাক্টটি বন্ধ করা আছে — পরে আবার চেষ্টা করুন।
MAILSHOP_PRODUCT_NOT_FOUND404false · nullএই কোডের কোনো প্রোডাক্ট নেই — সঠিক কোড দেখে নিন: GET /v1/mail-shop/products.
MAILSHOP_OUT_OF_STOCK409false · nullবর্তমান দামে এই সংখ্যার জন্য যথেষ্ট স্টক নেই — error.details.stock = এখন কয়টি অ্যাকাউন্ট কেনা যায়।
MAILSHOP_QTY_LIMIT400false · nullquantity প্রতি অর্ডারের সর্বোচ্চ সীমা (বর্তমানে 500) ছাড়িয়ে গেছে — error.details.max দেখুন।
MAILSHOP_SUPPLIER_ERROR502false · nullউৎস সঙ্গে সঙ্গে কেনাটি প্রত্যাখ্যান করেছে: একটি failed অর্ডার রেকর্ড করে টাকা ফেরত দেওয়া হয়েছে (error.details.orderId)। পরে নতুন একটি Idempotency-Key দিয়ে আবার চেষ্টা করুন।
INTERNAL500false · nullঅপ্রত্যাশিত সার্ভার ত্রুটি — পরে আবার চেষ্টা করুন; বারবার হলে সাপোর্টে যোগাযোগ করুন।

ওয়েবহুক (পুশ নোটিফিকেশন)

প্রতিটি অ্যাকাউন্টে একটি URL রেজিস্টার করুন; কোনো অর্ডারে নতুন কোড এলে (order.code) বা সেটি বাতিল / রিফান্ড হলে (order.cancelled) আমরা সঙ্গে সঙ্গে সেই URL-এ একটি স্বাক্ষরিত JSON ইভেন্ট POST করি। ওয়েবহুক ঐচ্ছিক এবং আপনার অ্যাকাউন্টের সব অর্ডারে প্রযোজ্য (ওয়েব ও API)। ডেলিভারি সর্বোচ্চ চেষ্টার ভিত্তিতে — ব্যাকআপ হিসেবে ধীর পোলিং চালু রাখুন (নিচে দেখুন)।
3 ধাপে সেটআপ
  1. আপনার URL (চাইলে events-ও) দিয়ে PUT /v1/webhook — data.secret (64টি হেক্স অক্ষর) সংরক্ষণ করুন: প্রতিটি ডেলিভারি যাচাইয়ের জন্য এটি দরকার। আবার PUT ডাকলেও একই secret থাকে।
  2. POST /v1/webhook/test — আমরা সঙ্গে সঙ্গে একটি ping ইভেন্ট পাঠাই এবং আপনার সার্ভার কী উত্তর দিল তা ফেরত দিই (ok, httpStatus, error)।
  3. আপনার এন্ডপয়েন্টকে 5 সেকেন্ডের মধ্যে যেকোনো 2xx দিয়ে উত্তর দিতে হবে — আগে উত্তর দিন, পরে ইভেন্ট প্রসেস করুন। অন্য সবকিছু (3xx, 4xx, 5xx, টাইমআউট, সংযোগ ত্রুটি) ব্যর্থ হিসেবে গণ্য হয় এবং আবার পাঠানো হয়।
URL অবশ্যই http:// বা https:// দিয়ে শুরু হবে (বৈধ সার্টিফিকেটসহ) এবং ইন্টারনেট থেকে পৌঁছানো যাবে: localhost, প্রাইভেট, link-local, multicast ও সংরক্ষিত ঠিকানা (10.x, 172.16–31.x, 192.168.x, 169.254.x, fc00::/7, fe80::/10…) এবং OTPGmail-এর নিজস্ব সার্ভার VALIDATION_ERROR দিয়ে প্রত্যাখ্যাত হয়। প্রতিটি ডেলিভারির আগে হোস্ট নাম আবার রিজলভ করা হয়। রিডাইরেক্ট অনুসরণ করা হয় না — চূড়ান্ত URL রেজিস্টার করুন।
অনুরোধের ফরম্যাট
প্রতিটি ডেলিভারি হলো আপনার URL-এ JSON বডি (UTF-8) ও এই হেডারগুলোসহ একটি HTTP POST:
হেডারমান
Content-Typeapplication/json
User-AgentOTPGmail-Webhook/1
X-OTPGmail-Eventইভেন্টের নাম: order.code, order.cancelled বা ping
X-OTPGmail-Deliveryইভেন্টের অনন্য ID (UUID) — বডির deliveryId-এর সমান এবং প্রতিটি পুনঃচেষ্টায় অপরিবর্তিত
X-OTPGmail-Timestampএই চেষ্টায় স্বাক্ষর করার Unix সময় (সেকেন্ড) — বডির sentAt-এর সমান
X-OTPGmail-Signaturesha256= + আপনার secret-কে কী ধরে timestamp + "." + কাঁচা বডি-র ওপর HMAC-SHA256-এর ছোট হাতের hex
স্বাক্ষর যাচাই করুন
আপনার secret-কে কী ধরে X-OTPGmail-Timestamp + . + অনুরোধের কাঁচা বডির ওপর HMAC-SHA256 ছোট হাতের hex-এ হিসাব করুন এবং sha256=-এর পরের মানের সঙ্গে ধ্রুব-সময়ে তুলনা করুন। কী হলো 64 অক্ষরের secret স্ট্রিংটি নিজেই (এর UTF-8 বাইট — hex ডিকোড করবেন না)। কাঁচা বাইটই ব্যবহার করুন: JSON পার্স করে আবার সিরিয়ালাইজ করলে বাইট বদলে যায়। আপনার ঘড়ি থেকে 5 মিনিটের বেশি সরে থাকা timestamp প্রত্যাখ্যান করুন (রিপ্লে সুরক্ষা)।
রিসিভারের উদাহরণ (Python ও Node কেবল স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করে; curl কমান্ড আপনার নিজের রিসিভারে সঠিকভাবে স্বাক্ষরিত একটি টেস্ট ডেলিভারি পাঠায়)
# লোকাল টেস্ট: আপনার রিসিভারে হুবহু আমাদের মতো স্বাক্ষরিত একটি ডেলিভারি পাঠান
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"
ইভেন্ট
ইভেন্টকখন পাঠানো হয়
order.codeঅর্ডারে নতুন কোড এসেছে — প্রতি কোডে একটি ইভেন্ট, একই ইনবক্সের পরের কোডগুলোসহ। code হলো নতুন কোড; otp ওই মুহূর্ত পর্যন্ত অর্ডারের সব কোড পুরোনো থেকে নতুন ক্রমে দেয় (GET /v1/orders/{id}-এর মতো; বডি 64 KB ছাড়ালে কেবল নতুন কোড)।
order.cancelledঅর্ডার বাতিল বা রিফান্ড হয়েছে — প্রতি অর্ডারে একবার: সময়সীমার আগে কোনো কোড আসেনি (timeout), আপনি বাতিল করেছেন (user), কোনো অ্যাডমিন বাতিল করেছেন (admin), অথবা ওয়্যারহাউস ব্যর্থ হওয়ায় রিফান্ড হয়েছে (provider)। refundVnd = আপনার ব্যালান্সে ফেরত দেওয়া VND (সেবার নিয়মে রিফান্ড না থাকলে 0)।
pingকেবল POST /v1/webhook/test থেকে।
ইভেন্টের ফিল্ড
ফিল্ডধরনবিবরণ
eventstringইভেন্টের নাম (X-OTPGmail-Event হেডারেও থাকে)
deliveryIdstringইভেন্টের অনন্য ID (UUID, = X-OTPGmail-Delivery) — ডুপ্লিকেট এড়াতে সংরক্ষণ করুন
sentAtnumberএই চেষ্টার Unix সময় (= X-OTPGmail-Timestamp)
orderIdstringঅর্ডার ID — GET /v1/orders/{id}-এর মতোই
servicestringসেবার কোড
warehouse1 | 2 | 3 | 4 | nullইনবক্স দেওয়া ওয়্যারহাউস 1–4; অর্ডার কখনো ইনবক্স না পেলে null
domainstringইনবক্সের ডোমেইন: gmail.com, icloud.com বা gmx.com
emailstring | nullভাড়া নেওয়া ইনবক্সের ঠিকানা
codestringকেবল order.code: নতুন কোড — এটি লিংক বা পুরো ইমেইলও হতে পারে, otp[].code-এর মতো
receivedAtnumberকেবল order.code: কোড আসার Unix সময়
statusstringওই মুহূর্তে অর্ডারের অবস্থা: order.code-এর জন্য completed, order.cancelled-এর জন্য cancelled (আগে থেকেই কোড আছে এমন অর্ডার অ্যাডমিন রিফান্ড করলে সেটি completed-ই থাকে)
otparrayকেবল order.code: ওই মুহূর্ত পর্যন্ত সব কোড, [{code, receivedAt}], পুরোনো থেকে নতুন
reasonstringকেবল order.cancelled: timeout | user | admin | provider
refundVndnumberকেবল order.cancelled: আপনার ব্যালান্সে রিফান্ড হওয়া VND (0 = রিফান্ড নেই)
উদাহরণ বডি — order.code
{
  "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
    }
  ]
}
উদাহরণ বডি — 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"
}
উদাহরণ বডি — ping
{
  "event": "ping",
  "deliveryId": "3c9a1e7f-2b4d-4c6e-8f0a-5d7b9c1e3a2f",
  "sentAt": 1760700000
}
পুনঃচেষ্টা, বিরতি ও ইতিহাস
  • ব্যর্থ ডেলিভারি 10 সেকেন্ড, 1 মিনিট, 5 মিনিট, 30 মিনিট ও 2 ঘণ্টা পরে আবার পাঠানো হয় (5টি পুনঃচেষ্টা); শেষটিও ব্যর্থ হলে ইভেন্ট বাদ দেওয়া হয় (failed)।
  • পরপর 50টি ব্যর্থ চেষ্টা (সব ইভেন্ট মিলিয়ে) ওয়েবহুক থামিয়ে দেয়: GET /v1/webhook-এ pausedAt দেখা যায়, কিছুই পাঠানো হয় না এবং নতুন ইভেন্ট সারিতে যোগ হয় না।
  • আবার চালু করতে: আবার PUT /v1/webhook ডাকুন (একই URL চলবে) অথবা একটি সফল POST /v1/webhook/test করুন — এরপর সারিতে অপেক্ষমাণ ইভেন্টগুলো পাঠানো হয়।
  • GET /v1/webhook/deliveries সর্বশেষ 100টি ডেলিভারি তাদের অবস্থা, চেষ্টার সংখ্যা ও শেষ ত্রুটিসহ দেখায়; ইতিহাস 7 দিন রাখা হয়।
ডুপ্লিকেট ও ক্রম
একই ইভেন্ট একাধিকবার আসতে পারে (যেমন আপনার 2xx উত্তর হারিয়ে গেলে) এবং ইভেন্ট ক্রমের বাইরে আসতে পারে (কয়েকটি সমান্তরালে পাঠানো হয়)। প্রসেস করা deliveryId সংরক্ষণ করুন এবং পুনরাবৃত্তি বাদ দিন; কোনো অর্ডারের ক্ষেত্রে আসার ক্রমের বদলে তার সবচেয়ে নতুন ডেটার (otp, status) ওপর ভরসা করুন।
ব্যাকআপ হিসেবে পোলিং চালু রাখুন
ওয়েবহুক দেরিতে আসতে পারে (পুনঃচেষ্টা) বা হারিয়ে যেতে পারে (ওয়েবহুক থামানো, আপনার সার্ভার বন্ধ)। ধীর পোলিং চালু রাখুন — যেমন যেসব অর্ডার এখনো waiting_code-এ আছে সেগুলোর জন্য প্রতি 30–60 সেকেন্ডে GET /v1/orders/{id} — এবং API থেকে পাওয়া অর্ডার অবজেক্টকেই সঠিক উৎস ধরুন।
PUT/v1/webhook
আপনার অ্যাকাউন্টের ওয়েবহুক রেজিস্টার বা আপডেট করে। প্রথম কল এটি তৈরি করে এবং নতুন secret ফেরত দেয়; পরের কলগুলো secret একই রাখে, ওয়েবহুক আবার চালু করে এবং থেমে থাকলে আবার শুরু করে। events না পাঠালে: নতুন ওয়েবহুকে দুটি ইভেন্টই, বিদ্যমানটিতে কোনো পরিবর্তন নেই। URL অবশ্যই পাবলিক ঠিকানা হতে হবে — না হলে 400 VALIDATION_ERROR (কারণ error.details.problem-এ)।
প্যারামিটার
নামধরনআবশ্যকবিবরণ
urlstringহ্যাঁআপনার এন্ডপয়েন্ট (http:// বা https://, পাবলিক ঠিকানা, সর্বোচ্চ 2048 অক্ষর)
eventsstring[]নাকোন ইভেন্ট পাঠাবেন: ["order.code", "order.cancelled"] (ডিফল্ট দুটিই)
উদাহরণ
# data.secret সংরক্ষণ করুন — প্রতিটি ডেলিভারি যাচাইয়ে এটি দরকার
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
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, VALIDATION_ERROR
GET/v1/webhook
আপনার অ্যাকাউন্টের ওয়েবহুক, secret, pausedAt ও consecutiveFailures সহ। কোনো ওয়েবহুক রেজিস্টার না থাকলে data হয় null।
উদাহরণ
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
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED
DELETE/v1/webhook
ওয়েবহুক মুছে দেয়; সারিতে অপেক্ষমাণ ইভেন্টগুলো বাদ যায়। সবসময় 200 — মোছার কিছু না থাকলে data.deleted হয় false।
উদাহরণ
curl -X DELETE "https://otpgmail.net/v1/webhook" \
  -H "Authorization: Bearer og_xxx..."
নমুনা রেসপন্স
{
  "success": true,
  "data": {
    "deleted": true
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED
POST/v1/webhook/test
এখনই আপনার URL-এ একটি ping ইভেন্ট পাঠায় এবং ফলাফল জানায়: ok (আপনার সার্ভার 2xx দিয়েছে), httpStatus, durationMs, error। সফল টেস্ট থেমে থাকা ওয়েবহুক আবার চালু করে। প্রতি মিনিটে সর্বোচ্চ 10টি টেস্ট; পুরো সিস্টেমে ওয়েবহুক বন্ধ থাকলে 503 MAINTENANCE।
উদাহরণ
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"
  }
}
আপনার সার্ভার 2xx না দিলে 200 উত্তর
{
  "success": true,
  "data": {
    "ok": false,
    "httpStatus": 500,
    "durationMs": 88,
    "error": "HTTP 500",
    "deliveryId": "7d2b9f4e-1c6a-4e3b-8d5f-0a9c2e7b1f4d"
  }
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED, NOT_FOUND, RATE_LIMITED, MAINTENANCE
GET/v1/webhook/deliveries
সর্বশেষ ডেলিভারি, নতুনগুলো আগে (7 দিন রাখা হয়): status = queued (পরের চেষ্টা nextAt-এ) | delivered | failed | paused, সঙ্গে attempts, lastHttpStatus ও lastError। ইভেন্টের বডি ফেরত দেওয়া হয় না।
প্যারামিটার
নামধরনআবশ্যকবিবরণ
limitnumberনাডেলিভারির সংখ্যা, 1–100 (ডিফল্ট 100)
উদাহরণ
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
    }
  ]
}
সম্ভাব্য ত্রুটি: UNAUTHORIZED