MrHiWash API analysis

Rant : wasted on ~11+ spin-only orders(no water wastage) and accidently deleted my account just to capture user.cancelAccount api, now i cant use washer !!

are you ready? lets get you started

alt text alt text

Base URL: https://www.mrhiwash.com/GlobalWashCallApi/
Protocol: HTTPS GET POST
App ID: hl7c87b100fc2143a
App Secret: 759fcd66ad674c80a250753bd7fd5fcb
API Version: 1.6


HTTP Methods

All requests use the params as query string for GET or form-encoded body for POST.

Endpoint GET POST
common/user/queryCountryList.api
common/user/getLatestVersion.api
common/user/restoreAccount.api
common/user/login.api
common/user/register.api
common/user/requestVerifyCode.api
common/user/checkVerifyCode.api
common/user/checkPhoneOrEmail.api
common/user/retrievePassword.api
common/laundry/getNearbyLaundryList.api
common/laundry/getLaundryDetail.api
common/laundry/getLaundryDeviceList.api
common/laundry/getDeviceInfo.api
common/appAd/getAppAdInfo.api
common/system/analysisURL.api
common/common/quaryShowInvitation.api
common/common/quaryShowModule.api
common/common/queryNewFocusList.api
api/user/getProfile.api
api/user/logout.api
api/user/updateUserEmail.api
api/user/updatePwd.api
api/user/updateUserName.api
api/user/setMessageNotification.api
api/user/updateAvatarImage.api
api/user/getCouponList.api
api/user/getCouponCount.api
api/user/cancelAccount.api
api/message/queryAllAppMessage.api
api/message/queryAppMessageById.api
api/order/orderDevice.api
api/order/reserve.api
api/order/getUserOrderList.api
api/order/cancelOrder.api
api/order/getOrderDetail.api
api/order/sendVerifyCodeToDevice.api
api/order/vertify.api
api/order/getDeviceEndRuntimeByOrderId.api
api/order/startCleanProgram.api
api/order/orderWithCoupon.api
api/order/resetDevice.api
api/order/startDevice.api
api/pay/getPrepay.api
api/pay/queryOrderPaySuccess.api
api/alipay/alipayTradeQuery.api

Request Structure

Parameter Description Notes
charset UTF-8 Fixed
country US Fixed (observed)
tokenId Auth token Empty string for unauthenticated APIs
method API method name e.g. user.login
sign SHA1withRSA signature Signed over encrypted bizcontent bytes
format JSON Fixed
timeZone Client timezone e.g. GMT+05:30
language Language code e.g. en
nonce Request nonce Base64(MD5("appId=<APP_ID>&appSecret=<APP_SECRET>&timestamp=<TIMESTAMP>"))
version 1.6 Fixed
bizcontent Encrypted payload RSA encrypted JSON, Base64 encoded
appId hl7c87b100fc2143a Fixed
timestamp GMT+8 timestamp Format: yyyyMMddHHmmss

bizcontent Generation

zsh
payload_json   = JSON.stringify(api_specific_params)   // compact, no spaces
encrypted      = RSA_encrypt(payload_json, server_public_key)  // RSA/ECB/PKCS1Padding, 117-byte blocks
bizcontent     = Base64(encrypted)
sign           = Base64(SHA1withRSA(encrypted_bytes, client_private_key))

Keys

Server Public Key (encrypt bizcontent):

zsh
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCg0xP7ICNOo5QW2HFsiIt4PTFxD3aVys64GZWpX
EzHROwxyqe2f1Jzbumof9oCSsBkCbY7FMFlYvwMNnFN+PwmbTxmiBCuYrcbLkRPHZmxSCVCt46e1
PH7AsuVd6FbupyAAoPGAuFZA4yP3ksa+GkRN8+kKif1Asg/f3E+EWc4gwIDAQAB

Client APK Private Key (sign requests + decrypt responses):

