API Signature Authentication
This authentication method supports partner platforms using the open platform APIs
API Domain
https://open.wesurvey.com
Request Structure
- All API interfaces communicate via
HTTPS
and useUTF-8
encoding - Supported HTTP request methods: POST, GET, PUT, DELETE
- Supported Content-Type for POST requests:
application/json
. Parameters marked as body in subsequent documentation should be passed in JSON format - Note: Do not make open API requests directly from the frontend to prevent secret leakage
Common Parameters
1. Parameter Description
Parameters used for user identification and interface authentication. Unless necessary, these parameters will not be explained separately in each interface's documentation, but they must be included in every request for normal operation. Common parameters are defined as follows:
Parameter Name | Description | Example Value |
---|---|---|
appid | Third-party application ID | tpidGFSJgefA |
timestamp | Current timestamp | 1615783862 |
nonce | Random positive integer | 815390 |
sign | Signature | ff47fd770c11936a14435c2a8f15fa6626c90464 |
2. GET Request Structure Example
(This interface is for signature method debugging, no practical use)
https://open.wesurvey.com/api/signature/check?appid=tpidGFSJgefA&nonce=26377876×tamp=1615794722&sign=70e45a2659340a9d97e1115483e265c0a1e3a207
3. POST Request Structure Example
(This interface is for signature method debugging, no practical use)
https://open.wesurvey.com/api/signature/check?appid=tpidGFSJgefA&nonce=83990929×tamp=1615795350&sign=e9c028ec5e3fcbdf7c7202d2fc5017e78ae7cf33
{"input":"ping"}
Interface Authentication
1. Application Credential Application
- Before using the open APIs, you must first apply for appid and secret from the backend
- The API will authenticate each access request, meaning each request must include signature information (Signature) in the common request parameters to verify the requester's identity
- The signature information is generated by security credentials. The security credential is the secret, used for encrypting the signature string and server-side verification of the signature string (i.e., the sign parameter)
2. Sort Request Parameters
- First, sort all URL request parameters (excluding sign and data) in ascending order by parameter name's dictionary order (ASCII code)
- Users can use relevant sorting functions in programming languages to implement this functionality, such as the ksort function in PHP or sort.Strings(keys) in Golang
- The sorting result of the above GET example parameters is:
appid, nonce, timestamp
3. Concatenate Query String
- This step generates the URL parameter request string by formatting the sorted request parameters from the previous step into "parameter name"="parameter value" form
- Note: "Parameter value" should be the original value, not the URL-encoded value. Then join the formatted parameters with "&"
- The final generated query string is:
appid=tpidGFSJgefA&nonce=93914207×tamp=1615789882
4. Concatenate Original Signature String
This step generates the original signature string
The original signature string consists of the following parameters: Request method: Supports POST and GET methods, note that the method should be in all caps. Request domain: open.wesurvey.com/api/user/. The actual request domain varies depending on the interface module, see each interface description for details. Request string: The request string generated by concatenating URL parameters after sorting in the previous step.
GET request signature string concatenation rule: "GET" + request domain + interface route + "?" + query string
GETopen.wesurvey.com/api/signature/check?appid=tpidGFSJgefA&nonce=26377876×tamp=1615794722
- POST request signature string concatenation rule: "POST" + request domain + interface route + "?" + query string + "&data=" + request body JSON string
POSTopen.wesurvey.com/api/signature/check?appid=tpidGFSJgefA&nonce=93914207×tamp=1615789882&data={"input":"ping"}
5. Generate Signature
First, use the HMAC-SHA1 algorithm to sign the original signature string obtained in the previous step, then encode the generated signature string in hexadecimal to obtain the final signature string. (See example code below for various language implementations)
6. Concatenate Signature
Add the sign parameter from step 5 to the string concatenated in step 3, like xxx&sign={$signStr}. The final request URL will be:
https://open.wesurvey.com/api/signature/check?appid=tpidGFSJgefA&nonce=26377876×tamp=1615794722&sign=a6d9017202db28fedc622a40833d794452179c45
7. Make Request
POST
https://open.wesurvey.com/api/signature/check?appid=tpidGFSJgefA&nonce=93914207×tamp=1615789882&sign=a6d9017202db28fedc622a40833d794452179c45
{"input":"ping"}
Example Code
PHP Example Code
<?php
$appid = "tpidGFSJgefA"; // Replace with your appid
$secret = "ff47fd770c11936a14435c2a8f15fa6626c90464"; // Replace with your secret
$data = json_encode(["input"=>"ping"]);
$method = "POST";
$url = "open.wesurvey.com/api/signature/check";
$params = [
"timestamp" => time(),
"appid" => $appid,
"nonce" => rand(1, 100000000),
];
// 1. Sort parameters
ksort($params);
$paramsStr = http_build_query($params);
$rawStr = $method . $url . "?" . $paramsStr;
if ($method == "POST" || $method == "PUT") {
$rawStr = $rawStr . "&data=" . $data;
}
// 2. hmac_sha1 signature
$key = utf8_encode($secret);
$msg = utf8_encode($rawStr);
// 3. Hexadecimal string
$b16encoded = hash_hmac("sha1", $msg, $key, false);
// 4. urlencode
$signStr = urlencode($b16encoded);
// 5. Send request
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://".$url."?".$paramsStr."&sign=".$signStr);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
var_dump($response);
?>
Golang Example Code
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"fmt"
"math/rand"
"net/http"
"net/url"
"sort"
"strconv"
"time"
)
func main() {
appid := "tpidGFSJgefA" // Replace with your appid
secret := "ff47fd770c11936a14435c2a8f15fa6626c90464" // Replace with your secret
data, _ := json.Marshal(map[string]string{"input": "ping"})
method := "POST"
apiURL := "open.wesurvey.com/api/signature/check"
params := map[string]string{
"timestamp": strconv.FormatInt(time.Now().Unix(), 10),
"appid": appid,
"nonce": strconv.Itoa(rand.Intn(100000000)),
}
// 1. Sort parameters
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
paramsStr := ""
for _, k := range keys {
paramsStr += k + "=" + url.QueryEscape(params[k]) + "&"
}
paramsStr = paramsStr[:len(paramsStr)-1]
rawStr := method + apiURL + "?" + paramsStr
if method == "POST" || method == "PUT" {
rawStr = rawStr + "&data=" + string(data)
}
// 2. hmac_sha1 signature
key := []byte(secret)
mac := hmac.New(sha1.New, key)
mac.Write([]byte(rawStr))
b16encoded := hex.EncodeToString(mac.Sum(nil))
// 4. urlencode
signStr := url.QueryEscape(b16encoded)
// Print signature string
fmt.Println(signStr)
// 5. Send request
resp, err := http.Post("https://"+apiURL+"?"+paramsStr+"&sign="+signStr, "application/json", bytes.NewReader(data))
if err != nil {
fmt.Println(err.Error())
return
}
defer resp.Body.Close()
fmt.Println(resp.Status)
// 5. Parse response
type respStruct struct {
Code string `json:"code"`
RequestID string `json:"request_id"`
}
var respData respStruct
err = json.NewDecoder(resp.Body).Decode(&respData)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(respData)
}
Java Example Code
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class Main {
public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
testSign();
}
public static void testSign() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
String appid = "tpidGFSJgefA"; // Replace with your appid
String secret = "ff47fd770c11936a14435c2a8f15fa6626c90464"; // Replace with your secret
// Manually creating JSON string
String data = "{\"input\":\"ping\"}";
String method = "POST";
String url = "open.wesurvey.com/api/signature/check";
Map<String, Object> params = new HashMap<>();
params.put("timestamp", System.currentTimeMillis() / 1000L);
params.put("appid", appid);
params.put("nonce", new Random().nextInt(100000000));
// 1. Sort parameters
String paramsStr = params.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(Collectors.joining("&"));
String rawStr = method + url + "?" + paramsStr;
if ("POST".equals(method) || "PUT".equals(method)) {
rawStr = rawStr + "&data=" + data;
}
// 2. hmac_sha1 signature
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
mac.init(secretKeySpec);
byte[] hmacSha1Bytes = mac.doFinal(rawStr.getBytes(StandardCharsets.UTF_8));
// 3. Hexadecimal string
StringBuilder sb = new StringBuilder();
for (byte b : hmacSha1Bytes) {
sb.append(String.format("%02x", b));
}
String b16encoded = sb.toString();
// 4. urlencode
String signStr = java.net.URLEncoder.encode(b16encoded, StandardCharsets.UTF_8.toString());
// 5. Send request
URL requestUrl = new URL("https://" + url + "?" + paramsStr + "&sign=" + signStr);
HttpURLConnection conn = (HttpURLConnection) requestUrl.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
os.write(data.getBytes(StandardCharsets.UTF_8));
os.flush();
}
int responseCode = conn.getResponseCode();
String responseMessage = new java.io.BufferedReader(new java.io.InputStreamReader(conn.getInputStream()))
.lines()
.collect(Collectors.joining("\n"));
System.out.println("Response Code: " + responseCode);
System.out.println("Response Message: " + responseMessage);
}
}
Python3 Example Code
import time
import random
import hmac
import hashlib
import urllib.parse
import requests
import json
def test_sign():
appid = "tpidGFSJgefA" # Replace with your appid
secret = "ff47fd770c11936a14435c2a8f15fa6626c90464" # Replace with your secret
data = json.dumps({"input": "ping"})
method = "POST"
url = "open.wesurvey.com/api/signature/check"
params = {
"timestamp": int(time.time()),
"appid": appid,
"nonce": random.randint(1, 100000000),
}
# 1. Sort parameters
sorted_params = sorted(params.items())
params_str = urllib.parse.urlencode(sorted_params)
raw_str = method + url + "?" + params_str
if method in ["POST", "PUT"]:
raw_str += "&data=" + data
# 2. hmac_sha1 signature
key = secret.encode('utf-8')
msg = raw_str.encode('utf-8')
b16encoded = hmac.new(key, msg, hashlib.sha1).hexdigest()
# 4. urlencode
sign_str = urllib.parse.quote(b16encoded)
# 5. Send request
full_url = f"https://{url}?{params_str}&sign={sign_str}"
headers = {'Content-Type': 'application/json'}
response = requests.post(full_url, data=data, headers=headers)
print(response.text)
# Call function for testing
test_sign()
Response Examples
- Successful Request
{
"code": "OK",
"error": {
"type": ""
},
"data": {
"output": "pong"
},
"request_id": "7a1eeb3c-3225-404e-9f60-558e58fc5ed9"
}
- Failed Request
{
"code": "PermissionDenied",
"error": {
"type": "invalid_signature"
},
"data": {},
"request_id": "ec8917cb-e7ee-4462-8423-abffb27641c5"
}
Error Codes
Primary Error Status
code Error Code | Description |
---|---|
OK | Request successful |
PermissionDenied | Request failed (no permission) |
Secondary Error Status
error.type Error Code | Description |
---|---|
invalid_appid | Invalid appid |
invalid_signature | Invalid signature |
timestamp_error | Timestamp error |
nonce_existed | Nonce repeated within short period |
claim_error | Resource permission error |