LogoLogo
  • SWAPPLE API
    • Changelog
      • 2022, 26 January
      • 2022, 29 December
      • 2022, 14 June
      • 2024, 11 March
      • 2024, 27 June
      • 2024, 31 July
      • 2024, 27 August
      • 2024, 3 September
    • API Reference
      • Authorization
      • Orders
      • Statuses
      • Currencies
      • Webhook
      • Sandbox
    • Examples and sample usages
      • Sample usage
      • Merchant User Flow
      • Fixed Rate Order Guide
    • FAQ
  • CRYPTO ACQUIRING API
Powered by GitBook
On this page
  • How to sign requests
  • How to verify responses (Optional)
  1. SWAPPLE API
  2. API Reference

Authorization

PreviousAPI ReferenceNextOrders

Last updated 2 months ago

  1. To start working with us, the partner needs to contact us via email. Further communication can be carried out in the agreed communication channel.

  2. There, we have to agree on the points of cooperation, i.e., which pairs, fees we will work with etc. Іmportant - clarify the type of fees (fixed/floating) for which we will work for a specific pair.

  3. The partner needs to exchange keys with our service and implement signature formation and verification of our signature in the code: the partner, on their side, generate a pair of keys (private and public keys) and send us a public key signed with their private key.

    And we, in turn, also generate a pair of keys for the partner and send them our public key signed with our private key.

    With the help of these public keys, a check is made that the request came from specific recipients.

  4. After the configuration by our team, the partner can call the API and fully work with crypto processing.

SWAPPLE API uses RSA-1024 PKCS1 keypair to secure requests.

First of all you need to generate RSA-1024 keys and send us your public key. We will send you our public key so that you can verify our response.

How to sign requests

You need to generate SHA512 hash sign based on request body.

Authentication parameters are transmitted in Headers:

  • public-key

  • signature

  • timestamp - current time in milliseconds (used in sign generation)

An example of generating a signature.

import requests
import binascii
import time
import collections
from decimal import Decimal
from Crypto.Hash import SHA512
from Crypto.Signature.pkcs1_15 import PKCS115_SigScheme
from Crypto.PublicKey import RSA

private_key = b'-----BEGIN RSA PRIVATE KEY-----\nMIICXAIagdfgadfJBdBhOb5mkijXoA/VeGqiIPVjdWth25uI\n369z434y8VMYAcmQ9a44vdutn2Zwq9dVtM35cK+etbtVo/GSDGSDGSD\n8QOIlZn+18+Hd4kWESCiycllJBsjwsNZK3PdnM7s2c6UmFuqesY3MDD/4QIDAQAB\nAoGagdfgadfgadfgadfgadfgdK//VD6lxaKvM5RNz8\nAOTc3WFefN4AnULh1T4vxq1zaPwDWhXj+y3SZjUZs6un8dZ5P6c7vqlILThy7ihJ\nCS04GRTzzybPHDU5c6eMlrm55jBpub3ajyhGgSyWgynY+RECQQC5Y/HSI18kEDWp\nerdbdc6vPs1TkhULAZOzoQXXZhDoEZjF9bRhEcbUHdiKs4+QLMjEP2CVhG/AtZ1r\nibw2A6XdAkEA8I/YzDUr1ns9jI9ZZrshblCdYu3F0Bs01Uwub36ro6LK3aVv8unz\ndxMuJQcsk+hQwnheXGsNi2/qWyC5aW2L1QJAMhEWxpx83j1ucJXOnOmk5tj8FJy4\nCB/l5rYO4MwUtsfBzXx8uVZWrwRcbaDunY4qri07hUWd9JpXqCorZR75FQJADycA\nYNx4hmn81n2xA+eFk41AXJrdet471bOWuS8hYI1AefWRt5tE2ps6rNpm1GotrBIo\n32le0QmbmWHWS+26gQJBALYrgSaKJEG4avc4fwCUF75CIZfiCUWYRSPndyQljXf0\n0XOhVNGDqFbQCtlggQ4Z+zxDoVM5LGZqw0XEIjd+/wc=\n-----END RSA PRIVATE KEY-----'
public_key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuNd6JS7plbbj3XvsJBdBhOb5mkijXoA/VeGqiIPVjdWth25uI369z434y8VMYAcmQ9a44vdutn2Zwq9dagdfgadfgadfbcvxn+18+Hd4kWESCiycllJBsjwsNZK3PdnM7s2c6UmFuqesY3MDD/4QIDAQAB" # no comments


