To ensure the authenticity and integrity of data during funds transfer, Zone requires all funds transfer requests to be signed and these requests will be verified by Zone using the signatures and a public key:

When calling the Funds Transfer API, you must sign the request (Zone's selected request properties) sent to Zone using your generated Private Key (PEM).

Sign a Fund Transfer Request

Prerequisite

To sign a request, generate a pair of asymmetric public and private keys using the RSA method. You can use here to get a pair of asymmetric keys for testing purposes.

Submit Public Key

After generating the public and private key pairs you must submit a base64 string of your public key to Zone through the "Configure Transactional Key" on the dashboard.

📘

Public Key Format

The public key to be submitted must be a base64 encoded string version of the public key (PEM string), headers inclusive (-----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY-----) .

Example of Base64 encoding public key

var publicKey = @"-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpdSdQfaQZV+WXj+47SXj7q/+9
HlY79IV+2XMMCYRroFUdkQTAqCFB22sSUR13FW+TnXkTBiql6W8AVr3w+JMdUNUB
6zoZitdpL0+3jkpJ7FhgUDkTCM1aTe400onAbBY/xs+us7vgfm5nr62hyaQT8cIb
YZh+CmH7avmXMvBOeQIDAQAB
-----END PUBLIC KEY-----";

var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(publicKey);
var encodedKeyString = System.Convert.ToBase64String(plainTextBytes);
const publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpdSdQfaQZV+WXj+47SXj7q/+9
HlY79IV+2XMMCYRroFUdkQTAqCFB22sSUR13FW+TnXkTBiql6W8AVr3w+JMdUNUB
6zoZitdpL0+3jkpJ7FhgUDkTCM1aTe400onAbBY/xs+us7vgfm5nr62hyaQT8cIb
YZh+CmH7avmXMvBOeQIDAQAB
-----END PUBLIC KEY-----`;

const plainTextBytes = new TextEncoder().encode(publicKey);
const encodedKeyString = btoa(String.fromCharCode(...plainTextBytes));
import java.util.Base64;

String publicKey = "-----BEGIN PUBLIC KEY-----\n" +
                   "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpdSdQfaQZV+WXj+47SXj7q/+9\n" +
                   "HlY79IV+2XMMCYRroFUdkQTAqCFB22sSUR13FW+TnXkTBiql6W8AVr3w+JMdUNUB\n" +
                   "6zoZitdpL0+3jkpJ7FhgUDkTCM1aTe400onAbBY/xs+us7vgfm5nr62hyaQT8cIb\n" +
                   "YZh+CmH7avmXMvBOeQIDAQAB\n" +
                   "-----END PUBLIC KEY-----\n";

byte[] plainTextBytes = publicKey.getBytes("UTF-8");
String encodedKeyString = Base64.getEncoder().encodeToString(plainTextBytes);

Example of the returned string after encoding the public key with Base64

LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDcGRTZFFmYVFaVitXWGorNDdTWGo3cS8rOQpIbFk3OUlWKzJYTU1DWVJyb0ZVZGtRVEFxQ0ZCMjJzU1VSMTNGVytUblhrVEJpcWw2VzhBVnIzdytKTWRVTlVCCjZ6b1ppdGRwTDArM2prcEo3RmhnVURrVENNMWFUZTQwMG9uQWJCWS94cyt1czd2Z2ZtNW5yNjJoeWFRVDhjSWIKWVpoK0NtSDdhdm1YTXZCT2VRSURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ==

Sign a Request

  • Construct the data to be signed in the order below

🚧

string( Amount + Currency + NameInquiryRef + TransactionReference )

var data =  $"{amount}{currency}{nameInquiryRef}{transactionReference}";
const data = `${amount}${currency}${nameInquiryRef}${transactionReference}`;
String data = amount + currency + nameInquiryRef + transactionReference;
  • Generate the signature (Sign the data with "sha256withrsa")
var payload = SignData(data, privateKey);

//Example Private Key
var privateKey = @"-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCmlpdKEAyqmyCJdmSh2FF254MYmbosUjAqxTd5t81PJe0jJPgd
tS7GQMPRvH0F0LI3DUcJtYJID5eZ6YTq17lCaW3j+x1LsqJbNfIzWJXhZg80jt9x
vkQ/3Y5iQJNmCKb7lgrkYcizbUwslX60ejTv8Ldh7Crxo9kVVjSUf61CuwIDAQAB
AoGAQj1A3O8yyieysVYFP6FvCxOVOhPuRi9L/cW7gEeIeH9BIqdRjSZ8+dHIyz3i
jIxmQKOj6oVkz1h71HRZKLQsckfUBZMOpfDK75TZmMDM3GU1iBhMTlEzRVkJsc46
Yagewvs0dQPMLbF7fvy2tK+FnldXgqHJobMpDk5jRjiBREECQQD383IVi+T13fXN
8OBUH/8FBHv/Ed7dxTH3FUqtcTvcTeeB46aN4CfowH0N2ZvfWKzNKpl3We/Evb63
AfcabtPhAkEAq/7+i1BgkEu3VF2TAZN4yqEkE2PDw+w4sycaitSYvuVuUi/JPtla
PBpGPtfhrW8wdEswem7fOYwzO2GvTnoqGwJBAKVyagN6j1KHwsaiHe3EU9QzQ9HV
SNLODCMEsAm/buP3j6yaDL7KfZbPKiKdu2ZyswtLi4+aEWVD/wf6ZbnbjcECQDsF
5KA2UwzxjtY6zmnqC7etmM22nMWtWL/SGX+u+UP5Q+ScVXll6VtawORr/RwhXgVq
kBZT2fLLtAEawqgxsCUCQQCrHlvFkhd8FRUUCISfFDLL0VLFhm/bkJVgR+kr4Gmo
VVlhU9CcnHTlT5f3/0XGNAomjtJ03xjXfN80qIcobDnL
-----END RSA PRIVATE KEY-----";

//Example SignData

public string SignData(string data, string privateKey)
{
  using (var rsa = RSA.Create())
  {
    var pem = new PemReader(new StringReader(privateKey.ToString()));
    var keyPair = (AsymmetricCipherKeyPair)pem.ReadObject();
    var privateKeyParameters = (RsaPrivateCrtKeyParameters)keyPair.Private;
    var rsaParameters = DotNetUtilities.ToRSAParameters(privateKeyParameters);

    rsa.ImportParameters(rsaParameters);

    var dataToSign = Encoding.UTF8.GetBytes(data);
    var signature = rsa.SignData(dataToSign, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
    return Convert.ToBase64String(signature);
  }
}
const privateKeyPEM = `-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCmlpdKEAyqmyCJdmSh2FF254MYmbosUjAqxTd5t81PJe0jJPgd
tS7GQMPRvH0F0LI3DUcJtYJID5eZ6YTq17lCaW3j+x1LsqJbNfIzWJXhZg80jt9x
vkQ/3Y5iQJNmCKb7lgrkYcizbUwslX60ejTv8Ldh7Crxo9kVVjSUf61CuwIDAQAB
AoGAQj1A3O8yyieysVYFP6FvCxOVOhPuRi9L/cW7gEeIeH9BIqdRjSZ8+dHIyz3i
jIxmQKOj6oVkz1h71HRZKLQsckfUBZMOpfDK75TZmMDM3GU1iBhMTlEzRVkJsc46
Yagewvs0dQPMLbF7fvy2tK+FnldXgqHJobMpDk5jRjiBREECQQD383IVi+T13fXN
8OBUH/8FBHv/Ed7dxTH3FUqtcTvcTeeB46aN4CfowH0N2ZvfWKzNKpl3We/Evb63
AfcabtPhAkEAq/7+i1BgkEu3VF2TAZN4yqEkE2PDw+w4sycaitSYvuVuUi/JPtla
PBpGPtfhrW8wdEswem7fOYwzO2GvTnoqGwJBAKVyagN6j1KHwsaiHe3EU9QzQ9HV
SNLODCMEsAm/buP3j6yaDL7KfZbPKiKdu2ZyswtLi4+aEWVD/wf6ZbnbjcECQDsF
5KA2UwzxjtY6zmnqC7etmM22nMWtWL/SGX+u+UP5Q+ScVXll6VtawORr/RwhXgVq
kBZT2fLLtAEawqgxsCUCQQCrHlvFkhd8FRUUCISfFDLL0VLFhm/bkJVgR+kr4Gmo
VVlhU9CcnHTlT5f3/0XGNAomjtJ03xjXfN80qIcobDnL
-----END RSA PRIVATE KEY-----`;

signStringWithRSA : (stringToSign, privateKey) => {
  const sig = new jsrsasign.KJUR.crypto.Signature({ 'alg': 'SHA256withRSA' });
  sig.init(privateKey);
  var hash = sig.signString(stringToSign);
  const encodedSignature = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(hash));
  return encodedSignature;
}

const payload = signStringWithRSA(data, privateKeyPem)
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;

public static String signStringWithRSA(String stringToSign, String privateKeyPEM) throws Exception {
  byte[] stringBytes = stringToSign.getBytes(StandardCharsets.UTF_8);

  PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyPEM.getBytes());
  KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

  Signature signer = Signature.getInstance("SHA256withRSA");
  signer.initSign(privateKey);
  signer.update(stringBytes);

  byte[] signatureBytes = signer.sign();
  return java.util.Base64.getEncoder().encodeToString(signatureBytes);
}
  • Add the generated signature to the request header of the Funds Transfer endpoint under the key "x-payload-signature"

Example of the returned signature after signing

PfYbXBo4wtgWoKZI0TvYlqWbKdcPV2d50hk4r/E2biPIcJ+JHQ7zqXqPH6jorvvpE4l7Z5j+6OyqaJ2n43CrxuWDkjiLpwQTXMad53UNgtgBfexNL9guKQ/pMaBv0aJ7yqB/EoI+ouFAbX+2fe3KAxcmZ8BhJlQ+Y1NMQ6RyFYA=