Connecting crypto payments via API

api connection crypto

API connection instructions for developers

  1. You need to get an API key in our system in the “Settings” section. Registration takes approximately 5 seconds. Initial review and confirmation of your store is not necessary. You can start accepting cryptocurrency immediately and withdraw it immediately.
  2. When the order is placed in your online store and the total cost of the order is ready on your part, you create a JSON object, which you send to our server with a POST request.
  3. We register your possible payment request, in response we send you our internal order number and a payment link.
  4. You redirect the user to this payment page, he pays, he is automatically redirected back to your site.
  5. We contact your site with a hidden request and tell you that the order is paid (this is done through the so-called webhook). You put the order in your database as paid (automatically) and then the process is standard for you, like any other paid order.

If your online store is powered by WordPress (WooCommerce), then you don’t need to program anything, we have a ready-made plugin for accepting cryptocurrency, follow the link for instructions and the plugin itself


API description:

Step 2, creating a JSON object (JavaScript example).

Possible values for the blockchain field, take the value from the quotes (for example: tether-trc20):

'tether-erc20' (ERC20 Ethereum USDT, contract: 0xdac17f958d2ee523a2206206994597c13d831ec7)

'tether-bep20' (BEP20 Binance smart chain USDT, contract: 0x55d398326f99059ff775485246999027b3197955)

'tether-trc20' (TRC20 Tron USDT, contract: TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t)

'mitilena-own' (Vanishing Mitilena, VMT token)
'apfcoin' (ERC20 Ethereum APFC, contract: 0x8eD955a2b7d2C3a17a9d05dACa95E01818f8C11e)


let createPaymentObj =
        userSecret: 'your_API_key', // required
        userPaymentId: 'your_payment_id_usually_order_id', // required
        blockchain: 'tether-trc20', // required 
        fiatCode: '3x_ISO_code_of_your_fiat_currency_for example_EUR', // required
        customerEmail: 'customer_mail', // required

        fiatAmount: 'digit_amount_in_fiat_currency_for_example_100', // number, required
        userProductId: 'your_product_id_if_any', // not required
        language: 'two_digit_ISO_language_code', // default en, not required [available: en, cz, ru, tr, my, hr, si, ar, swa] - the rest will be an error
        // redirectUrl_yours: 'thank_you_page or success_page',
        redirectUrl_yours: 'url_on_your_site_where_to_send_user_after_successful_payment', // not required, but very desirable
        webHookPostUrl_yours: 'url_on_your_site_where_the_hidden_POST_request_will_go_on_successful_payment,' // required

In the headers of the request, you also need to insert your API key: ‘mitilena-signature’: ‘your_api_key’
It looks something like this:

headers: {
     'Content-Type': 'application/json',
     accept: 'application/json',
     'mitilena-signature': 'your_key',

And send it as a POST request to the address:

If the creation of the invoice was successful, then the server response will be with the code 200 and the response will contain a JSON object, for example, something like this:
From this response you only need 2 fields, invoiceId and paymentPage. You must send (redirect) the user to the payment page to the Mitilena Pay website [paymentPage field]!

  usdtOverAmount: '1.580437',
  invoiceId: 'auto-e80099-ef456c-e0de42',
  invoiceVs: '0437',
  fiatAmount: '1.450',
  fiatCurrency: 'EUR',
  rateLocalCurrencyToNeededCrypto: '0.917',
  rateNeededCryptoToUSD: '0.99959700',
  isTrc20: 1,
isErc20: 0,
isBep20: 0, whenInit: '2023-08-22T11:30:05.000Z', contractAddress: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', customerEmail: '', productId: 85, expiresAt: '2023-09-05T11:30:05.000Z', blockchainHash: null, cryptoShortCode: 'USDT', cryptoValue: '1.580437', fiatValue: '1.450', receivedOnAddress: 'TRHpcBugcdEdD6BdW6k1Grtof6LBvRGWWJ', txId: 'auto-e80099-ef456c-e0de42', fiatShortCode: 'EUR', wasPaid: null, redirectUrl: '', paymentPage: '' }

If an error occurs, the server response will be with a 400 code and the response will contain a String, the error text.
The lifetime of such a link is 14 days. There are plans to make it possible to choose the lifetime of the link.

JavaScript examples (node.js version 16.8)
const https = require('https');
const url = require('url');

const data = JSON.stringify({
    userSecret: '',
    userPaymentId: 'userPaymentdId111',
    blockchain: 'tether-trc20',
    fiatCode: 'EUR',
    customerEmail: '',

    fiatAmount: 1.45,
    userProductId: 'new_someGoodsOk',
    language: 'en', // default en, not neccessary
    // redirectUrl_yours: '',
    redirectUrl_yours: '',
    webHookPostUrl_yours: ''

const myURL = url.parse('');

const options = {
    hostname: myURL.hostname,
    port: myURL.port,
    path: myURL.pathname,
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        accept: 'application/json',
        'mitilena-signature': '',

requestAsync(options, data)
    .then(dataFObj => {
        if (dataFObj.statusCode === 200) {
            let tokensObj = JSON.parse(dataFObj.dataRaw);
            console.log('success:', tokensObj)
        } else {
            console.log('error dataFObj', dataFObj);
            throw new Error('some errror in postToWebHook ' + dataFObj.dataRaw);
    .catch(e => {
        console.log('error request:', e)

function requestAsync(optionsArr, dataToPost = false) {
    return new Promise((resolve, reject) => {
        const req = https.request(optionsArr, (resp) => {
            // console.log(`statusCode: ${resp.statusCode}`);
            let dataF = '';
            // A chunk of data has been received.
            resp.on('data', (chunk) => {
                dataF += chunk;

            resp.on('end', () => {
                resolve({statusCode: resp.statusCode, dataRaw: dataF});
            }).on('error', (err) => {
                console.log('Error: ' + err);

        if (dataToPost) {


The url module in Node.js above version 16 seems to have changed the syntax, if anything, find information on this topic or enter the address and path manually.

Examples in PHP and WordPress:
Query using a WordPress function wp_remote_post(), check out the pure PHP function, it will look something like this:
$request_body = [
    'userSecret' => $this->mitilenaToken,
    'userPaymentId' => $order->id,    
  'blockchain' => 'tether-trc20', 'fiatCode' => $order->currency,    
  'customerEmail' => $order->get_billing_email(), 'fiatAmount' => $order->get_total(), 'userProductId' => $orderids, 'language' => 'en', // default en, not neccessary 'redirectUrl_yours' => $order->get_checkout_order_received_url(), 'webHookPostUrl_yours' => '' ]; $request_headers = [ 'content-type' => 'application/json', 'mitilena-signature' => $this->mitilenaToken, ]; $args = [ 'method' => 'POST', 'httpversion' => '1.0', 'timeout' => 90, 'headers' => $request_headers, 'body' => '' ]; $environment_url = ''; $result = wp_remote_post($environment_url, array( 'method' => 'POST', 'headers' => $request_headers, 'timeout' => 60, // added 'redirection' => 5, // added 'blocking' => true, // added 'httpversion' => '1.0', 'sslverify' => false, 'body' => json_encode($request_body)) ); $fullObj = json_decode($result['body']); if (isset($result['response']) && isset($result['response']['code']) && $result['response']['code'] != 200) { $mi__err_message = 'Unknown error'; if (isset($result['body'])) { $mi__err_message = 'Error: ' . $result['body']; } // error handling + exit exit; } if (!isset($fullObj->paymentPage)) { http_response_code(400); // Bad Request echo "Error: No payment page specified"; exit; } $paymentPage = $fullObj->paymentPage; if (strlen($paymentPage) < 5) { http_response_code(400); // Bad Request echo "Error: payment page is too short."; exit; } ?>


Step 5, creating a WebHook handler on the side of your site (server):

On the example of Node.js 16.8 version and Express.js 4 version (JavaScript)
const bodyParser = require('body-parser');
const Big = require('big.js')
let endpointSecret = 'copy of the api key value'

// an object called statusObj arrives'/mi_webhook/', bodyParser.json(), (request, response) => {

    try {
        let eventObj = request.body;
        const signature = request.headers['mitilena-signature'];

// compare the incoming secret key with your real one
        if (signature === endpointSecret) {
            if (!eventObj.statusObj) {
                return response.status(400).send('Error, no object.');

            let hookObj = eventObj.statusObj;

            if (
                typeof hookObj.mitilenaInvoiceId === 'undefined' ||
                typeof hookObj.yourPaymentId === 'undefined' ||
                typeof hookObj.yourProductName === 'undefined' ||
                typeof hookObj.yourProductId === 'undefined' ||
                typeof hookObj.secretKey === 'undefined' ||
                typeof hookObj.stableCoinAmount === 'undefined' ||
                typeof hookObj.stableCoinSymbol === 'undefined' ||
                typeof hookObj.stableCoinBlockchain === 'undefined' ||
                typeof hookObj.localCurrencyAmount === 'undefined' ||
                typeof hookObj.localCurrencyCode === 'undefined' ||
                typeof hookObj.wasPaid === 'undefined' ||
                typeof hookObj.blockchainHash === 'undefined'
            ) {
                return response.status(400).send('Error, incomplete object.');

            if (hookObj.wasPaid === true) {
                let centsAmount = Big(hookObj.localCurrencyAmount).times(Big(100)).round(0).toNumber();

// put the order in your database as paid and return the status code 200
// this is an example of our code, yours may look different
                    .completeUserPayment(hookObj.mitilenaInvoiceId, centsAmount)
                    .then((okString) => {
                        return response.status(200).send('all good Mitilena token');
                    .catch((e) => {
                        console.log('err in completeUserCardPayment', e.message);
                        return response.status(400).send('error, contact support');
            } else {
                return response.status(400).send('invoice was not paid');
        } else {
            return response.status(400).send('bad Mitilena token');
    } catch (e) {
        console.log('webhook err:', e.message);
        return response.status(400).send('bad request, error');
Using the PHP example:

Create a handler file and put it on your web server (site) so that it is accessible from the outside, i.e. if you write the full path to the file so that it opens, for example (this is an example, you can do it differently, through routing, etc.).

As mentioned above, specify this address in the object in which you create a payment link, i.e.
webHookPostUrl_yours: ‘’

File contents:

$mi__jsonData = file_get_contents('php://input');
if (!$mi__jsonData) {
    http_response_code(400); // Bad Request
    echo 'bad input data';
// Decode the JSON data into a PHP associative array
$mitilena_data = json_decode($mi__jsonData, true);

// Check if decoding was successful
if ($mitilena_data !== null && isset($mitilena_data['statusObj'])) {
    $mitilena_data = $mitilena_data['statusObj'];

    if (!isset($mitilena_data['secretKey'])) {
        http_response_code(400); // Bad Request
        echo "Error: Api key of Mitilena (Mitilena Token) is not specified. We can't verify if the request is genuine. Cancellation of a transaction.";
    $mitilenaToken = $mitilena_data['secretKey'];

    // compare your real API key with the one you received
    $realMitilenaToken = 'your_api_key'

    if ($mitilenaToken != $realMitilenaToken) {
        http_response_code(400); // Bad Request
        echo "Error: API token does not match. The website owner must specify the correct Api Mitilena token.";

    if (!isset($mitilena_data['yourPaymentId'])) {
        http_response_code(400); // Bad Request
        echo "Error: No payment id specified";
    $mi__paymentId = $mitilena_data['yourPaymentId'];

    if (strlen($mi__paymentId) < 1) {
        http_response_code(400); // Bad Request
        echo "Error: too short payment id.";
    function mi__pay_escapeString($var)
        $var = stripslashes($var);
        $var = htmlentities($var);
        $var = strip_tags($var);
        return $var;

    // yourPaymentId
    try {
        $mi__order = '';  // search your database for this order, mi__pay_escapeString($mi__paymentId)
    } catch (Throwable $e) {
        http_response_code(400); // Bad Request
        echo "Error: wrong payment id (order id). {yourPaymentId: \"\"}";

    if (!isset($mitilena_data['wasPaid'])) {
        http_response_code(400); // Bad Request
        echo "Error: No payment status specified";
    $mi__wasPaid = $mitilena_data['wasPaid'];

    if ($mi__wasPaid == true) {

        $blockchainHash = '';
        if (isset($mitilena_data['blockchainHash'])) {
            $blockchainHash = mi__pay_escapeString($mitilena_data['blockchainHash']);

        // set the order as paid in your database
        // reduce inventory if required
        // send the user an email if required

        echo 'success';
    } else {
        echo 'unpaid status received';
 } else {

    // JSON decoding failed
    http_response_code(400); // Bad Request
    echo "Invalid JSON data";


That’s all, if you have any questions, ask in the comments.

Don’t have a developer to implement this for you? Write to us at, we will make you a commercial proposal for the developer’s work on connecting crypto-payments.

Leave a Reply

Your email address will not be published. Required fields are marked *