SWAPPLE_ROOT_API_URL = "https://api.swapple.org/api/v3"


def request_body_to_str_line(body, timestamp):
    body = collections.OrderedDict(sorted(body.items()))
    line = ""
    for value, keys in body.items():
        if keys:
            try:
                line += value.lower() + str(Decimal(str(keys)))
            except Exception:
                line += value.lower() + str(keys).lower()
    line += "timestamp" + timestamp
    return line


def request_sign(body, timestamp):
    line = request_body_to_str_line(body, timestamp)
    new_hash = SHA512.new(line.encode())
    signer = PKCS115_SigScheme(RSA.importKey(private_key))
    sign = signer.sign(new_hash)
    return binascii.hexlify(sign).decode("utf-8")


def get_authorization_headers(body):
    timestamp = str(int(time.time()))
    signature = request_sign(body, timestamp)
    return {
        "public-key": public_key, 
        "signature": signature, 
        "timestamp": timestamp,
    }


body = {"from": "CARDUAH", "fromAmount": "5000", "to": "USDT","toNetwork": "TRX"}

requests.post(
    f"{SWAPPLE_ROOT_API_URL}/estimate-amount",
    json=body,
    headers=get_authorization_headers(body)
)
<?php
require 'vendor/autoload.php';

use phpseclib\Crypt\RSA;

// Read private key from file
$privateKeyFilePath = 'private_key.pem';
$privateKey = file_get_contents($privateKeyFilePath);

// Read public key from file
$publicKeyFilePath = 'public_key.pem';
$publicKey = file_get_contents($publicKeyFilePath);

$rsa = new RSA();
$rsa->loadKey($privateKey);
$rsa->setHash('sha512');
$rsa->setMGFHash('sha512');
$rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);

$body = ["from" => "CARDUAH", "fromAmount" => "5000", "to" => "USDT"];
$timestamp = strval(time());
$line = '';

foreach ($body as $key => $value) {
    $line .= strtolower($key) . strtolower($value);
}

$line .= 'timestamp' . $timestamp;
echo $line;


$signature = $rsa->sign($line);
$signatureHex = bin2hex($signature);;

$headers = [
    'public-key' => $publicKey,
    'signature' => $signatureHex,
    'timestamp' => $timestamp,
];
echo '<pre>'; print_r($headers); echo '</pre>';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.swapple.org/api/v3/estimate-amount");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    "Content-Type: application/json",
    "public-key: " . $headers['public-key'],
    "signature: " . $headers['signature'],
    "timestamp: " . $headers['timestamp']
));

$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
const crypto = require('crypto');
const fs = require('fs');
 
const privateKey = fs.readFileSync('private_key.pem');
const timestamp = '1678367651';
 
function requestBodyToStrLine(body, timestamp) {
  const sortedBody = Object.entries(body).sort();
  let line = '';
  for (const [key, value] of sortedBody) {
    if (value) {
      line += key.toLowerCase() + value.toString().toLowerCase();
    }
  }
  line += 'timestamp' + timestamp;
  console.log(line);
  return line;
}
 
function requestSign(body, timestamp) {
  const line = Buffer.from(requestBodyToStrLine(body, timestamp));
  
  // Створення об'єкту для генерації підпису
  const signer = crypto.createSign('RSA-SHA512');
  
  // Додавання даних для підпису
  signer.update(line);
  
  // Генерація підпису
  const signature = signer.sign(privateKey, 'hex');
  return signature
}
 
const body = {
  from: 'CARDUAH',
  to: 'USDT',
  fromAmount: 20,
  rateType: 'FLOATING',
  fromNetwork: null,
  toNetwork: 'TRC20'
};
 
