-
Notifications
You must be signed in to change notification settings - Fork 14
V2 API Reference
This documents the TP-Link Kasa Cloud API v2, reverse-engineered from the Kasa Android app v3.4.451 (decompiled February 2026).
TP-Link migrated from a V1 API to a V2 API for authentication. Key differences:
| Aspect | V1 (Legacy) | V2 (Current) |
|---|---|---|
| Base URL | https://wap.tplinkcloud.com |
https://n-wap.tplinkcloud.com |
| Auth endpoint |
POST / with {"method":"login","params":{...}}
|
POST /api/v2/account/login with flat body |
| appType | Kasa_Android |
Kasa_Android_Mix |
| Request signing | None | HMAC-SHA1 on every request |
| URL query params |
token only |
appName, appVer, termID, ospf, brand, locale, + token
|
| MFA/2FA | Not supported | Full support |
| Refresh tokens | Not supported | Supported |
| SSL | Standard certs | TP-Link private CA chain |
| Device operations | V1 format on /
|
Same V1 format on /, but with signing + query params |
Before logging in, discover the regional server for the user's account.
Endpoint: POST https://n-wap.tplinkcloud.com/api/v2/account/getAccountStatusAndUrl
Body:
{
"appType": "Kasa_Android_Mix",
"cloudUserName": "user@example.com"
}Response:
{
"error_code": 0,
"result": {
"accountApiUrl": "https://use1-account-api.i.tplinkcloud.com",
"serviceRegion": "us-east-1",
"appServerUrl": "https://n-use1-wap.tplinkcloud.com",
"appServerUrlV2": "https://n-use1-wap.i.tplinkcloud.com",
"status": 1
}
}Use appServerUrl for subsequent requests. The status field indicates account state (1 = active).
Endpoint: POST {appServerUrl}/api/v2/account/login
Body (flat JSON, no wrapper):
{
"appType": "Kasa_Android_Mix",
"appVersion": "3.4.451",
"cloudPassword": "your_password",
"cloudUserName": "user@example.com",
"platform": "Android",
"refreshTokenNeeded": true,
"supportBindAccount": false,
"terminalUUID": "uuid-v4-string",
"terminalName": "MyDevice",
"terminalMeta": "MyDevice"
}Successful Response:
{
"error_code": 0,
"result": {
"token": "xxxxxxxx-xxxxxxxxxxxxxxxxxxxx",
"refreshToken": "xxxxxxxx-xxxxxxxxxxxxxxxxxxxx",
"accountId": "1234567",
"email": "user@example.com",
"regionCode": "US",
"supportedMFATypes": [],
"appServerUrl": "https://n-use1-wap.tplinkcloud.com",
"appServerUrlV2": "https://n-use1-wap.i.tplinkcloud.com"
}
}MFA Required Response (error -20677):
{
"error_code": -20677,
"result": {
"mfaProcessId": "process-id-string",
"supportedMFATypes": ["email"],
"accountId": "1234567"
}
}See MFA Authentication Flow for handling this case.
Device listing and passthrough commands still use the V1 JSON format, but on the V2 infrastructure with signing and query params.
Get Device List:
POST {appServerUrl}/?token={token}&appName=Kasa_Android_Mix&appVer=3.4.451&...
Body:
{
"method": "getDeviceList",
"params": {}
}
Passthrough (control a device):
POST {appServerUrl}/?token={token}&appName=Kasa_Android_Mix&appVer=3.4.451&...
Body:
{
"method": "passthrough",
"params": {
"deviceId": "DEVICE_ID_HERE",
"requestData": "{\"system\":{\"set_relay_state\":{\"state\":1}}}"
}
}
Note: requestData is a JSON string, not a nested object.
All requests require these query parameters (added by the Retrofit interceptor C29914q in the Android app):
| Parameter | Value | Required |
|---|---|---|
appName |
Kasa_Android_Mix |
Always |
appVer |
3.4.451 |
Always |
netType |
wifi |
Always |
termID |
UUID v4 string | Always |
ospf |
Android 14 |
Always |
brand |
TPLINK |
Always |
locale |
en_US |
Always |
model |
Device model string | Optional |
termName |
Terminal name | Optional |
termMeta |
Terminal metadata | Optional |
token |
Auth token | When authenticated |
See HMAC Request Signing for full details.
| Code | Meaning |
|---|---|
0 |
Success |
-20104 |
Parameter doesn't exist (missing required field) |
-20571 |
Invalid request or signature |
-20651 |
Token expired (use refresh token) |
-20655 |
Refresh token expired (re-login required) |
-20677 |
MFA required |
-23003 |
App version too old |
All under {appServerUrl}/api/v2/account/:
| Endpoint | Description | Auth Required |
|---|---|---|
getAccountStatusAndUrl |
Regional URL discovery | No |
login |
Login with credentials | No |
logout |
Invalidate token | Yes |
getAccountInfo |
Get account details | Yes |
checkMFACodeAndLogin |
Complete MFA login | No |
getEmailVC4TerminalMFA |
Request email MFA code | No |
getPushVC4TerminalMFA |
Request push MFA notification | No |
register |
Create new account | No |
getRegVeriCode |
Get registration verification code | No |
checkRegVeriCode |
Verify registration code | No |
resetCloudPassword |
Reset password | No |
modifyCloudPassword |
Change password | Yes |
getCountryCallingCodes |
Get country codes list | No |
checkPassword |
Validate password | No |
The V2 servers (n-wap.tplinkcloud.com, n-use1-wap.tplinkcloud.com) use TP-Link's private CA chain:
Root: tp-link-CA (self-signed)
└── Intermediate: TP-LINK CA P1
└── Leaf: *.tplinkcloud.com
Standard SSL verification will fail. Options:
- Bundle the CA chain and pass it to your HTTP client
- Use
appServerUrlV2(e.g.,n-use1-wap.i.tplinkcloud.com) which uses public certs - Disable SSL verification (not recommended for production)
The CA chain can be extracted from the server:
openssl s_client -showcerts -connect n-wap.tplinkcloud.com:443 < /dev/null 2>/dev/null | \
awk '/BEGIN CERT/,/END CERT/{print}'