SP
ShoppePay Gateway
DOCS • sppg.ioi.my.id
DOMAIN RESMI — sppg.ioi.my.id

ShoppePay Partner
API Gateway Docs

Gateway 100% Stateless (tanpa database & tanpa polling) untuk verifikasi mutasi ShopeePay, validasi token, riwayat bulanan, dan pembuatan Dynamic QRIS EMVCo dengan CRC16-CCITT recalculation — polling hanya saat checkout aktif sehingga aman dari rate-limit.

Lihat API Reference → Copy cURL Example BASE: https://sppg.ioi.my.id
LATENCY
<120 ms
in-memory QRIS
STATELESS
100%
no DB, no cron
UPTIME CHECK
/api/health
public endpoint
LIVE REQUEST
200 OK
# Base URL
https://sppg.ioi.my.id
# Create QRIS
curl -X POST https://sppg.ioi.my.id/create-qris \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"amount":15000}'
Health
GET /api/health
no auth
Verify
POST /check-payment
X-API-Key
⚠️ Unofficial Gateway: Tidak berafiliasi dengan Shopee. Token disimpan di .env server Anda sendiri & hanya dikirim ke shopeepay.shopee.co.id. Read-only, tidak mengubah saldo.

Introduction

Gateway ini membaca data dari ShopeePay Partner Portal menggunakan sesi akun merchant Anda (token internal B:...) — mirip cara kerja extension browser. Desain stateless / client-polled: gateway hanya hit Shopee saat ada pembeli aktif di halaman checkout (poll tiap 10–15 detik), sehingga trafik nol ketika toko sepi dan terhindar dari blokir rate-limit.

Zero-Database
Tanpa SQLite/Postgres. Kebal restart di Render/Railway/Vercel.
Dynamic QRIS Injector
Parsing TLV, inject Tag 54 (amount), recalc CRC16-CCITT in-memory.
Anti Double Claim
In-memory Map transactionId (24 jam) + dedup di DB toko utama.
SEQUENCE — Client-Polled Stateless
Toko → Gateway: POST /create-qris {amount} (X-API-Key)
Gateway: parse QRIS_STATIC, inject amount, calc CRC → return qris_url + expiry (15 menit)
Toko → Pelanggan: tampilkan QR
Pelanggan → Shopee: scan & bayar
loop tiap 10-15s selama checkout aktif:
  Toko → Gateway: POST /check-payment {amount, startTime}
  Gateway → Shopee: POST /get-transaction-list (range startTime→now)
  Shopee → Gateway: list transaksi
  if paid → Gateway → Shopee: get-transaction-detail → return {paid:true, transaction{...issuer: Seabank/OVO/DANA/BCA...}}
  else → {paid:false}

Base URL & Domain

PRODUCTION BASE URL
https://sppg.ioi.my.id Semua endpoint di bawah ini relatif terhadap base ini. Contoh: https://sppg.ioi.my.id/api/health
Health: GET https://sppg.ioi.my.id/api/health (public)
Create QRIS: POST https://sppg.ioi.my.id/create-qris
Check: POST https://sppg.ioi.my.id/check-payment

Authentication

Semua endpoint sensitif wajib kirim API Key via header X-API-Key: <API_KEY> atau query ?api_key=<API_KEY>. Multi-store: tambahkan X-Shopee-Token: B:... per-request untuk override token .env.

HEADERS
X-API-Key: shopee-secret-key-2026
X-Shopee-Token: B:EWznmVD... (opsional)
Content-Type: application/json
ENV (.env)
SHOPEE_TOKEN="B:EWznmVDI//r..."
API_KEY="shopee-secret-key-2026"
PORT=4000
QRIS_STATIC="000201010211266..."
TELEGRAM_BOT_TOKEN="..."
TELEGRAM_CHAT_ID="..."

Quick Start — 5 Menit

# 1) Health (no auth)
curl https://sppg.ioi.my.id/api/health

# 2) Create QRIS — dynamic amount
curl -X POST https://sppg.ioi.my.id/create-qris \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount":15000}'

# 3) Poll verify — startTime = unix detik saat create QRIS
curl -X POST https://sppg.ioi.my.id/check-payment \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount":15000,"startTime": 1715660000}'
Tips anti double claim (kolisi nominal kembar): Tambahkan kode unik Rp1–99 di amount (mis. 50000 → 50027). Simpan transactionId dari /check-payment ke DB toko & tolak jika sudah pernah dipakai. Gateway juga dedup in-memory 24 jam.
POST

/create-qris — Generate Dynamic QRIS

Parsing QRIS statis (TLV), inject nominal ke Tag 54, hitung ulang CRC16-CCITT in-memory. Return URL redirect QR + expiry 15 menit.