zsh
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKp3BAOIv8nLompKBdCdJiZcNmeE5
5642ION/RVpNej806OKkDtQTHW1ALACAZ3pXYNaNiimLJV9oEa2tdg6wDS5fUAiV4h6ehVpxh+Hm
OzQRuIKSKjL/TjKYW/lpocK0VuSsDTCMY8VpI5fmFS1fHpkYMDmAXtODT/UBaPXvn9TAgMBAAEC
gYA8LYfdN4l9U8Yif79NxiyRnjwWj3S1M8w7pQSTanD9r0OHmIMSbWaQpzV27T5k4N2CYXZ9Iyz
aGV9bl2Ta0OLJJAfVn3h+LA98EcPV264HXbHfZUcZynDRw86oJt/v+4+4mMllz2w6/R9YD0/eN0
w543zWiSHsyULBY6mAnMDAAQJBAPygcgewFnpjQhpp+2prLAKOwjsvyICI1o5QUUrriV5BTTAr+m
na4yNrDVe8Tvz3RQjub1VJNKwxFmg9WEamNQECQQCsvbdctf0afnshVJ78NM0REb0eVtm6KhGhVE
MwxVxDZ3fOfSltvOK5om501BU4lPOtsh6C/n7Op/6BnWd4S1BTAkEA5KWDD5o8fgEgby/FMghWCO
qUuWUCH/O53YysRxbvebO43QSw3OYT9paJuQLiqupSPUcw1Qww9Dhpg2ciYq9EAQJAXZYDK3Vlh
N8Vcn9YCyfIGgFURoWjPBriplbyeA/U5qe93t8sfMmixBPeZ+km/hqk0mv339xlcyzM1AglMKUNB
QJBAJUdcV1Bg48PTbKTu2z1t+Hbu7Qx9ByPQSv/dNn2Pw+zYfnG7gzFTTgzInA4EOWzjBdclIZZ
Lo/oGZL9ph5Nv+s=

Alttext

no kity i haven't leaked my keys, every apk file have this embedded in it

Examples in python
python
def encrypt(payload: dict) -> str:
    data = json.dumps(payload, separators=(',', ':')).encode('utf-8')
    cipher = PKCS1_v1_5.new(PUBLIC_KEY)
    encrypted = bytearray()
    for i in range(0, len(data), 117):
        encrypted.extend(cipher.encrypt(data[i:i+117]))
    return base64.b64encode(bytes(encrypted)).decode('utf-8')

def sign(encrypted_b64: str) -> str:
    h = SHA.new(base64.b64decode(encrypted_b64))
    return base64.b64encode(pkcs1_15.new(PRIVATE_KEY).sign(h)).decode('utf-8')

def nonce(ts: str) -> str:
    s = f"appId={APP_ID}&appSecret={APP_SECRET}&timestamp={ts}"
    return base64.b64encode(hashlib.md5(s.encode()).digest()).decode('utf-8')

def decrypt(encrypted_b64: str) -> str:
    data = base64.b64decode(encrypted_b64)
    cipher = PKCS1_v1_5.new(PRIVATE_KEY)
    out = bytearray()
    for i in range(0, len(data), 128):
        chunk = cipher.decrypt(data[i:i+128], None)
        if chunk:
            out.extend(chunk)
    return out.decode('utf-8')

Response Structure

Success:

json
{
  "retCode": "00000",
  "retInfo": "operation success",
  "retData": "<Base64 RSA-encrypted response>",
  "sysTime": 1771131098219
}

Error:

json
{
  "retCode": "<code>",
  "retInfo": "<message>",
  "retData": null,
  "sysTime": 1771131098219
}

retData decryption: RSA_decrypt(Base64_decode(retData), client_private_key) → JSON string

Known error codes:

Code Meaning
00000 Success
10050 Timestamp expired (>60s old)
10081 Invalid request / version mismatch

Order Status Codes

