MeiSIM Dealer API

REST API for authorized dealers to programmatically order eSIMs, top up SIMs, and manage their wallet.

Base URLhttps://meisimusa.com
Content typeapplication/json
API versionv1

Quick start

# 1. Get your API key (one-time)
curl -X POST https://meisimusa.com/dealer/send-otp \
  -H 'content-type: application/json' \
  -d '{"email":"you@yourcompany.com"}'

# Check email for the 6-digit code, then:
curl -X POST https://meisimusa.com/dealer/verify-otp \
  -H 'content-type: application/json' \
  -d '{"email":"you@yourcompany.com","code":"123456"}'
# → returns { "verified": true, "apiKey": "..." }

# 2. Use the API key on every request
curl https://meisimusa.com/api/v1/me \
  -H 'x-dealer-key: YOUR_API_KEY'

Authentication

Two equivalent auth methods. Use either on any endpoint.

Option A — API Key (recommended for backend integration)

Issued via the OTP flow below. Passed in the request header:

x-dealer-key: YOUR_API_KEY

The key does not expire. Treat it like a password.

Option B — JWT (for portal/UI integrations)

Issued via the password-login flow. Passed in the standard Bearer header:

Authorization: Bearer YOUR_JWT

JWT expires after 12 hours. Re-login to refresh.

Auth flow — OTP login

POST/dealer/send-otp

Send a 6-digit code to your email.

{ "email": "you@yourcompany.com" }

Response: { "sent": true }. Rate limit: 5 sends per 15 min per IP. Code expires in 5 minutes; max 5 verification attempts.

POST/dealer/verify-otp

Verify the code and receive your API key.

{ "email": "you@yourcompany.com", "code": "123456" }

Response:

{ "verified": true, "apiKey": "dk_..." }

Rate limit: 10 verifications per 15 min per IP.

Auth flow — password login (returns JWT)

POST/dealer/auth/set-password

One-time password setup. Requires x-dealer-key from the OTP flow.

{
  "email": "you@yourcompany.com",
  "password": "min-8-chars"
}

Response: { "ok": true }.

POST/dealer/auth/login

Email + password → JWT.

{ "email": "you@yourcompany.com", "password": "..." }

Response:

{
  "ok": true,
  "token": "eyJhbGc...",
  "expiresAt": "2026-05-06T12:00:00.000Z",
  "dealer": { "id": "...", "email": "...", "company": "..." }
}

Rate limit: 8 attempts per 15 min per IP.

eSIM endpoints

GET/api/v1/esim/countries

List supported countries. Returns the upstream country catalog.

POST/api/v1/esim/bundles

List bundles for a country/region.

{
  "countryISO":   "JP",            // optional, ISO 3166-1 alpha-2
  "countryName":  "Japan",         // optional, alternative to ISO
  "region":       "Asia",          // optional
  "pageNumber":   1,               // optional, default 1
  "pageSize":     20               // optional, default 20, max 100
}

Response: paginated bundle list with each bundle's name, data allowance, validity, and price.

POST/api/v1/esim/order

Order an eSIM for an end customer.

{
  "bundleName":        "esim_5gb_30days_jp",  // required, from /bundles
  "customerReference": "ORDER-12345",         // optional, your tracking id
  "emailAddress":      "end-customer@x.com",  // optional, where the QR is sent
  "qrToCustomer":      true                    // optional, default false
}

Response: { "Status": "Success", "Iccid": "...", "QrCode": "...", ... } (upstream-format). The order is logged in your dealer history.

POST/api/v1/esim/details

Get activation status and data usage.

{ "iccid": "894900..." }

Returns activation state, data used vs allowance, expiry.

POST/api/v1/esim/revoke

Deactivate an eSIM upstream and update your dealer order history.

{ "iccid": "894900..." }

Rate limit: 10 per minute per dealer.

Top-up endpoints

For recharging existing SIMs (not new eSIMs).

GET/api/v1/topup/networks

List networks eligible for top-up.

POST/api/v1/topup/confirm

Validate a target SIM exists on a network. Use this before recharge to avoid charging a non-existent SIM.

{
  "networkName":     "Vodafone-UK",
  "contactNumber":   "+447700900000",   // either contactNumber
  "simSerialNumber": "894400..."         // OR simSerialNumber
}

POST/api/v1/topup/recharge

Execute a top-up recharge.

{
  "networkName":       "Vodafone-UK",       // required
  "contactNumber":     "+447700900000",     // OR simSerialNumber
  "simSerialNumber":   "894400...",
  "topUpValue":        20,                  // required, currency depends on network
  "bundleValue":       null,                // optional bundle add-on
  "bundleProductCode": null
}

Account & history

GET/api/v1/me

Whoami.

{ "id": "...", "company_name": "...", "email": "...", "status": "approved" }

GET/api/v1/orders

Recent orders. Returns up to the last 100, newest first.

[
  {
    "id": "...",
    "order_type": "esim" | "topup",
    "bundle_name": "esim_5gb_30days_jp",
    "customer_reference": "ORDER-12345",
    "email_address": "end-customer@x.com",
    "iccid": "894900...",
    "amount": 6.50,
    "status": "completed",
    "created_at": "2026-05-05T12:34:56Z"
  }
]

Wallet

GET/dealer/wallet

Wallet balance and recent transactions.