Request
POST https://sppg.ioi.my.id/create-qris
Header: X-API-Key: YOUR_API_KEY
{
  "amount": 15000
}
Response 200
{
  "success": true,
  "data": {
    "qris_url": "https://sppg.ioi.my.id/qr/f3f050d4",
    "amount": 15000,
    "expires_at": "2026-07-15 09:29:25",
    "expires_in": "15 menit"
  }
}
curl -X POST https://sppg.ioi.my.id/create-qris \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount":15000}'
GET

/qr/:id — Tampilkan QR Image

Redirect QR image untuk pelanggan. Tanpa auth (publik). Contoh: https://sppg.ioi.my.id/qr/f3f050d4 → image/png QRIS.

GET https://sppg.ioi.my.id/qr/:id — img src langsung di halaman checkout.
POST

/check-payment — Verifikasi Pembayaran (Stateless)

Polling tiap 10–15 detik hanya selama checkout aktif. Gateway hit /get-transaction-list dengan rentang startTime → now, lalu /get-transaction-detail untuk issuer (Seabank/OVO/DANA/BCA/Mandiri). In-memory dedup mencegah double claim.

Request
POST https://sppg.ioi.my.id/check-payment
X-API-Key: ... (+ X-Shopee-Token opsional)
{
  "amount": 1008,
  "startTime": 1784050000
}
startTime = unix detik saat QR dibuat (Math.floor(Date.now()/1000)).
Response — Paid
{
  "success": true,
  "paid": true,
  "transaction": {
    "transactionId": "264693445089687719",
    "amount": 1008,
    "status": "success",
    "time": "2026-07-15 00:42:21",
    "issuer": "Seabank"
  }
}
Jika belum bayar: {"success":true,"paid":false}
GET

/transactions — Mutasi Terbaru

curl -H "X-API-Key: YOUR_API_KEY" https://sppg.ioi.my.id/transactions

{
  "success": true,
  "total_amount": "409.662",
  "data": {
    "transactions": [
      { "amount": 9600, "status": "success", "time": "2026-07-13 14:12:41", "issuer": "OVO" }
    ]
  }
}
GET

/transactions/all — Mutasi Sebulan Penuh

Mengambil seluruh mutasi dalam sebulan (paginasi internal ke Shopee). Gunakan X-Shopee-Token untuk filter per-merchant.

curl -H "X-API-Key: YOUR_API_KEY" https://sppg.ioi.my.id/transactions/all
GET

/api/logs — In-Memory Logs (100 terakhir)

curl -H "X-API-Key: YOUR_API_KEY" https://sppg.ioi.my.id/api/logs
// → { "logs": [ { "timestamp": "...", "level": "info", "message": "..." } ] }
GET

/token-status — Cek Validitas Token

curl -H "X-API-Key: YOUR_API_KEY" https://sppg.ioi.my.id/token-status

{"success":true,"data":{"token_status":"valid","message":"Token is working"}}
// jika mati → token_status: invalid + Telegram alert (cek tiap 5 menit)
POST

/update-token — Perbarui Token Live

Update tanpa restart. Ambil token baru dari DevTools → Network → get-transaction-list → payload → metadata → token (B:...).

curl -X POST https://sppg.ioi.my.id/update-token \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"token":"B:NEW_TOKEN_DI_SINI"}'
GET

/api/health — Health Check (public)

curl https://sppg.ioi.my.id/api/health
{"success":true,"message":"ShopeePay API Service is running","timestamp":"2026-07-15T02:14:10.091Z"}
Buka Health →

Errors & Codes

Status / CodeArtiSolusi
200 OKSuksesBaca data response
401 UnauthorizedAPI Key salah/kosongCek header X-API-Key
400 Bad RequestParam salahCek JSON body
200020 (Shopee)Token mati/invalidPOST /update-token + cek Telegram
EADDRINUSEPort bentrokKill proses di PORT 4000

Deployment — sppg.ioi.my.id (VPS + Nginx + PM2)

Domain sudah pointing ke VPS ini (38.47.92.20). Gateway jalan di 127.0.0.1:4000 via PM2, Nginx reverse-proxy + SSL Let’s Encrypt.

PM2
pm2 start server.js --name sppg-gateway -- --port 4000
pm2 save
pm2 startup
pm2 logs sppg-gateway
Nginx (sppg.ioi.my.id.conf)
server_name sppg.ioi.my.id;
location / { root /root/shoppepay-api-gateway/docs; try_files $uri $uri/ =404; }
location ~ ^/(api/health|create-qris|check-payment|transactions|token-status|update-token|qr|api/logs) {
  proxy_pass http://127.0.0.1:4000;
}
Cara ambil SHOPEE_TOKEN: Login https://partner.shopee.co.id → F12 → Network → filter Fetch/XHR → refresh → cari get-transaction-list → Payload → data → metadata → token (awalan B:).