> ## 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.

# PHP integration guide for the MIOeSIM API

> Authenticate with MIOeSIM and make signed API calls from PHP using built-in hash functions and cURL. Full working examples with no external dependencies.

This guide shows you how to compute the request signature, log in to obtain a session token, and make authenticated API calls — all in PHP with no external dependencies.

## Computing the signature

Every request to the MIOeSIM API requires a `sign` parameter. Use the `bpm_sign` function below to compute it.

```php sign.php theme={null}
<?php

function bpm_sign($data_ary) {
    if (!is_array($data_ary)) {
        return '';
    }

    $Sign_key = "1234567890qwertyuiopasdfghjklzxc";

    // Remove "sign" if already present — it must not be part of the input
    if (isset($data_ary['sign'])) {
        unset($data_ary['sign']);
    }

    // Format each parameter as "key=value"
    $ArrayList = [];
    foreach ($data_ary as $k => $v) {
        $ArrayList[] = $k . "=" . $v;
    }

    // Sort alphabetically and concatenate
    sort($ArrayList);
    $Buffer = implode('', $ArrayList);

    // URL-encode the concatenated string plus secret key, then MD5-hash it
    $encodeStr = customURLEncode($Buffer . $Sign_key);
    return strtoupper(hash('md5', $encodeStr));
}

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

The function:

1. Removes `sign` from the array so it is never part of the input.
2. Formats each remaining parameter as `key=value` and sorts them alphabetically.
3. Concatenates the sorted strings, appends your secret key, and URL-encodes the result with `customURLEncode`.
4. Returns the uppercase MD5 hex digest of the encoded string.

### Why `customURLEncode` is needed

PHP's `rawurlencode` encodes the string according to RFC 3986, but produces output that differs slightly from the encoding expected by the MIOeSIM signing algorithm:

| Character | `rawurlencode` output | `customURLEncode` output |
| --------- | --------------------- | ------------------------ |
| space     | `+`                   | `%20`                    |
| `*`       | `*`                   | `%2A`                    |
| `~`       | `%7E`                 | `~`                      |

Always pass the pre-signature string through `customURLEncode` before hashing. Skipping this step produces an incorrect signature.

<Warning>
  Never include your secret key in client-side code, public repositories, or logs. Treat it like a password.
</Warning>

## Logging in

Call `POST /api_order/login` to exchange your phone number and password for a session token. The login request itself must include a valid `sign`.

```php login.php theme={null}
<?php

function login($phonenumber, $password) {
    $params = [
        'phonenumber' => $phonenumber,
        'password'    => $password,
    ];
    $params['sign'] = bpm_sign($params);

    $ch = curl_init('https://bpm.mioesim.com/api_order/login');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));

    $response = curl_exec($ch);
    curl_close($ch);

    $data = json_decode($response, true);
    if ($data['code'] === 1) {
        return $data['data']['token'];
    }

    throw new RuntimeException('Login failed: ' . $data['message']);
}

$token = login('YOUR_PHONE_NUMBER', 'YOUR_PASSWORD');
echo "Token: " . $token . PHP_EOL;
```

A successful response returns a token in the `data` field:

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

Pass the returned token to every subsequent API call.

## Making authenticated API calls

After login, include both `token` and `sign` on every request. The example below calls `GET /api_esim/getSkus` to retrieve available eSIM packages.

```php get-skus.php theme={null}
<?php

function getSkus($token) {
    $params = [
        'token' => $token,
    ];
    $params['sign'] = bpm_sign($params);

    $url = 'https://bpm.mioesim.com/api_esim/getSkus?' . http_build_query($params);

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $response = curl_exec($ch);
    curl_close($ch);

    return json_decode($response, true);
}

$skus = getSkus($token);
print_r($skus);
```

Build the parameter array with `token` first, compute `sign` from that array, then add `sign` to the array before appending it to the request URL.

<Note>
  Tokens are valid for **2 hours**. Store the token and its issue time, then re-authenticate before the token expires rather than calling login on every request.
</Note>

<Tip>
  Replace `'YOUR_PHONE_NUMBER'` and `'YOUR_PASSWORD'` with your actual MIOeSIM account credentials before running the code.
</Tip>
