> ## Documentation Index
> Fetch the complete documentation index at: https://developers.mioesim.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authenticate with the MIOeSIM API

> Learn how the MIOeSIM two-part auth system works: obtain a session token via login, then sign every request with an HMAC-MD5 signature.

Every MIOeSIM API request requires two security elements: a **token** that identifies your session, and a **sign** that proves the request parameters have not been tampered with. You obtain the token by calling the login endpoint; you compute the sign yourself using an HMAC-MD5 algorithm applied to the sorted request parameters and your secret key.

## Obtaining a token

Call `POST /api_order/login` to exchange your credentials for a session token. The login request itself also requires a `sign` — see [Computing the signature](#computing-the-signature) below for how to generate it.

### Request parameters

<ParamField body="phonenumber" type="string" required>
  Your MIOeSIM account phone number. This is your login username.
</ParamField>

<ParamField body="password" type="string" required>
  Your MIOeSIM account password.
</ParamField>

<ParamField body="sign" type="string" required>
  HMAC-MD5 signature computed from `phonenumber` and `password`. See [Computing the signature](#computing-the-signature).
</ParamField>

### Example request and response

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url "https://bpm.mioesim.com/api_order/login" \
    --header "Content-Type: application/json" \
    --data '{
      "phonenumber": "13800000000",
      "password": "mypassword",
      "sign": "a1b2c3d4e5f6..."
    }'
  ```
</CodeGroup>

```json theme={null}
{
  "code": 1,
  "message": "Successful",
  "data": {
    "token": "29281-9EFE5E410BEF5300DD15E3830BD65601"
  }
}
```

***

## Computing the signature

Every API request — including the login request — requires a `sign` parameter. Compute it using the following algorithm:

1. Collect all request parameters **except** `sign` itself.
2. Format each parameter as `key=value`.
3. Sort the resulting strings alphabetically.
4. Concatenate all sorted strings with no separator.
5. Append your secret key directly to the end of the concatenated string.
6. MD5 hash the full string (UTF-8 encoded).
7. Use the hex digest as the `sign` value.

**Example** — signing a login request with `phonenumber=13800000000` and `password=mypassword`:

```
Step 1-2: ["phonenumber=13800000000", "password=mypassword"]
Step 3:   ["password=mypassword", "phonenumber=13800000000"]
Step 4:   "password=mypasswordphonenumber=13800000000"
Step 5:   "password=mypasswordphonenumber=138000000001234567890qwertyuiopasdfghjklzxc"
Step 6-7: MD5("password=mypasswordphonenumber=138000000001234567890qwertyuiopasdfghjklzxc")
          → <hex-digest>
```

<Warning>
  Your secret key grants full access to your account. Never expose it in client-side code, public repositories, or logs.
</Warning>

### Code examples

<CodeGroup>
  ```java Java theme={null}
  import java.util.*;
  import org.apache.commons.codec.binary.Hex;
  import org.apache.commons.codec.digest.DigestUtils;

  public static String createSign(Map<String, Object> map) throws Exception {
      final String sign_key = "1234567890qwertyuiopasdfghjklzxc";
      StringBuffer buffer = new StringBuffer();
      List<String> arrayList = new ArrayList<String>();
      map.remove("sign");
      for (String item : map.keySet()) {
          arrayList.add(item + "=" + map.get(item));
      }
      Collections.sort(arrayList);
      for (String string : arrayList) {
          buffer.append(string);
      }
      String content = buffer + sign_key;
      byte[] data = content.getBytes("UTF-8");
      return Hex.encodeHexString(DigestUtils.md5(data));
  }
  ```

  ```php PHP theme={null}
  <?php
  function bpm_sign($data_ary) {
      $Sign_key = "1234567890qwertyuiopasdfghjklzxc";
      $Buffer = '';
      $ArrayList = [];
      if (isset($data_ary['sign'])) { unset($data_ary['sign']); }
      foreach ($data_ary as $k => $v) { $ArrayList[] = $k . "=" . $v; }
      sort($ArrayList);
      $Buffer = implode('', $ArrayList);
      $encodeStr = customURLEncode($Buffer . $Sign_key);
      return strtoupper(hash('md5', $encodeStr));
  }

  function customURLEncode($string) {
      return str_replace(['+', '*', '%7E'], ['%20', '%2A', '~'], rawurlencode($string));
  }
  ```

  ```python Python theme={null}
  import hashlib
  import urllib.parse

  sign_key = '1234567890qwertyuiopasdfghjklzxc'

  def creat_sign(value):
      # value is a list of "key=value" strings, with "sign" excluded
      value.sort()
      MD5 = "".join(value) + sign_key
      encoded_str = urllib.parse.quote(MD5, safe='')
      sign_value = hashlib.md5(encoded_str.encode('utf-8')).hexdigest().upper()
      return sign_value
  ```
</CodeGroup>

***

## Using the token

After a successful login, include the `token` and `sign` on every subsequent request. For `GET` requests, pass them as query parameters. For `POST` requests, include them in the request body.

**GET example:**

```bash theme={null}
curl --request GET \
  "https://bpm.mioesim.com/api_esim/getSkus?token=29281-9EFE5E410BEF5300DD15E3830BD65601&sign=<computed-sign>"
```

**POST example:**

```bash theme={null}
curl -X POST https://bpm.mioesim.com/api_esim/addEsimOrder \
  -d "token=29281-9EFE5E410BEF5300DD15E3830BD65601" \
  -d "skuId=26" \
  -d "priceId=441" \
  -d "count=1" \
  -d "backInfo=1" \
  -d "sign=<computed-sign>"
```

Compute the `sign` fresh for each request, using all parameters in that specific request (excluding `sign` itself).

***

## Token expiry

Tokens are valid for **2 hours** from the time of issue. After a token expires, all requests return an authentication error.

To handle expiry gracefully:

* Store the token and its issue timestamp locally.
* Before each request, check whether the token is within 10–15 minutes of its 2-hour expiry.
* If it is, call `POST /api_order/login` to obtain a fresh token before proceeding.

Avoid calling the login endpoint on every request — fetch a new token only when necessary.

***

## Error codes

The login endpoint returns the following error codes in the `code` field of the response:

| Code  | Meaning                               |
| ----- | ------------------------------------- |
| `1`   | Success — token returned in `data`    |
| `-1`  | Wrong username or password            |
| `-2`  | Username or password is empty         |
| `-3`  | Account does not have call permission |
| `-30` | Signature (`sign`) is incorrect       |

If you receive `-30`, verify that your signature algorithm sorts parameters alphabetically and that you are using the correct secret key.