Status Meaning
102 Created / transitioning (transient state observed between order creation and 109)
103 Running (machine active)
104 Completed (paid, run finished) — actualPrice field present in order object
105 Cancelled
106 Completed
109 Pending payment
111 Verified / awaiting payment confirmation (after order.vertify succeeds, before Paytm payment completes)

Phone Number Format

plaintext
[4-digit zero-padded country code][phone number]

Examples: India (91) → 0091 + 9876543210 = 00919876543210

Use user.queryCountryList to get country codes.


Authentication

tokenId is returned by user.login. It is account-specific and persistent (does not expire per session). Pass empty string "" for unauthenticated APIs.


APIs


User


user.queryCountryList

Path: /common/user/queryCountryList.api
Auth: No
Payload: {}

Response (decrypted, array):

json
[
  {
    "code": "IN",
    "enname": "India",
    "id": 900077,
    "regexinfo": "^[0-9]*$",
    "regionCode": "0091",
    "zhname": "भारत"
  }
]

regexinfo: regex pattern for validating phone number input for this region
regionCode: 4-digit zero-padded dialling prefix, used as the phone number prefix in all API calls


user.login

Path: /common/user/login.api
Auth: No (tokenId = "")

Payload:

json
{
  "deviceType": "2",
  "password": "<plain_text_password>",
  "phoneNumber": "<formatted_phone>",
  "verifyCode": "",
  "osVersion": "51",
  "type": "2",
  "channelId": "",
  "androidUserId": "null"
}

All fields required. verifyCode is empty string for password-based login.

Response (decrypted):

json
{
  "avatarURL": "",
  "email": "user@example.com",
  "phoneNumber": "00911234567890",
  "tokenId": "<base64_token>",
  "userId": "<user_id>",
  "userName": "<display_name>"
}

user.cancelAccount

Path: /api/user/cancelAccount.api
Auth: Yes

Payload: {}

No response captured. Called as the final step of the account deletion flow, after OTP verification via user.checkVerifyCode (type "3").

Account deletion flow:

plaintext
1. user.requestVerifyCode  {"phoneNumber": "<phone>", "type": "3"}  → null
2. user.checkVerifyCode    {"phoneNumber": "<phone>", "verifyCode": "<otp>", "type": "3"}
3. user.cancelAccount      {}

Note on re-registration after deletion: Attempting to register with the same phone number immediately after cancelAccount results in repeated failures at the checkVerifyCoderegister step (observed: 3 consecutive retries). The user.checkPhoneOrEmail call made during registration will flag the number as already in use if the server has not yet processed the deletion. There is an observed delay before the server allows re-registration with the same credentials.


user.restoreAccount

Path: Unknown
Auth: Unknown
Payload: Unknown


user.getProfile

Path: /api/user/getProfile.api
Auth: Yes
Payload: {}

Response (decrypted):

json
{
  "avatar": "",
  "desensitizationMailNumber": "s****m@gmail.com",
  "email": "user@example.com",
  "hotLine": "",
  "isHavepwd": true,
  "isReceiveMessage": "T",
  "phoneNumber": "00911234567890",
  "userId": "<user_id>",
  "userName": "<display_name>"
}

isHavepwd: boolean, whether the account has a password set
isReceiveMessage: "T" = notifications enabled, "F" = disabled
desensitizationMailNumber: masked email address


user.checkPhoneOrEmail

Path: /common/user/checkPhoneOrEmail.api
Auth: No
Payload: Unknown

Called during the registration flow immediately before user.requestVerifyCode. Presumably validates whether the supplied phone number or email is already associated with an existing account. Called again on re-registration attempt after account deletion — consistent with a server-side duplicate check.


user.register

Path: /common/user/register.api
Auth: No
Payload: Unknown

Called after user.checkVerifyCode in the registration flow. On success, the app immediately calls user.login.

Registration flow:

