Authentication

Guide

  • Alchemy Pay will issue a pair of merchantCode&privatekey for each partner once onboarded with Alchemy Pay. The merchantCode is used to identify the partner, while privatekey is for signature purposes.
  • merchantCode&privatekey will be delivered to the partner upon request from Alchemy Pay's operation team. There is currently no online service for self-apply.
  • Under no circumstances expose the privatekey in any API request.

Signature

Mutual authentication is implemented. For requests, the caller needs to compute a digital signature and add the signature as part of the HTTP body. Conversely, for responses, Alchemy Pay provides its signature in the HTTP body in the response. The request signature is generated as follows:

StepDescriptionExample
1Sort all parameters in ascending order according to parameter namesParameter list: abc=value1 bcd=value2 bad=value3
Sort result: abc=value1 bad=value3 bcd=value2
2Connect all parameters with '&' with stringAabc=value1&bad=value3&bcd=value2
3Combine the stringA with ‘&’with key=privatekey to stringB. key is case sensitive must be with low caseabc=value1&bad=value3&bcd=value&key=privatekey.
4MD5 the stingB with upper caseMD5(stringB).toUpperCase();
5Save the signature in HTTP body

Sign demo for Page integration

package com.example;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import java.util.TreeMap;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.util.Random;
public class nft {

    private final static String CHARSET = "UTF-8";

    public static String sign(String s, String key) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA1");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(CHARSET), mac.getAlgorithm());
        mac.init(secretKeySpec);
        byte[] hash = mac.doFinal(s.getBytes(CHARSET));
        return DatatypeConverter.printBase64Binary(hash);
    }

    public static void main(String[] args) throws Exception {
        final String APP_ID = "ahzxh0klegv1fzol";
        final String APP_SECRET = "py2bwighth62ajq6";
                String signStr = "amount=3000&appId=ahzxh0klegv1fzol&callbackUrl=https://alchemypay.org&fiat=USD&merchantName=merchantName&merchantOrderNo=ACH100001234&name=nftname&nonce=1862325104&picture=https://download.bit.store/official/BitStore/pic/user_portrait/20.jpeg&redirectUrl=https://alchemypay.org&targetFiat=SGD&timeout=1675394255000&timestamp=1675417608&type=MARKET&uniqueId=1113"
        String signture = sign(signStr, APP_SECRET); // 公共参数
                System.out.println("signture is: " + signture);

    }
}

Sign demo for API

public class APISignCheckUtil {

    private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
        '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

    public static String getMerSign(String appId, String appSecret, String timestamp) {
        return encode("sha1", appId  + appSecret + timestamp);
    }


    private static String encode(String algorithm, String value) {
        if (value == null) {
            return null;
        }
        try {
            MessageDigest messageDigest
                = MessageDigest.getInstance(algorithm);
            messageDigest.update(value.getBytes());
            return getFormattedText(messageDigest.digest());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    private static String getFormattedText(byte[] bytes) {
        int len = bytes.length;
        StringBuilder buf = new StringBuilder(len * 2);
        for (int j = 0; j < len; j++) {
            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
            buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
        }
        return buf.toString();
    }
}