Cryptoacquiring Production: API Docs
  • CRYPTO ACQUIRING: TECHNNICAL
    • Authorization
    • Formation of an order
    • Callbacks
    • Alternative cases
    • How to check that your integration works?
    • Fees
    • Sandbox and Production
  • CRYPTO ACQUIRING SANDBOX
Powered by GitBook
On this page
  1. CRYPTO ACQUIRING: TECHNNICAL

Authorization

PreviousCRYPTO ACQUIRING: TECHNNICALNextFormation of an order

Last updated 8 months ago

  1. To start working with us, you need to contact us via email and agree on cooperation.

  2. There, our team will communicate with you on which currency you can work with us (it’s only EUR now), what currency you can receive payments (also only EUR) and current fees.

  3. Next, you need to exchange keys with our service and implement signature formation and verification of our signature in the code: you, on your side, generate a pair of keys (private and public keys) and send us a public key signed with your private key. And we, in turn, also generate a pair of keys for you and send you our public key signed with our private key. With the help of these public keys, a check is made that the request really came from specific recipients.

* For a more detailed understanding of request signing, please read the information below:

To make a request, you need two things - a public key and a private key.

Next, you need to form a request to us according to our documentation, and this request needs to be signed with the private key.

The following request_body_to_str_line is a method that will turn a request:

import collections
import decimal


def stringify_value(value: str) -> str:
    """
    Convert the value to a decimal string or a lower case string.

    :param value: The value to be converted.
    :return: The converted value as a string.
    """
    try:
        # Try to convert value to a decimal string.
        decimal_value = Decimal(str(value))
    except decimal.InvalidOperation:
        # If not possible, convert the value to a lower case string.
        return str(value).lower()

    return str(decimal_value)


def request_body_to_str_line(body: dict, timestamp: str) -> str:
    """
    Convert the body of the request to a string line.

    :param body: The body of the request as a dictionary.
    :param timestamp: The timestamp as a string.
    :return: The string line.
    """
    sorted_body = collections.OrderedDict(sorted(body.items())) if isinstance(body, dict) else {}
    line = "".join(f"{key.lower()}{stringify_value(value)}" for key, value in sorted_body.items() if value)
    line += f"timestamp{timestamp}"
    return line.lower()

So, the output is a string to sign.

Next are two methods for signing:

def request_sign(body: dict, timestamp: str, private_key_pem: bytes) -> str:
    """
    Generate the request signature.

    :param body: The body of the request as a dictionary.
    :param timestamp: The timestamp as a string.
    :param private_key_pem: The private key as a PEM string.
    :return: The request signature as a string.
    """
    line = request_body_to_str_line(body, timestamp)
    new_hash = SHA512.new(line.encode())
    signer = PKCS115_SigScheme(RSA.importKey(private_key_pem))
    sign = signer.sign(new_hash)
    return binascii.hexlify(sign).decode('utf-8')

Here, body and timestamp are transferred, then the previous function is called and the next four lines form the signature:

  • hash - we take it from the string we received

  • create a signer object - the one who has to sign based on our private key

  • then we sign the hash we got in the line above

  • and return it as a string - this decodes the signature into a string.

And that's the result of the signature that needs to be added to the request.

Next, we generate a request that has a timestamp (i.e. the current time), a signature that calls the previous function and we transfer the public key, the signature we generated, and the timestamp we received and based on which we generated the signature:

def get_authorization_headers(private_key_pem: bytes, public_key: str, body: dict) -> dict:
    """
    Get the authorization headers.

    :param private_key_pem: The private key as a PEM string.
    :param public_key: The public key as a string.
    :param body: The body of the request as a dictionary.
    :return: The authorization headers as a dictionary.
    """
    timestamp = str(int(time.time()))
    signature = request_sign(body, timestamp, private_key_pem)

    return {
        'public-key': public_key,
        'signature': signature,
        'timestamp': timestamp,
    }

The partner can verify the responses from us (this is optional). But they can do it to be more confident. In fact, this is already our response, and then you take it and check it, having our public key.

Here is an example of response verification:

import binascii
from Crypto.Hash import SHA512
from Crypto.Signature.pkcs1_15 import PKCS115_SigScheme


def response_body_to_str_line(body, timestamp):
    line = ""
    body = collections.OrderedDict(sorted(body.items()))
    for value, keys in body.items():
        line += value + keys
        line += "timestamp" + timestamp
        line = line.lower()
    return line
    
def verify_signature(body, headers):
    line = response_body_to_str_line(body, headers.get('timestamp'))
    client_sign = headers.get('signature')
    hash = SHA512.new(line.encode())
    verifier = PKCS115_SigScheme(headers.get('public-key'))
    try:
        verifier.verify(hash, binascii.unhexlify(client_sign))
        return True
    except:
        return False
[email protected]