Sign a request¶
All requests must have the sign parameter. MEGOGO uses it to identify
your key pair and to make sure that nobody changed the request. This page
shows how to calculate the signature, with a worked example and code.
The algorithm¶
- Write the private key.
- Add
GET, in uppercase. - Add the path of the request, from
/terminals/to?. For example,/terminals/example_operator/subscription/subscribe. - Sort the query parameters by name, in ascending order. Do not include
sign. - Add each parameter as
name=value. Do not add?,&or other separators. - Calculate the SHA-256 hash of the text (UTF-8). Write it as 64 lowercase hexadecimal characters.
- Encode these 64 characters with Base64.
- Remove the
=characters. Replace each/and each+with-. - Add
_and your public key. - Add
signto the URL.
text = private_key + "GET" + path + "name1=value1name2=value2" (sorted by name)
sign = base64(sha256_hex(text)) without "=", "/" and "+" → "-", + "_" + public_key
CAUTION
Encode the hexadecimal text of the hash, not the binary hash. The
result has 86 characters before _.
Parameter values¶
- Use the values before URL encoding. For example, use
+380000000001, not%2B380000000001. - Encode the values only in the URL. Encode
+as%2B: a+in a URL is a space. - Include all parameters that you send. A parameter that is in the URL but not in the signature gives HTTP 401.
Worked example¶
The example uses invented values:
| Value | Example |
|---|---|
| Partner ID | example_operator |
| Public key | example_pub |
| Private key | Ex4mpleK3yN0tRealAbCdEfGhIjKlMnOpQrST |
| Phone number | 380000000001 |
| Service ID | example_svod |
| Request | GET /terminals/example_operator/subscription/subscribe?phone=380000000001&serviceId=example_svod |
-
Write the private key,
GETand the path:Ex4mpleK3yN0tRealAbCdEfGhIjKlMnOpQrSTGET/terminals/example_operator/subscription/subscribe -
Add the parameters, sorted by name (
phone, thenserviceId):Ex4mpleK3yN0tRealAbCdEfGhIjKlMnOpQrSTGET/terminals/example_operator/subscription/subscribephone=380000000001serviceId=example_svod -
Calculate the SHA-256 hash:
251876030d8bf8d5bdcbd14297ebdd8a6766ac0bdb30fa020856f3d3f036f82a -
Encode the hash text with Base64:
MjUxODc2MDMwZDhiZjhkNWJkY2JkMTQyOTdlYmRkOGE2NzY2YWMwYmRiMzBmYTAyMDg1NmYzZDNmMDM2ZjgyYQ== -
Remove
=, replace/and+with-, and add_and the public key:MjUxODc2MDMwZDhiZjhkNWJkY2JkMTQyOTdlYmRkOGE2NzY2YWMwYmRiMzBmYTAyMDg1NmYzZDNmMDM2ZjgyYQ_example_pub -
Add
signto the URL:https://billing.megogo.net/terminals/example_operator/subscription/subscribe?phone=380000000001&serviceId=example_svod&sign=MjUxODc2MDMwZDhiZjhkNWJkY2JkMTQyOTdlYmRkOGE2NzY2YWMwYmRiMzBmYTAyMDg1NmYzZDNmMDM2ZjgyYQ_example_pub
More examples with the same keys:
| Request | Text before the hash | sign |
|---|---|---|
subscriptions |
…GET/terminals/example_operator/subscriptions |
NjAwOGFmZDkyYzc1OTAyNzQ1NzEzZWRkNWIwZTY5NGRjMDgwZWNkN2UwZjc5ZmM0ZTQ2YmEwNWRlMTg3NzEyYg_example_pub |
user/phone, phone=380000000001 |
…GET/terminals/example_operator/user/phonephone=380000000001 |
MjdhZTU2NzQ4YjAxMTI1NmQ0NGU5OWFkN2Y1OGRhNGM5ZDk2MDljODY4N2MwMzE4MzI3YTlkZGM2ZTE5YmFhMw_example_pub |
user/phone, phone=+380000000001 |
…GET/terminals/example_operator/user/phonephone=+380000000001 |
YWU1MjYwZDcxNTA4NDg5MzM4ZjkwNjhjNWIyMTBhZWNhYTVkZjY2N2FlMzE2MjY4Nzk1OWEzMmJlZmVjN2QxZA_example_pub |
subscriptions, phone=380000000001 |
…GET/terminals/example_operator/subscriptionsphone=380000000001 |
OWU1MGI2YjdjNDBlYTEyNTdlYmRjZWU4OWVjYmJkZDVhNTkwNDVhNmU3MDg1YzRiYmIxZGFkZDYxMzkzMGI3NQ_example_pub |
… is the private key. Use these examples to test your code.
Code¶
The functions get the path and the parameters. They sort the parameters themselves.
import base64
import hashlib
from urllib.parse import urlencode
def terminals_sign(path, params, private_key, public_key):
text = private_key + "GET" + path
text += "".join(f"{name}={params[name]}" for name in sorted(params))
digest = hashlib.sha256(text.encode("utf-8")).hexdigest()
sign = base64.b64encode(digest.encode("ascii")).decode("ascii")
sign = sign.replace("=", "").replace("/", "-").replace("+", "-")
return sign + "_" + public_key
def signed_url(path, params, private_key, public_key):
query = dict(params, sign=terminals_sign(path, params, private_key, public_key))
return "https://billing.megogo.net" + path + "?" + urlencode(query)
print(signed_url("/terminals/example_operator/subscription/subscribe",
{"phone": "380000000001", "serviceId": "example_svod"},
"Ex4mpleK3yN0tRealAbCdEfGhIjKlMnOpQrST", "example_pub"))
const crypto = require("crypto");
function terminalsSign(path, params, privateKey, publicKey) {
const names = Object.keys(params).sort();
const text = privateKey + "GET" + path + names.map((n) => `${n}=${params[n]}`).join("");
const digest = crypto.createHash("sha256").update(text, "utf8").digest("hex");
const sign = Buffer.from(digest, "ascii").toString("base64")
.replace(/=/g, "").replace(/[/+]/g, "-");
return sign + "_" + publicKey;
}
function signedUrl(path, params, privateKey, publicKey) {
const query = new URLSearchParams({ ...params, sign: terminalsSign(path, params, privateKey, publicKey) });
return "https://billing.megogo.net" + path + "?" + query;
}
console.log(signedUrl("/terminals/example_operator/subscription/subscribe",
{ phone: "380000000001", serviceId: "example_svod" },
"Ex4mpleK3yN0tRealAbCdEfGhIjKlMnOpQrST", "example_pub"));
<?php
function terminals_sign(string $path, array $params, string $privateKey, string $publicKey): string {
ksort($params, SORT_STRING);
$text = $privateKey . 'GET' . $path;
foreach ($params as $name => $value) {
$text .= $name . '=' . $value;
}
$sign = base64_encode(hash('sha256', $text));
$sign = str_replace(['=', '/', '+'], ['', '-', '-'], $sign);
return $sign . '_' . $publicKey;
}
function terminals_signed_url(string $path, array $params, string $privateKey, string $publicKey): string {
$params['sign'] = terminals_sign($path, $params, $privateKey, $publicKey);
return 'https://billing.megogo.net' . $path . '?' . http_build_query($params, '', '&', PHP_QUERY_RFC3986);
}
echo terminals_signed_url('/terminals/example_operator/subscription/subscribe',
['phone' => '380000000001', 'serviceId' => 'example_svod'],
'Ex4mpleK3yN0tRealAbCdEfGhIjKlMnOpQrST', 'example_pub'), "\n";
All three examples give the URL from step 6 of the worked example.
NOTE
In PHP, hash('sha256', $text) gives the hexadecimal text. Do not set
the third parameter (binary) to true.
Errors¶
| Response | Cause | Action |
|---|---|---|
HTTP 401, "message": "Not Authorized" |
The signature is not correct or not in the request. Or the partner ID or the public key is not known. Or the IP address of your server is not in the list | Use the worked example to test your code. Make sure that the request comes from a server in the list. See Credentials |
HTTP 400, "message": "Invalid request format" |
A required parameter is not in the request, or it is empty | Read the API reference |
Related pages¶
Guide version 1.0.0, 2026-11-02 · Report a problem on this page