# Access
# Before Accessing
- Please ensure that the appropriate permissions are enabled for API access. Unauthorized API access attempts may result in account suspension.
- Please confirm that the access frequency limit is configured properly. Exceeding the limit will result in a temporary suspension.
- Please take appropriate measures to prevent reentrancy, as network issues may cause multiple callbacks which result in duplicate callback messages being sent to the accessing party, and this can have an adverse impact on users.
- Please verify the pushed data to avoid data falsification or loss.
- Users can only get information about drivers in their fleet.
# Request Access to Relevant Keys
To request access keys and decryption keys, please go to fleet website > Account > open api. Keys will be provided once your request is approved by the reviewer.
# API Portals
Production Environment:
https://open-jelly-ru.didiglobal.com/
Sandbox Environment:
https://open-jelly-ru-sim.didiglobal.com
# Service Calling
Production Environment:
//Driver Balance Management
curl -X POST
-H "Content-Type: application/json"
-H "Authorization: bearer {cid}|{access_token}"
-d 'json {
"fleet_id": 10000000000000,
"driver_id": 50000000000000,
"location_country": "RU",
"lang": "ru-RU"
}'
'https://open-jelly-ru.didiglobal.com/biz/fleet/open-api/drivers/getBalance'
2
3
4
5
6
7
8
9
10
11
Sandbox Environment:
//Driver Balance Management
curl -X POST
-H "Content-Type: application/json"
-H "Authorization: bearer {cid}|{access_token}"
-d 'json {
"fleet_id": 10000000000000,
"driver_id": 50000000000000,
"location_country": "RU",
"lang": "ru-RU"
}'
'https://open-jelly-ru-sim.didiglobal.com/biz/fleet/open-api/drivers/getBalance'
2
3
4
5
6
7
8
9
10
11
Note
domain + "/biz" + api_url is required to call service API Don’t forget "/biz"
# Security Verification
Method: POST
URL: /oauth/token
Feature: Oauth2.0 Verification
Requested Parameters:
| Parameter Name | Type | Description |
|---|---|---|
| grant_type | string | Request mode. Only two modes are supported. i.Client mode: client_credentials ii. Refresh token: refresh_token |
| scope | string | Requested permissions list. |
| _ | string | Current time, the format is "2006-01-02T15:04:05-0700", valid for 10 minutes. Not checked in test environment |
| nostr | string | A random string. 6 characters with a combination of digits and letters (not case sensitive) |
| refresh_token | string | refresh_token field received when requesting token(Required for refreshing) |
Scope Value Ranges
| Scope Value | Description |
|---|---|
| fleet | fleet features |
Request token:
curl -X POST -H "Content-Type: application/json"
-H "Authorization: Bearer {cid}|{sign}"
-d '{"grant_type":"client_credentials","_":"2016-07-01T10:00:00+0800""nostr":"123abc"}'
'https://open-jelly-ru.didiglobal.com/oauth/token'
2
3
4
Refresh token:
curl -X POST -H "Authorization: Bearer {cid}|{sign}"
-H "Content-Type: application/json"
-d '{"grant_type":"refresh_token","refresh_token":"43713d0303-49c60a08fe-835c9fc1fe","_":"2016-07-01T11:00:00+0800","nostr":"123abc"}'
'https://open-jelly-ru.didiglobal.com/oauth/token'
2
3
4
Normal Return:
| Parameter Name | Type | Description |
|---|---|---|
| access_token | string | Access token. Must be provided by header when requesting other APIs. Multiple tokens can be active on the platform at once |
| refresh_token | string | Refresh token, which is used when the access_token expires. This token can only be valid one time. After refreshing, a new refresh_token will be assigned. The token does not have a fixed expiration date |
| expires_in_second | int | access_token’s validity period (seconds) |
| token_type | string | token type, bearer/mac. Only bear type is supported. |
| scope | string | token access level (same as the requested level) |
Note
Frequency limit for requesting a token: Platform <= 10 times/day; Refresh <= 10 times/day. Once this limit is exceeded, the account will be suspended for 24 hours
Returned Result:
http status
- 200 indicates the request is valid
- Non-200 indicates a request error
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"access_token": "didiCB5DEFD8086CE8EAC49CFDCFFA3BF94E66BFC287113521F868B9257E8782D0DB978B81A04133BA5968D9B15B6A4655A9B3B8E7E856ED69BC1FF5848DC784C5080523D74F1AA6B2AC310219BAD3CDE24DF60E61A83B67565B0FC63DE417858FF4",
"refresh_token": "bd01a0d243-e4a056f463-138c7a00fd",
"expires_in_second": 259200,
"token_type": "bearer",
"scope": "calling_car"
}
2
3
4
5
6
7
Description:
- Request data format must be in json
- header should contain the accessing party’s id and signature. Authorization: bearer {cid}|{sign}. bearer represents the token type. cid is the assigned accessing party id, which is connected to the signature sign with "|"
- Signature algorithm
php version
function generalCreateSign( $aData = array(), $sKey = '' )
{
if ( empty( $aData ) || ! is_string( $sKey ) ) { //Signature data cannot be blank, and key must be a string
return FALSE;
}
ksort( $aData ); //Signature data is sorted by key value in the dictionary order
$str = '';
foreach ( $aData as $k => $v ) {
if ( empty( $v ) && $v !== 0 ) { //Empty key value is not used in signature
continue;
}
if ( is_array( $v ) ) {
$v = json_encode( $v );
}
$str .= trim( $k ) . '=' . trim( $v ) . '&'; //Key1=Value1&Key2=Value2...
}
$str = trim( $str, '&' ); //Remove & characters at two ends of the string
return md5( md5( $str ) . $sKey ); //2 times md5, key is the signature assigned to the accessing party's key
}
golang version
func generalCreateSign(req GetTokenReq, clientSecret string) string {
reqData := map[string]string{}
keys := []string{}
t := reflect.TypeOf(req)
v := reflect.ValueOf(req)
for i := 0; i < t.NumField(); i++ {
tag := t.Field(i).Tag.Get("json")
value := v.Field(i).String() // req All fields are string type
reqData[tag] = value
keys = append(keys, tag)
}
// Sort by dictionary order
sort.Strings(keys)
sign := ""
for _, k := range keys {
if reqData[k] == "" {
continue
}
// k1=v1&k2=v2...
sign += strings.TrimSpace(k) + "=" + strings.TrimSpace(reqData[k]) + "&"
}
sign = strings.Trim(sign, "&")
withSecret := fmt.Sprintf("%x", md5.Sum([]byte(sign))) + clientSecret
return fmt.Sprintf("%x", md5.Sum([]byte(withSecret)))
}
c# version
public static string GenerateMD5(string txt)
{
byte[] buffer = Encoding.Default.GetBytes(txt);
byte[] newBuffer = MD5.Create().ComputeHash(buffer);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < newBuffer.Length; i++)
{
sb.Append(newBuffer[i].ToString("x2"));
}
return sb.ToString();
}
public static string GeneralCreateSign(IDictionary parameters, string secret)
{
IDictionary sortedParams = new SortedDictionary(parameters);
IEnumerator> iterator = sortedParams.GetEnumerator();
StringBuilder strBuilder = new StringBuilder();
while (iterator.MoveNext())
{
string key = iterator.Current.Key;
string value = iterator.Current.Value;
if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
{
strBuilder.Append(key).Append("=").Append(value).Append("&");
}
}
string finalString = strBuilder.ToString().Trim('&');
string result = GenerateMD5(GenerateMD5(finalString) + secret);
return result;
}
java version
public static String Md5(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException {
byte s[] = MessageDigest.getInstance("md5").digest(str.getBytes("UTF8"));
String Md5String = "";
for (int i = 0; i < s.length; i++) {
Md5String += Integer.toHexString((0x000000FF & s[i]) | 0xFFFFFF00).substring(6);
}
return Md5String;
}
public static Map sortMapByKey(Map map) {
if (map == null || map.isEmpty()) {
return null;
}
Map sortMap = new TreeMap(new Comparator() {
public int compare(String obj1, String obj2) {
return obj1.compareTo(obj2);//Sort by ascending
}
});
sortMap.putAll(map);
return sortMap;
}
public static String CreateSign(Map params, String key) throws Exception {
if (key.isEmpty() || params.isEmpty()){
throw new Exception("sign key is empty or param is empty");
}
// Sort
params = sortMapByKey(params);
Iterator> it = params.entrySet().iterator();
String sign = "";
while (it.hasNext()){
Map.Entry entry = it.next();
String k = entry.getKey();
String v = entry.getValue();
if (!v.isEmpty()){
sign+=k.trim()+"="+v.trim()+"&";
}
}
// Remove & at the end
sign = sign.substring(0,sign.length()-1);
// md5
return Md5(Md5(sign)+key) ;
}