Skip to content

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

  1. Write the private key.
  2. Add GET, in uppercase.
  3. Add the path of the request, from /terminals/ to ?. For example, /terminals/example_operator/subscription/subscribe.
  4. Sort the query parameters by name, in ascending order. Do not include sign.
  5. Add each parameter as name=value. Do not add ?, & or other separators.
  6. Calculate the SHA-256 hash of the text (UTF-8). Write it as 64 lowercase hexadecimal characters.
  7. Encode these 64 characters with Base64.
  8. Remove the = characters. Replace each / and each + with -.
  9. Add _ and your public key.
  10. Add sign to 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
  1. Write the private key, GET and the path:

    Ex4mpleK3yN0tRealAbCdEfGhIjKlMnOpQrSTGET/terminals/example_operator/subscription/subscribe
    
  2. Add the parameters, sorted by name (phone, then serviceId):

    Ex4mpleK3yN0tRealAbCdEfGhIjKlMnOpQrSTGET/terminals/example_operator/subscription/subscribephone=380000000001serviceId=example_svod
    
  3. Calculate the SHA-256 hash:

    251876030d8bf8d5bdcbd14297ebdd8a6766ac0bdb30fa020856f3d3f036f82a
    
  4. Encode the hash text with Base64:

    MjUxODc2MDMwZDhiZjhkNWJkY2JkMTQyOTdlYmRkOGE2NzY2YWMwYmRiMzBmYTAyMDg1NmYzZDNmMDM2ZjgyYQ==
    
  5. Remove =, replace / and + with -, and add _ and the public key:

    MjUxODc2MDMwZDhiZjhkNWJkY2JkMTQyOTdlYmRkOGE2NzY2YWMwYmRiMzBmYTAyMDg1NmYzZDNmMDM2ZjgyYQ_example_pub
    
  6. Add sign to 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

Guide version 1.0.0, 2026-11-02 · Report a problem on this page