plaintext
1. user.queryCountryList     {} (no auth)
2. user.checkPhoneOrEmail    (no auth) — duplicate check
3. user.requestVerifyCode    {"phoneNumber": "<phone>", "type": "<type>"} → null
4. user.checkVerifyCode      {"phoneNumber": "<phone>", "verifyCode": "<otp>", "type": "<type>"}
5. user.register             (no auth)
6. user.login                (no auth) → tokenId

Path: /common/user/getLatestVersion.api
Auth: Optional

Payload:

json
{
  "osType": "2"
}

osType: "2" = Android


user.requestVerifyCode

Path: /common/user/requestVerifyCode.api
Auth: No

Payload:

json
{
  "phoneNumber": "<formatted_phone>",
  "type": "3"
}

type: "3" = password reset and account deletion (same OTP flow for both), "1" = registration (unverified)

Response (decrypted): null


user.checkVerifyCode

Path: /common/user/checkVerifyCode.api
Auth: No

Payload:

json
{
  "phoneNumber": "<formatted_phone>",
  "verifyCode": "<otp>",
  "type": "3"
}

user.retrievePassword

Path: /common/user/retrievePassword.api
Auth: No

Payload:

json
{
  "password": "<new_plain_text_password>",
  "phoneNumber": "<formatted_phone>",
  "verifyCode": "<otp>"
}

verifyCode must match the one sent via user.requestVerifyCode.


user.setMessageNotification

Path: /api/user/setMessageNotification.api
Auth: Yes

Payload:

json
{
  "isReceive": "T"
}

isReceive: "T" = enable, "F" = disable


user.getCouponList

Path: /api/user/getCouponList.api
Auth: Yes

Payload (general):

json
{
  "pageNumber": "1",
  "type": "1",
  "isExpired": "N"
}

Payload (device-specific):

json
{
  "pageNumber": "1",
  "code": "washCoupon",
  "type": "1",
  "isExpired": "N",
  "deviceId": "<device_id>"
}

isExpired: "N" = valid coupons, "Y" = expired


user.getCouponCount

Path: /api/user/getCouponCount.api
Auth: Yes

Payload:

json
{
  "code": "washCoupon",
  "type": "1",
  "deviceId": "<device_id>"
}

Response (decrypted): 0 (integer, count of available coupons)



Laundry


laundry.getNearbyLaundryList

Path: /common/laundry/getNearbyLaundryList.api
Auth: Optional

Payload:

json
{
  "pageNumber": "1",
  "distance": "50000",
  "latitude": "<decimal_degrees>",
  "type": "1",
  "longitude": "<decimal_degrees>"
}

distance: radius in meters. The app always sends "50000" (hardcoded).
type: "1" = washers, "2" = dryers
pageNumber: starts at "1", paginated (10 results per page observed)

Response (decrypted, array):

json
[
  {
    "distance": "5m",
    "laundry": {
      "address": "VNIT NAGPUR",
      "businessStatus": "2",
      "floorNumbers": ["00"],
      "latitude": "21.123242",
      "laundryId": "1181",
      "longitude": "79.051513",
      "name": "VNIT NAGPUR - SWAMINATHAN",
      "spareDeviceNumber": "1",
      "weekEndTime": "23:59",
      "weekStartTime": "00:00",
      "workEndTime": "23:59",
      "workStartTime": "00:00"
    }
  }
]

distance: string with unit suffix (e.g. "5m")
spareDeviceNumber: number of available machines (string)
Note: businessId, hotLine, and payWindowTotalTime are absent from this response; use laundry.getLaundryDetail to retrieve them.


laundry.getLaundryDetail

Path: /common/laundry/getLaundryDetail.api
Auth: Optional

Payload:

json
{
  "type": "1",
  "laundryId": "<laundry_id>"
}

Response includes:

json
{
  "address": "VNIT NAGPUR",
  "businessId": "4",
  "businessStatus": "2",
  "floorNumbers": ["00"],
  "hotLine": "18001029999",
  "latitude": "21.123242",
  "laundryId": "1181",
  "longitude": "79.051513",
  "name": "VNIT NAGPUR - SWAMINATHAN",
  "payWindowTotalTime": "10",
  "spareDeviceNumber": "1",
  "weekEndTime": "23:59",
  "weekStartTime": "00:00",
  "workEndTime": "23:59",
  "workStartTime": "00:00"
}

payWindowTotalTime: minutes to complete payment after booking
spareDeviceNumber: number of available machines


laundry.getLaundryDeviceList

Path: /common/laundry/getLaundryDeviceList.api
Auth: Optional

Payload (all floors):

json
{
  "pageNumber": "1",
  "type": "1",
  "laundryId": "<laundry_id>"
}

Payload (specific floor):

json
{
  "pageNumber": "1",
  "floorNumber": "00",
  "type": "1",
  "laundryId": "<laundry_id>"
}

floorNumber: zero-padded floor string e.g. "00", "01"


laundry.getDeviceInfo

Path: /common/laundry/getDeviceInfo.api
Auth: Optional

Payload:

json
{
  "deviceId": "<device_id>"
}

Response includes:

json
{
  "capacity": "8",
  "currentRunModeId": "97",
  "deviceId": "3801",
  "location": "KCE-CBE-LH D&G",
  "model": "HW100-IM10636IOT",
  "moduleType": "4gmodule",
  "name": "8kgwifi drum washer 01",
  "runMode": [
    {
      "code": "STANDARD",
      "isDisply": "T",
      "modeFeature": "Use normal cycle for normal items with cold water.",
      "modeId": "94",
      "modeImage": "http://img.mrhiwash.com//runmodel/13.png",
      "modeName": "Normal",
      "price": "49.00",
      "timeDuration": "40"
    },
    {
      "code": "FAST",
      "isDisply": "T",
      "modeId": "95",
      "modeName": "Quick",
      "price": "39.00",
      "timeDuration": "25"
    },
    {
      "code": "SINGLE",
      "isDisply": "T",
      "modeId": "97",
      "modeName": "Spin",
      "price": "6.00",
      "timeDuration": "6"
    },
    {
      "code": "TNK_CLN",
      "isDisply": "F",
      "modeId": "109",
      "modeName": "Tub cleaning",
      "price": "0.00",
      "timeDuration": "6"
    }
  ],
  "serialNumber": "00F-U01",
  "status": "2",
  "supportsCleaning": "T",
  "timeRemaining": "6",
  "type": "1030",
  "typeName": "8KG Wifi Drum washing machine"
}

Confirmed modeId → program mapping:

modeId code name duration price (₹)
94 STANDARD Normal 40 min 49.00
95 FAST Quick 25 min 39.00
97 SINGLE Spin 6 min 6.00
109 TNK_CLN Tub cleaning 6 min 0.00

Device status values:

status Meaning
"1" Offline / Unavailable
"2" Available / Idle
"3" In use / Running


Order


order.reserve

Path: /api/order/reserve.api
Auth: Yes

Payload:

json
{
  "modeId": "<mode_id>",
  "orderesource": "1",
  "deviceId": "<device_id>"
}

orderesource: always "1" (observed)
Note: field name is orderesource (not orderSource)


order.orderDevice

Path: /api/order/orderDevice.api
Auth: Yes

Payload:

json
{
  "modeId": "<mode_id>",
  "isRq": "1",
  "orderesource": "1",
  "runCount": "1",
  "deviceId": "<device_id>"
}

runCount: number of cycles
isRq: always "1" (observed)


order.getUserOrderList

Path: /api/order/getUserOrderList.api
Auth: Yes

Payload:

json
{
  "orderType": "1",
  "pageNumber": "1"
}

Response (decrypted, array):

