Comprehensive API documentation covering security authentication, signature generation, and core API usage examples.
companyCode:
Enterprise unique identifier (used for request header identity)
key:
API signature key (only used for local signature generation, never transmit in plaintext)
time and sign) by Unicode code point ascending order, concatenate as key=value&key=value format.
time={UTC+0 timestamp in seconds}&key={assigned key}.
aiMode=0&batRatedCapacity=1&batRatedChargingPower=1000&customTimes=00:00,12:00,1000&13:00,15:00,-2000&dataTime=2025-06-26&energyMode=2&priceCompany=Germany&time=1732756652&key=2a1891544dbcf8e8b45b36d03187485a
time and sign fields.
{
"energyMode": "2",
"aiMode": "0",
"customTimes": "00:00,12:00,1000&13:00,15:00,-2000",
"batRatedCapacity": "1",
"batRatedChargingPower": "1000",
"dataTime": "2025-06-26",
"priceCompany": "Germany"
}
aiMode, batRatedCapacity, batRatedChargingPower, customTimes, dataTime, energyMode, priceCompany
key=value format, joined by &.
aiMode=0&batRatedCapacity=1&batRatedChargingPower=1000&customTimes=00:00,12:00,1000&13:00,15:00,-2000&dataTime=2025-06-26&energyMode=2&priceCompany=Germany
time and key at the end of the string.
aiMode=0&batRatedCapacity=1&batRatedChargingPower=1000&customTimes=00:00,12:00,1000&13:00,15:00,-2000&dataTime=2025-06-26&energyMode=2&priceCompany=Germany&time=1732756652&key=2a1891544dbcf8e8b45b36d03187485a
status=&time=...&key=...)sign parameter value.
import java.security.MessageDigest;
import java.util.TreeMap;
public class SignGenerator {
public static String generateSign(TreeMap params, String key) {
try {
StringBuilder sb = new StringBuilder();
// Concatenate business parameters
for (String paramKey : params.keySet()) {
if (!paramKey.equals("sign")) {
sb.append(paramKey).append("=").append(params.get(paramKey)).append("&");
}
}
// Append time and key
sb.append("time=").append(params.get("time")).append("&key=").append(key);
// MD5 encrypt and convert to lowercase
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(sb.toString().getBytes("UTF-8"));
StringBuilder hexString = new StringBuilder();
for (byte b : digest) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString().toLowerCase();
} catch (Exception e) {
throw new RuntimeException("Signature generation failed", e);
}
}
}
import hashlib
from urllib.parse import urlencode
def generate_sign(params, key):
"""
Generate API signature
:param params: Business parameter dict (contains time)
:param key: Assigned key
:return: MD5 signature string (lowercase)
"""
# Exclude sign field, sort by key
sorted_params = sorted([(k, v) for k, v in params.items() if k != 'sign'])
# Concatenate parameters
param_str = '&'.join([f"{k}={v}" for k, v in sorted_params])
# Append time and key
sign_str = f"{param_str}&time={params['time']}&key={key}"
# MD5 encrypt and convert to lowercase
return hashlib.md5(sign_str.encode('utf-8')).hexdigest().lower()
# Usage example
params = {
'energyMode': '2',
'aiMode': '0',
'customTimes': '00:00,12:00,1000&13:00,15:00,-2000',
'batRatedCapacity': '1',
'batRatedChargingPower': '1000',
'dataTime': '2025-06-26',
'priceCompany': 'Germany',
'time': '1732756652'
}
sign = generate_sign(params, '2a1891544dbcf8e8b45b36d03187485a')
print(f"Generated signature: {sign}")
const crypto = require('crypto');
function generateSign(params, key) {
// Get sorted parameter keys (exclude sign)
const sortedKeys = Object.keys(params)
.filter(k => k !== 'sign')
.sort();
// Concatenate parameter string
const paramString = sortedKeys
.map(k => `=`)
.join('&');
// Append time and key
const signString = `&time=&key=`;
// MD5 encrypt and convert to lowercase
return crypto.createHash('md5')
.update(signString, 'utf8')
.digest('hex')
.toLowerCase();
}
// Usage example
const params = {
energyMode: '2',
aiMode: '0',
customTimes: '00:00,12:00,1000&13:00,15:00,-2000',
batRatedCapacity: '1',
batRatedChargingPower: '1000',
dataTime: '2025-06-26',
priceCompany: 'Germany',
time: '1732756652'
};
const sign = generateSign(params, '2a1891544dbcf8e8b45b36d03187485a');
console.log('Generated signature:', sign);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
public class SignGenerator
{
public static string GenerateSign(Dictionary parameters, string key)
{
// Exclude sign field, sort by key
var sortedParams = parameters
.Where(p => p.Key != "sign")
.OrderBy(p => p.Key, StringComparer.Ordinal)
.Select(p => $"{p.Key}={p.Value}");
// Concatenate parameters
string paramString = string.Join("&", sortedParams);
// Append time and key
string signString = $"{paramString}&time={parameters["time"]}&key={key}";
// MD5 encrypt and convert to lowercase
using (var md5 = MD5.Create())
{
byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(signString));
StringBuilder sb = new StringBuilder();
foreach (byte b in hashBytes)
{
sb.Append(b.ToString("x2")); // Convert to lowercase hex
}
return sb.ToString();
}
}
}
companyCode: {Enterprise Code} and Accept-Language: en-US.
time (exact UTC+0 timestamp used in signature) and sign (MD5 signature value).
curl --location 'https://api.aecc.com/openApi/price/setEnergyMode' \
--header 'companyCode: AECC2024001' \
--header 'Accept-Language: en-US' \
--header 'Content-Type: application/json' \
--data '{
"energyMode": "2",
"aiMode": "0",
"customTimes": "00:00,12:00,1000&13:00,15:00,-2000",
"batRatedCapacity": "1",
"batRatedChargingPower": "1000",
"dataTime": "2025-06-26",
"priceCompany": "Germany",
"time": "1732756652",
"sign": "c3757db87150d5efbb45009d9253d375"
}'
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
public class ApiClient {
private static final String API_URL = "https://api.aecc.com/openApi/price/setEnergyMode";
private static final String COMPANY_CODE = "AECC2024001";
private static final String KEY = "2a1891544dbcf8e8b45b36d03187485a";
public static void main(String[] args) throws Exception {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(API_URL);
// Set headers
httpPost.setHeader("companyCode", COMPANY_CODE);
httpPost.setHeader("Accept-Language", "en-US");
httpPost.setHeader("Content-Type", "application/json");
// Prepare business parameters
long currentTime = System.currentTimeMillis() / 1000; // UTC+0 second timestamp
TreeMap params = new TreeMap<>();
params.put("energyMode", "2");
params.put("aiMode", "0");
params.put("customTimes", "00:00,12:00,1000&13:00,15:00,-2000");
params.put("batRatedCapacity", "1");
params.put("batRatedChargingPower", "1000");
params.put("dataTime", "2025-06-26");
params.put("priceCompany", "Germany");
params.put("time", String.valueOf(currentTime));
// Generate signature
String sign = SignGenerator.generateSign(params, KEY);
params.put("sign", sign);
// Construct JSON request body
JSONObject requestBody = new JSONObject();
for (String key : params.keySet()) {
requestBody.put(key, params.get(key));
}
httpPost.setEntity(new StringEntity(requestBody.toString(), "UTF-8"));
// Send request
String response = httpClient.execute(httpPost, response -> {
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println("Status code: " + statusCode);
return responseBody;
});
System.out.println("Response: " + response);
httpClient.close();
}
}
companyCode in request headertime parameter is within allowed time range (default ±5 minutes), prevent replay attackssign value in request, must match exactly| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| companyCode | header | string | Yes | Enterprise unique identifier |
| Accept-Language | header | string | Yes | en-US |
| time | body | string | Yes | UTC+0 timestamp (seconds) |
| sign | body | string | Yes | Signature info |
| priceCompany | body | string | Yes | Price region (e.g., Germany="Germany") |
| batRatedCapacity | body | string | Yes | Battery rated full charge capacity (kWh), 0~100, energy needed to fully charge |
| batRatedChargingPower | body | string | Yes | Battery rated charging power (W), used with capacity to calculate charge time |
| dataTime | body | string | Yes | Today's date (yyyy-MM-dd) |
| energyMode | body | int | Yes | Energy mode: 0=Off (no control), 1=Smart mode, 2=Custom mode |
| aiMode | body | int | No | AI control enable: 0=Disabled, 1=Enabled (only for Smart mode, default 0) |
| customTimes | body | string | No | Custom time periods, format: startTime,endTime,power (e.g., 00:00,12:00,1000&13:00,15:00,-2000). Max 16 periods |
{
"energyMode": "2",
"aiMode": "0",
"customTimes": "00:00,12:00,1000&13:00,15:00,-2000",
"batRatedCapacity": "1",
"batRatedChargingPower": "1000",
"dataTime": "2025-06-26",
"priceCompany": "Germany",
"time": "1732756652",
"sign": "c3757db87150d5efbb45009d9253d375"
}
packet:
Hexadecimal control message. Requires secondary encryption and CRC16 checksum calculation per device protocol before sending to collector.
powerTimes:
Time period strategy array, containing charging/discharging power commands for each time period.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| companyCode | header | string | Yes | Enterprise unique identifier |
| Accept-Language | header | string | Yes | en-US |
| dataTime | body | string | Yes | Date (yyyy-MM-dd) |
| priceCompany | body | string | Yes | Price region (e.g., Germany, France) |
| mode | body | string | No | Price granularity: 0=1 hour, 1=15 minutes (default 0) |
| time | body | string | Yes | UTC+0 timestamp (seconds) |
| sign | body | string | Yes | Signature info |
{
"dataTime": "2024-09-07",
"priceCompany": "Germany",
"mode": "0",
"time": "1725677116",
"sign": "e07b26034722d166e7f059cb728ab3fd"
}
priceArr:
24-hour electricity price array, unit is EUR/MWh.
pricesDayList:
Time period detail list, containing start/end time, price value and peak/valley/flat identifier for each period.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| companyCode | header | string | Yes | Enterprise unique identifier |
| Accept-Language | header | string | Yes | en-US |
| deviceSn | body | string | Yes | Device serial number |
| time | body | string | Yes | UTC+0 timestamp (seconds) |
| sign | body | string | Yes | Signature info |
{
"deviceSn": "NB2548300T110CHAB",
"time": "1725450897",
"sign": "e83ba9c021edd831ae69033f77528ac5"
}
obj:
Device rated data model.
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| companyCode | header | string | Yes | Enterprise unique identifier |
| Accept-Language | header | string | Yes | en-US |
| deviceSn | body | string | Yes | Device serial number |
| time | body | string | Yes | UTC+0 timestamp (seconds) |
| sign | body | string | Yes | Signature info |
{
"deviceSn": "NB2548300T110CHAB",
"time": "1725450897",
"sign": "e83ba9c021edd831ae69033f77528ac5"
}
obj:
Device real-time data model.
Server recalculates signature using the same rules (sort business params by Unicode → append time and key at end → MD5 → lowercase) and compares with sign in request body. Any mismatch returns result=10001, msg="Signature exception".
Troubleshooting steps (by likelihood):
status=&time=...). Special characters like &, :, , (in customTimes field) are concatenated directly without URL encoding.result=10001, msg="Signature exception".Time deviation handling suggestions:
No.
&key=xxx). It is not a request parameter, not in header, not in URL query.--header 'companyCode: AECC2024001'. key only participates in local MD5, never in any request field.Security requirement: Keys should be stored in server-side config files or environment variables, never hardcode into client, never print to logs, never send with requests. If suspected leak, immediately contact official for reset.
Open API HTTP layer basically returns 200. Business result is expressed through result field in response body. Real system-level exceptions are mapped to result=4000, msg="System error, please contact the administrator!".
Note: The status field in response is actually named result (not code). Below is described as "status code" for easier understanding.
Response structure:
{
"result": 0,
"msg": "Request successfully.",
"data": { /* business data */ }
}
result: Status code. 0 means success, non-0 means failure.msg: Status description text, supports i18n. Language determined by Accept-Language header (e.g., en-US, zh-CN), defaults to en-US if not provided.data/obj: Business data carrier, returns specific business object on success.| result | Meaning | Typical msg (en-US) | Trigger Scenario |
|---|---|---|---|
| 0 | Success | Request successfully. | Business processed normally |
| 1 | General failure | (varies) | Business logic validation failed, msg explains details |
| 10000 | Not logged in / Token expired | Please login. / token expired | Token mode: claims invalid or expired |
| 10001 | Signature exception | Signature exception | Signature error, timestamp expired, companyCode/time/sign missing (merged code) |
| 10002 | Incorrect email format | Incorrect email format. | Register/bind email format invalid |
| 10006 | User disabled | The user has been disabled. | Account locked |
| 20000 | Incorrect parameter type | Incorrect parameter type. | Request parameter type mismatch |
| 20001 | Data cannot be empty | Submitted data cannot be empty. | Required parameter missing |
| 20002 | Permission exception | Abnormal permissions. | openApi auth: companyCode not exists, credentials not enabled (flagState!=1), or no operation permission |
| 20003 | Time format error | Time format error. | Date/time parameter format invalid |
| 20004 | Parameter format error | Parameter format error. | Parameter format validation failed |
| 20005 | No such parameter | No this parameter. | Missing required business parameter |
| 20006 | System error, try later | System error, try later. | Server business exception |
| 20007 | DeviceCode does not exist | DeviceCode does not exist | Invalid device type code |
| 20008 | Device off-line | Device off-line | Device has not reported data |
| 20009 | Device not exist | Device not exist | deviceSn not found in system |
| 4000 | System global error | System error, please contact the administrator! | Uncaught exception, transaction rollback, parameter parsing exception (recommend retry or contact official) |