OwlProxy API
  • 简体中文
  • English
  • 简体中文
  • English
  • Product Introduction
  • Product Type
  • Product Billing
  • OpenAPI
    • API Documentation
    • API Guide
    • Change Log
    • LLMs.txt (AI Quick Reference)
    • OpenAPI Specification (AI Exclusive)
    • Error Code
  • Related Agreements
    • /en/system/PrivacyAgreement.html

API Guide

Overview

OwlProxy OpenAPI uses V2 SHA-256 signing for request authentication.

Get AK/SK

Before calling the API, contact your technical representative to obtain:

  • Access Key ID (AK)
  • Secret Access Key (SK)

Keep the SK secure. Do not expose it in frontend code, public repositories, or logs.

Request Headers

Every OpenAPI request must contain these authentication headers:

HeaderTypeRequiredDescriptionExample
X-Access-KeystringYesAccess Key IDak_xxxxxxxxxxxx
X-TimestampstringYes10-digit Unix timestamp in seconds1747555200
X-SignstringYes64-character SHA-256 hexadecimal signature6069dfb4cb3ac57b...
Content-TypestringPOST/PUTRequest body typeapplication/json

X-Timestamp must be within five minutes of the current time.

Signing Algorithm

Concatenate the fields directly without delimiters:

signString = SK + X-Timestamp + path + bodyOrQuery
X-Sign = lowerHex(SHA-256(signString_UTF8))
FieldValue
SKSecret Access Key
X-TimestampThe exact seconds timestamp sent in the request header
pathFull request path, such as /owlproxy/api/openApi/vcProxy/queryByorderIdList
bodyOrQueryDetermined by the request type; see below

bodyOrQuery Rules

Request typebodyOrQuery
GETRaw query string; use an empty string when there are no parameters
POST/PUT JSONThe exact request body string sent to the API
No request bodyEmpty string

For GET requests, parameter order and URL encoding must match the actual request. For JSON requests, use a compact single-line body and do not format or serialize it again after signing.

Signing Example

This example calls the order query API:

SK = sk_xxxxxxxxxxxx
X-Timestamp = 1747555200
path = /owlproxy/api/openApi/vcProxy/queryByorderIdList
bodyOrQuery = {"orderIds":["ORDER-00001"]}

String to sign:

sk_xxxxxxxxxxxx1747555200/owlproxy/api/openApi/vcProxy/queryByorderIdList{"orderIds":["ORDER-00001"]}

Calculate SHA-256 over the UTF-8 bytes of this string:

X-Sign = 39c4d29bc564bdfdbffc8fba89bd088d79be40b29eb3a9f5050d007f416ab05e

Examples

curl

timestamp=$(date +%s)
accessKey="ak_xxxxxxxxxxxx"
secretKey="sk_xxxxxxxxxxxx"
path="/owlproxy/api/openApi/vcProxy/queryByorderIdList"
body='{"orderIds":["ORDER-00001"]}'

sign=$(printf "%s" "${secretKey}${timestamp}${path}${body}" | openssl dgst -sha256 -hex | awk '{print $2}')

curl -X POST "https://api.owlproxy.com${path}" \
  -H "X-Access-Key: ${accessKey}" \
  -H "X-Timestamp: ${timestamp}" \
  -H "X-Sign: ${sign}" \
  -H "Content-Type: application/json" \
  --data-binary "${body}"

Java

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;

public class OwlProxyOpenApiExample {
    private static final String BASE_URL = "https://api.owlproxy.com";
    private static final String ACCESS_KEY = "ak_xxxxxxxxxxxx";
    private static final String SECRET_KEY = "sk_xxxxxxxxxxxx";

    private static String sha256Hex(String value) throws Exception {
        byte[] digest = MessageDigest.getInstance("SHA-256")
                .digest(value.getBytes(StandardCharsets.UTF_8));
        StringBuilder hex = new StringBuilder(digest.length * 2);
        for (byte item : digest) {
            hex.append(String.format("%02x", item & 0xff));
        }
        return hex.toString();
    }

    public static void main(String[] args) throws Exception {
        String path = "/owlproxy/api/openApi/vcProxy/queryByorderIdList";
        String body = "{\"orderIds\":[\"ORDER-00001\"]}";
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000L);
        String sign = sha256Hex(SECRET_KEY + timestamp + path + body);

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(BASE_URL + path))
                .header("X-Access-Key", ACCESS_KEY)
                .header("X-Timestamp", timestamp)
                .header("X-Sign", sign)
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
                .build();

        HttpResponse<String> response = HttpClient.newHttpClient().send(
                request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
        System.out.println(response.body());
    }
}