json
[
  {
    "actualPrice": "6.0",
    "currencySymbol": "₹",
    "deviceList": {
      "currentRunModeId": "97",
      "deviceId": "3799",
      "name": "8kgwifi drum washer 02",
      "serialNumber": "00F-U02",
      "status": "2",
      "timeRemaining": "3",
      "type": "1030"
    },
    "orderCode": "12026021812514875",
    "orderId": "12514875",
    "orderStatus": "104",
    "price": "6.00",
    "salePrice": "6.00",
    "start": false
  }
]

start: true = machine currently running, false = not running
actualPrice: present only on orders with status 104 (post-completion); absent on pending/cancelled orders
deviceList.currentRunModeId: absent when device has no active/recent run mode (e.g. status "1" devices)


order.getOrderDetail

Path: /api/order/getOrderDetail.api
Auth: Yes

Payload:

json
{
  "orderId": "<order_id>"
}

Response: Full order object. Confirmed fields:

json
{
  "actualName": "Paytm",
  "actualPrice": "6.00",
  "coupunName": "",
  "coupunPrice": "",
  "currencySymbol": "₹",
  "deviceInfo": { "...": "see laundry.getDeviceInfo" },
  "hotLine": "",
  "isCleaningComplete": "F",
  "orderCode": "12026021812514875",
  "orderId": "12514875",
  "orderStatus": "103",
  "orderTime": "20260217201735",
  "payWindowRemainingTime": "526",
  "price": "6.00",
  "runCount": "1",
  "runMode": {
    "code": "SINGLE",
    "isDisply": "T",
    "modeFeature": "Spin only",
    "modeId": "97",
    "modeName": "Spin",
    "price": "6.00",
    "timeDuration": "6"
  },
  "salePrice": "6.00",
  "start": false
}

payWindowRemainingTime: seconds remaining to pay (string)
orderTime: format yyyyMMddHHmmss
isCleaningComplete: "F" = not complete, "T" = complete
start: boolean, true = machine currently running
actualName / actualPrice: payment method name and amount charged; only present after payment is confirmed
actualPrice is also present on list items in order.getUserOrderList for status 104 orders


order.cancelOrder

Path: /api/order/cancelOrder.api
Auth: Yes

Payload:

json
{
  "orderId": "<order_id>"
}

order.sendVerifyCodeToDevice

Path: /api/order/sendVerifyCodeToDevice.api
Auth: Yes

Payload:

json
{
  "orderId": "<order_id>"
}

Sends OTP to machine display.

Response (decrypted):

json
{
  "vertifiedCode": "0000"
}

The OTP code to be confirmed on the physical machine display is returned directly in this response.


order.vertify

Path: /api/order/vertify.api
Auth: Yes

Payload:

json
{
  "orderId": "<order_id>",
  "vertifiedCode": "<otp_from_machine>"
}

Note: field name is vertifiedCode and method is vertify (server-side spelling, not a typo here)


order.orderPayMode

Path: /api/order/orderPayMode.api
Auth: Yes

Payload:

json
{
  "deviceType": "2",
  "orderType": "1",
  "orderId": "<order_id>",
  "type": "1"
}

type determines which payment options are returned:

Response (type:"1"):

json
[
  {
    "activityname": "",
    "description": "Paytm",
    "displyName": "Paytm",
    "id": 1,
    "imgUrl": "http://img.mrhiwash.com//merchant/84876.png"
  }
]

Response (type:"2"):

json
[
  {
    "activityname": "",
    "description": "Coupon传帮",
    "displyName": "Coupon",
    "id": 2,
    "imgUrl": "http://img.mrhiwash.com//merchant/84877.png"
  }
]

order.startCleanProgram

Path: /api/order/startCleanProgram.api
Auth: Yes

Payload:

json
{
  "orderId": "<order_id>"
}

Starts machine after payment confirmed.

Response (decrypted):

json
{
  "remainingTime": 6
}

remainingTime: integer, minutes remaining for the cycle. in app it just runs local coutndown from 6 min ,no polling for this.