console.log(requestSign(body, timestamp));
package main

import (
	"bytes"
	"crypto"

	"crypto/rsa"
	"crypto/sha512"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"time"
)

var privateKey *rsa.PrivateKey
var publicKey string

func initKeys(privateKeyPath, publicKeyPath string) {
	// Read private key from file
	privateKeyData, err := ioutil.ReadFile(privateKeyPath)
	if err != nil {
		panic(err)
	}
	privateKeyBlock, _ := pem.Decode(privateKeyData)
	if privateKeyBlock == nil {
		panic("failed to parse private key")
	}
	privateKey, err = x509.ParsePKCS1PrivateKey(privateKeyBlock.Bytes)
	if err != nil {
		panic(err)
	}
}

func generateTimestamp() string {
	return strconv.FormatInt(time.Now().Unix(), 10)
}

func generateSignature(body map[string]interface{}, timestamp string) string {
	// Create sorted string from the request body and timestamp
	var keys []string
	for k := range body {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	var messageParts []string
	for _, k := range keys {
		v := body[k]
		var valueString string
		switch v := v.(type) {
		case float64:
			valueString = strconv.FormatFloat(v, 'f', -1, 64)
		case string:
			valueString = v
		}
		messageParts = append(messageParts, strings.ToLower(k)+valueString)
	}
	messageParts = append(messageParts, "timestamp"+timestamp)
	message := strings.ToLower(strings.Join(messageParts, ""))
	// Calculate SHA-512 hash
	hash := sha512.New()
	hash.Write([]byte(message))
	hashed := hash.Sum(nil)

	// Sign the hash with the private key
	signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA512, hashed)
	if err != nil {
		panic(err)
	}

	// Encode the signature to hexadecimal format
	signatureHex := fmt.Sprintf("%x", signature)
	return signatureHex
}

func main() {
	// Paths to private and public key files
	privateKeyPath := "private_key.pem"
	publicKeyPath := "public_key.pem"

	// Initialize keys
	initKeys(privateKeyPath, publicKeyPath)

	// Sample request body
	body := map[string]interface{}{
		"fromAmount": "100",
		"from": "CARDUAH",
		"to": "ETH",
	}

	// Generate timestamp and signature
	timestamp := "1"
	signature := generateSignature(body, timestamp)

	// Create HTTP headers
	headers := map[string]string{
		"public-key": publicKey,
		"signature":  signature,
		"timestamp":  timestamp,
	}
	fmt.Println(headers)

	// Send POST request
	url := "https://api.swapple.org/api/v3/estimate-amount"
	bodyJSON, err := json.Marshal(body)
	if err != nil {
		panic(err)
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(bodyJSON))
	if err != nil {
		panic(err)
	}

	for key, value := range headers {
		req.Header.Set(key, value)
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	// Handle abex response
	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	fmt.Println("Status Code:", resp.StatusCode)
	fmt.Println("Response Body:", string(responseBody))
}

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

To make a request, the partner needs two things - a public key and a private key.

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

The following is a method that will turn a request:

def request_body_to_str_line(body, timestamp):
body = collections.OrderedDict(sorted(body.items()))
line = ""
for value, keys in body.items():
if keys:
try:
line += value.lower() + str(Decimal(str(keys)))
except Exception:
line += value.lower() + str(keys).lower()
line += "timestamp" + timestamp
return line

So, the output is a string to sign.

Next are two methods for signing:

def request_sign(body, timestamp):
line = request_body_to_str_line(body, timestamp)
new_hash = SHA512.new(line.encode())
signer = PKCS115_SigScheme(RSA.importKey(private_key))
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(body):
timestamp = str(int(time.time()))
signature = request_sign(body, timestamp)
return {
"public-key": public_key,
"signature": signature,
"timestamp": timestamp,
}

How to verify responses (Optional)

We sign our responses the same way you sign a request. Though this step is optional we strongly advise on verifying responses.

You will receive three parameters in headers: public-key, signature and timestamp.

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]