WELIFE Docs Swagger Admin Web

WP-PAY-01 · SMS OTP · Expo refresh

2026-07-24

Payments (MoMo / VNPay / MOCK)

Endpoint Auth Mô tả
GET /payments/providers public Trạng thái MOCK/MOMO/VNPAY
POST /payments/init JWT Tạo PaymentIntent + payUrl
POST /payments/momo/init JWT Force MoMo
GET /payments/momo/return public Redirect return → credit ví
POST /payments/momo/ipn public IPN
POST /payments/vnpay/init JWT Force VNPay
GET /payments/vnpay/return public Verify hash → credit ví
GET /payments/mock/pay?orderId= public Local giả lập thanh toán
POST /payments/mock/confirm public Smoke confirm
GET /payments/status/:orderId JWT Trạng thái
GET /payments/history JWT Lịch sử
POST /payments/refund JWT Chưa IMP (WP-PAY-02)

Local: PAYMENTS_MOCK=true (mặc định non-prod). Prod: điền MOMO_* / VNPAY_*, PAYMENTS_MOCK=false, tắt ALLOW_INTERNAL_WALLET_CREDIT.

Credit ví idempotent: pay:{paymentId} trên wallet_ledger.

SMS OTP

SMS_PROVIDER Hành vi
console (default local) Log OTP · trả devOtp non-prod
esms eSMS VN SendMultipleMessage_V4_post_json · ESMS_API_KEY + ESMS_SECRET_KEY
http POST SMS_HTTP_URL JSON { phone, message, code } + SMS_HTTP_API_KEY
twilio Twilio Messages API

Production: bắt buộc esms | http | twilio (không OTP_DEV_CODE).

Live wire (stop-gate): cần credential thật từ eSMS / Twilio — không commit secret. Trên VPS:

# /opt/welife/api/.env
SMS_PROVIDER=esms
ESMS_API_KEY=...
ESMS_SECRET_KEY=...
ESMS_BRAND_NAME=WELIFE   # brand đã duyệt trên eSMS
# bỏ SMS_HTTP_URL placeholder nếu chuyển từ http → esms
docker compose --profile full up -d --force-recreate api

Expo refresh-on-401

mobile / driver / partner src/services/api.ts:

  1. Request 401
  2. Single-flight POST /auth/refresh
  3. Lưu token mới (SecureStore)
  4. Retry 1 lần
  5. Fail → clear tokens

Skip refresh cho /auth/otp/*, /auth/refresh, /auth/logout.

Smoke local

# OTP
curl -X POST .../auth/otp/send -d '{"phone":"+84901234567","surface":"CONSUMER"}'
# → smsProvider=console, otpBackend=redis

# Pay MOCK
# 1) OTP verify → Bearer
# 2) POST /payments/init {"amount":10000,"provider":"MOCK"}
# 3) POST /payments/mock/confirm {"orderId":"..."}
# → wallet credit