Python

import hashlib
import time

import requests

baseUrl = "https://api.owlproxy.com"
accessKey = "ak_xxxxxxxxxxxx"
secretKey = "sk_xxxxxxxxxxxx"
path = "/owlproxy/api/openApi/vcProxy/queryByorderIdList"
body = '{"orderIds":["ORDER-00001"]}'
timestamp = str(int(time.time()))
sign = hashlib.sha256(
    (secretKey + timestamp + path + body).encode("utf-8")
).hexdigest()

response = requests.post(
    baseUrl + path,
    headers={
        "X-Access-Key": accessKey,
        "X-Timestamp": timestamp,
        "X-Sign": sign,
        "Content-Type": "application/json",
    },
    data=body.encode("utf-8"),
)
print(response.text)

Node.js

const crypto = require("crypto");

const baseUrl = "https://api.owlproxy.com";
const accessKey = "ak_xxxxxxxxxxxx";
const secretKey = "sk_xxxxxxxxxxxx";
const path = "/owlproxy/api/openApi/vcProxy/queryByorderIdList";
const body = '{"orderIds":["ORDER-00001"]}';
const timestamp = Math.floor(Date.now() / 1000).toString();
const sign = crypto
  .createHash("sha256")
  .update(secretKey + timestamp + path + body, "utf8")
  .digest("hex");

async function main() {
  const response = await fetch(baseUrl + path, {
    method: "POST",
    headers: {
      "X-Access-Key": accessKey,
      "X-Timestamp": timestamp,
      "X-Sign": sign,
      "Content-Type": "application/json",
    },
    body,
  });
  console.log(await response.text());
}

main().catch(console.error);

GET Example

Request:

GET /owlproxy/api/openApi/vcProxyShop/getProxyTypeList?proxyMode=1

Signing fields:

path = /owlproxy/api/openApi/vcProxyShop/getProxyTypeList
bodyOrQuery = proxyMode=1

Common Error Codes

CodeDescriptionSuggested action
2019Signature verification failedCheck path, parameter order, and request body
2031Invalid keyCheck the Access Key ID
2032Authentication headers missingAdd all three V2 headers
2033Timestamp expired or malformedUse the current Unix timestamp in seconds

FAQ

How do I sign an empty POST body?

Use an empty string for bodyOrQuery; the string to sign ends with path.

Is X-Sign case-sensitive?

Use a 64-character lowercase hexadecimal string.

Why does verification fail with the same parameters?

Check the full request path, timestamp unit, GET parameter order, URL encoding, and the exact JSON string sent in the request.

Data Encryption/Decryption Example

Java AES GCM Decryption

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

public class AESUtils {
    private static final String AES = "AES";
    private static final String AES_CIPHER_ALGORITHM = "AES/GCM/NoPadding";
    private static final int GCM_TAG_LENGTH = 16;
    private static final int GCM_IV_LENGTH = 12;

    private static SecretKeySpec getKeyFromPassword(String password) throws NoSuchAlgorithmException {
        MessageDigest sha = MessageDigest.getInstance("SHA-256");
        byte[] key = sha.digest(password.getBytes());
        return new SecretKeySpec(key, AES);
    }

    public static byte[] generateIv() {
        byte[] iv = new byte[GCM_IV_LENGTH];
        new SecureRandom().nextBytes(iv);
        return iv;
    }

    public static String encrypt(String input, String key) {
        try {
            SecretKeySpec secretKeySpec = getKeyFromPassword(key);
            byte[] iv = generateIv();
            Cipher cipher = Cipher.getInstance(AES_CIPHER_ALGORITHM);
            GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmParameterSpec);
            byte[] cipherText = cipher.doFinal(input.getBytes());

            String ivString = Base64.getEncoder().encodeToString(iv);
            String cipherTextString = Base64.getEncoder().encodeToString(cipherText);
            return ivString + ":" + cipherTextString;
        } catch (Exception e) {
            return null;
        }
    }

    public static String decrypt(String encryptedData, String key) {
        try {
            SecretKeySpec secretKeySpec = getKeyFromPassword(key);
            String[] parts = encryptedData.split(":");
            byte[] iv = Base64.getDecoder().decode(parts[0]);
            byte[] cipherText = Base64.getDecoder().decode(parts[1]);

            Cipher cipher = Cipher.getInstance(AES_CIPHER_ALGORITHM);
            GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec);
            return new String(cipher.doFinal(cipherText));
        } catch (Exception e) {
            return null;
        }
    }
}
Prev
API Documentation
Next
Change Log