{
  "ok": true,
  "balance": 245.30,
  "markupPct": 15,
  "resendFee": 1.00,
  "company": "...",
  "email": "...",
  "transactions": [
    {
      "id": "...",
      "created_at": "2026-05-05T12:34:56Z",
      "type": "debit" | "topup",
      "amount_usd": -6.50,
      "balance_after_usd": 245.30,
      "description": "...",
      "stripe_session_id": null,
      "related_order_id": "..."
    }
  ]
}

GET/dealer/statement

CSV export. Default range: last 90 days.

GET /dealer/statement?from=2026-04-01&to=2026-05-01

Returns CSV with columns: Date, Type, Amount USD, Balance after USD, Description, Order ID, Stripe session.

POST/dealer/topup

Create Stripe checkout session for wallet top-up.

{ "amountUsd": 100 }

amountUsd must be between $50 and $10,000. Response: { ok, checkoutUrl, netAmt, grossAmt, fee }. Redirect user to checkoutUrl. Rate limit: 5/min.

POST/dealer/topup-intent

Create Stripe PaymentIntent for embedded checkout.

{ "amountUsd": 100 }

Response: { ok, clientSecret, publishableKey, netAmt, grossAmt, fee }. Use Stripe.js with clientSecret. Rate limit: 10/min.

GET/dealer/topup/preview?net=100

Preview Stripe fee. Response: { ok, net, gross, fee }.

Order from your wallet

POST/dealer/order

Alternative to /api/v1/esim/order — debits your wallet at your dealer price.

{
  "productId":     "p3:att-prepaid-30",      // required
  "customerEmail": "end@x.com",                // required
  "customerName":  "Jane Doe",                 // required
  "quantity":      1,                          // optional, 1–20
  "language":      "en",                       // optional
  "imei":          "359123456789012",          // required for US prepaid (15 digits)
  "eid":           "89001012...",              // required for US prepaid (hex)
  "address": {
    "first_name":     "Jane",
    "last_name":      "Doe",
    "address_line_1": "123 Main St",
    "city":           "Phoenix",
    "state":          "AZ",
    "zip_code":       "85001",
    "phone":          "+15555550100"
  }
}

Response:

{
  "ok": true,
  "orderId": "...",
  "shortId": "MM-AB12CD",
  "unitPriceUsd": 25.00,
  "totalUsd": 25.00,
  "newBalance": 220.30
}

Returns 402 Payment Required if balance is insufficient.

POST/dealer/resend-email/:orderId

Resend an eSIM activation email. Charges the resend fee (~$1).

{ "email": "alternate@x.com" }

Body is optional — omit email to resend to the original address.

POST/dealer/replace/:orderId

Issue a replacement eSIM at the original product's current price. Charged from your wallet. Returns 402 if insufficient balance.

Errors

All errors return JSON:

{ "error": "Invalid request", "message": "amountUsd must be between 50 and 10000" }
StatusMeaning
400Bad request — missing or malformed fields
401Unauthorized — missing or invalid x-dealer-key / JWT
402Payment required — insufficient wallet balance
403Forbidden — account not approved or suspended
404Not found — order, product, or dealer doesn't exist
429Rate limit exceeded
500Server error — try again, contact support if persistent

Rate limits (per dealer unless noted)

Endpoint groupLimit
Read operations (/api/v1/me, /api/v1/orders, /api/v1/esim/countries, /api/v1/esim/bundles, /api/v1/esim/details, /api/v1/topup/networks)60 / min
Order operations (/api/v1/esim/order, /api/v1/topup/confirm, /api/v1/topup/recharge, /dealer/order)30 / min
Revocations (/api/v1/esim/revoke)10 / min
Wallet top-ups (/dealer/topup, /dealer/topup-intent)5–10 / min
OTP send5 / 15 min per IP
OTP verify10 / 15 min per IP
Password login8 / 15 min per IP

Rate-limit window is sliding; on 429, wait the indicated period and retry.

Code samples

JavaScript / Node.js

const API = 'https://meisimusa.com';
const KEY = process.env.MEISIM_DEALER_KEY;

async function orderEsim(bundleName, customerEmail) {
  const r = await fetch(`${API}/api/v1/esim/order`, {
    method: 'POST',
    headers: {
      'x-dealer-key': KEY,
      'content-type': 'application/json',
    },
    body: JSON.stringify({
      bundleName,
      emailAddress: customerEmail,
      qrToCustomer: true,
    }),
  });
  if (!r.ok) throw new Error(`HTTP ${r.status}: ${await r.text()}`);
  return r.json();
}

Python

import os, requests

API = 'https://meisimusa.com'
KEY = os.environ['MEISIM_DEALER_KEY']

def order_esim(bundle_name, customer_email):
    r = requests.post(
        f'{API}/api/v1/esim/order',
        headers={'x-dealer-key': KEY},
        json={
            'bundleName': bundle_name,
            'emailAddress': customer_email,
            'qrToCustomer': True,
        },
        timeout=30,
    )
    r.raise_for_status()
    return r.json()

curl

curl -X POST https://meisimusa.com/api/v1/esim/order \
  -H "x-dealer-key: $MEISIM_DEALER_KEY" \
  -H 'content-type: application/json' \
  -d '{"bundleName":"esim_5gb_30days_jp","emailAddress":"end@x.com","qrToCustomer":true}'

For dealer onboarding, account questions, or technical support, contact your account manager directly.
Document version: v1.0 — 2026-05-05