order.getDeviceEndRuntimeByOrderId

Path: /api/order/getDeviceEndRuntimeByOrderId.api
Auth: Yes

Payload:

json
{
  "orderId": "<order_id>"
}

Response:

json
{
  "status": 103,
  "remainingTime": "6"
}

remainingTime: string, minutes remaining
status: integer order status code. Observed values: 109 (pending payment, pre-start), 103 (running).

App polls this endpoint continuously while machine is running.
Polling stop condition: Stop on remainingTime == "0" or status != 103. as prior condition can be missed between poll intervals — status change to 104/106 is the reliable completion signal.



Payment


pay.getPrepay

Path: /api/pay/getPrepay.api
Auth: Yes

Payload:

json
{
  "phoneType": "2",
  "payType": "1",
  "orderDeviceId": "<device_id>",
  "orderId": "<order_id>"
}

phoneType: "2" = Android payType: "1" = Paytm

Response:

json
{
  "payType": 1,
  "prepayInfo": {
    "CUST_ID": "MRHI<user_id>",
    "CHANNEL_ID": "WAP",
    "ORDER_ID": "<order_code>",
    "TXN_AMOUNT": "6.00",
    "CALLBACK_URL": "https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=<order_code>",
    "TXN_TOKEN": "<paytm_txn_token>",
    "MID": "HaierI99999377000796",
    "INDUSTRY_TYPE_ID": "Retail102",
    "CHECKSUMHASH": "<checksum>",
    "WEBSITE": "APPPROD"
  }
}

prepayInfo fields are Paytm gateway parameters. TXN_TOKEN and CHECKSUMHASH are generated server-side per transaction.


pay.queryOrderPaySuccess

Path: /api/pay/queryOrderPaySuccess.api
Auth: Yes

Payload:

json
{
  "payType": "1",
  "orderId": "<order_id>"
}

Response: nothing, it acts like ping to server, as reminder if payment recived on server side start the machine



Common


common.queryNewFocusList

Path: /common/common/queryNewFocusList.api
Auth: No

Payload:

json
{
  "type": "1"
}

common.quaryShowModule

Path: /common/common/quaryShowModule.api
Auth: No
Payload: {}


common.quaryShowInvitation

Path: /common/common/quaryShowInvitation.api
Auth: No
Payload: {}


Complete Booking Flow

plaintext
1. laundry.getNearbyLaundryList   → find laundries
2. laundry.getLaundryDetail       → laundry info + payWindowTotalTime
3. laundry.getLaundryDeviceList   → list machines
4. laundry.getDeviceInfo          → device status + available runModes + prices
5. order.orderDevice              → create order (status: 109)
   └─ payWindowTotalTime starts (10 min window)
6. order.sendVerifyCodeToDevice   → response contains vertifiedCode OTP
7. order.vertify                  → confirm OTP (order status transitions to 111)
8. order.getOrderDetail           → fetch updated order (status: 111)
9. order.orderPayMode (type:"1")  → get payment options
10. pay.getPrepay                 → get Paytm payment params
    └─ complete payment via Paytm gateway (external)
11. pay.queryOrderPaySuccess      → confirm payment (status: 103 = running)
12. order.getDeviceEndRuntimeByOrderId  → poll remaining time (status: 103 while running)
    └─ poll until remainingTime = "0"

Tub Clean Flow (free, no payment)

1. order.orderDevice (modeId for TNK_CLN, price: 0.00)
2. order.sendVerifyCodeToDevice
3. order.vertify
4. order.startCleanProgram   ← starts immediately, no payment step
5. poll getDeviceEndRuntimeByOrderId

remaining APIs

The following APIs exist in the app but payloads were not captured:

End

There might be typos, mistakes please do report them to make docs better. have used ai tools(makise) to assist in generate docs from network captures , and logs collected,though i dont have life ,i still wont write 1111 lines.

good bye.

sayonara