iPeakoin API Notifications

This document list and describes the events and data models used in iPeakoin Notifications.

WebHook

iPeakoin uses Webhooks to notify a single callback URL provided by the client in a specified format. iPeakoin will send different payloads according to the scenarios described further below, and the trigger event can be understood in terms of the Template field in the payload body.

The client should return the specified return code. If no corresponding return code is received after sending the callback URL, the iPeakoin system will consider the push unsuccessful. The return fields are as follows:

FieldTypeDescription
idstringid of the notification pushed to the customer
receivedbooleanReceiving identifier

The iPeakoin system delays the push for 30s, 60s, 120s, and 240s in sequence, with a maximum of five pushes.

Common Considerations

All current and future implementations of notification messages have the following attributes:

NameTypeDescriptionSample
idUUIDnotification identifier32b0216b-66d9-498b-a4bc-17612d9cb6cd
businessTypestringThe businessType of notificationAssetsDeposit
signstringsignature055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd

Account Notification

AccountRegistered

When you create a subaccount, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "AccountRegistered",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a Account Object.

KYC

When you create a subaccount through KYC, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "KYC",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a Account Object.

Quantum Card Notification

CreateCard

Create a quantum card, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "CreateCard",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a Card Object.

FrozenCard

Frozen quantum card, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "FrozenCard",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a Card Object.

UnfrozenCard

Unfrozen quantum card, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "UnfrozenCard",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a Card Object.

DeleteCard

Delete quantum card, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "DeleteCard",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a Card Object.

CardTransaction

When the quantum card generates a transaction, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "CardTransaction",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a CardTransaction Object.

FrozenAmount

Frozen the quantum card amount, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "FrozenAmount",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a CardTransaction Object.

UnfrozenAmount

Unfrozen the quantum card amount, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "UnfrozenAmount",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a CardTransaction Object.

BudgetTransaction

When a budget generates a transaction, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "UnfrozenAmount",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a BudgetTransaction Object.

Global Account Notification

CreateGlobalAccount

Open global accounts in compliance, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "CreateGlobalAccount",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a BankAccount Object.

GlobalAccountTransaction

When a global account generates a transaction, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "CreateGlobalAccount",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a GlobalAccountTransaction Object.

Crypto Asset Notification

AssetsDeposit

Once you process a successful deposit, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "AssetsDeposit",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a Deposit Object.

AssetsWithdrawal

Once you process a successful withdrawal, you should see a notification message on your local server shell that looks like the following.

{
    "id": "6a94b9c7-40d6-4007-a5d0-a96d714a1108",
    "businessType": "AssetsWithdrawal",
    "data": { ... },
    "sign": "055144f3c59f2412d5575daee1ecc473b028378d3c3e359970fc96b33314e5bd"
}

The data payload will be a Withdrawal Object.

Signature

Each request initiated by iPeakoin contains a sign parameter that can be used to verify the authenticity of the request from iPeakoin. For each request, the data of the data parameter is fetched and processed through the HMAC-SHA256 hash function.

  1. Set of parameters to be signed
const params = {
    "id": "ee74c872-8173-4b67-81b1-5746e7d5ab88",
    "accountId": null,
    "holderId": "d2bd6ab3-3c28-4ac7-a7c4-b7eed5eee367",
    "currency": "USD",
    "settlementCurrency": null,
    "counterparty": "SAILINGWOOD;;US;1800948598;;091000019",
    "transactionAmount": 11,
    "fee": 0,
    "businessType": "Inbound",
    "status": "Closed",
    "transactionTime": "2021-11-22T07:34:10.997Z",
    "transactionId": "124d3804-defa-4033-9f30-1d8b0468e506",
    "clientTransactionId": null,
    "createTime": "2021-11-22T07:34:10.997Z",
    "appendFee": 0,
};
  1. The parameter set key to be signed is sorted in ascending order according to "ASCII code of the first character of the string" (if the ASCII code value is the same in the sorting process, the next digit is incremented in sequence for comparison).
const keys = Object.keys(params);
keys.sort();
  1. Concatenates a string, and empty values are filled with empty strings
accountId=&appendFee=0&businessType=Inbound&clientTransactionId=&counterparty=SAILINGWOOD;;US;1800948598;;091000019&createTime=2021-11-22T07:34:10.997Z&currency=USD&fee=0&holderId=d2bd6ab3-3c28-4ac7-a7c4-b7eed5eee367&id=ee74c872-8173-4b67-81b1-5746e7d5ab88&settlementCurrency=&status=Closed&transactionAmount=11&transactionId=124d3804-defa-4033-9f30-1d8b0468e506&transactionTime=2021-11-22T07:34:10.997Z
  1. CLIENT_SECRET is used to perform hmac-sha256 signature on the concatenated string, and the hexadecimal encoding is used to obtain signature.
const hmac = crypto.createHmac('sha256', '25d55ad283aa400af464c76d713c07ad');
const sign = hmac.update('Concatenates a string').digest('hex');

Example Code

const crypto = require('crypto');

const params = {
    "id": "ee74c872-8173-4b67-81b1-5746e7d5ab88",
    "accountId": null,
    "holderId": "d2bd6ab3-3c28-4ac7-a7c4-b7eed5eee367",
    "currency": "USD",
    "settlementCurrency": null,
    "counterparty": "SAILINGWOOD;;US;1800948598;;091000019",
    "transactionAmount": 11,
    "fee": 0,
    "businessType": "Inbound",
    "status": "Closed",
    "transactionTime": "2021-11-22T07:34:10.997Z",
    "transactionId": "124d3804-defa-4033-9f30-1d8b0468e506",
    "clientTransactionId": null,
    "createTime": "2021-11-22T07:34:10.997Z",
    "appendFee": 0,
};

const keys = Object.keys(params);
keys.sort();

const result = [];

for (const key of keys) {
    let val = params[key];
    if (val == null) {
        val = '';
    }
    result.push(`${key}=${val}`);
}

const str = result.join('&');

const hmac = crypto.createHmac('sha256', '25d55ad283aa400af464c76d713c07ad');
const sign = hmac.update(str).digest('hex');

console.log(sign);
// => 8287d5539c03918c9de51176162c2bf7065d5a8756b014e3293be1920c20d102
package com.qbitnetwork.demo;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;

public class Signature {
    public static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        Formatter formatter = new Formatter(sb);
        for (byte b : bytes) {
            formatter.format("%02x", b);
        }
        return sb.toString();//完成16进制编码
    }

    public static byte[] sign(String str, String secret) throws NoSuchAlgorithmException, InvalidKeyException {
        Key sk = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
        Mac mac = Mac.getInstance(sk.getAlgorithm());
        mac.init(sk);
        return mac.doFinal(str.getBytes());//完成hmac-sha256签名
    }

    public static String joinStr(Map<String, Object> data) {
        String[] keys = data.keySet().toArray(new String[0]);
        Arrays.sort(keys);
        StringBuilder sb = new StringBuilder();
        for (String key : keys) {
            Object val = data.get(key);
            if (val == null) {
                val = "";
            }
            sb.append(key).append("=").append(val).append("&");
        }
        String str = sb.toString();
        return str.substring(0, str.length() - 1);
    }

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
        Map<String, Object> data = new HashMap<>();
        data.put("id", "ee74c872-8173-4b67-81b1-5746e7d5ab88");
        data.put("accountId", null);
        data.put("holderId", "d2bd6ab3-3c28-4ac7-a7c4-b7eed5eee367");
        data.put("currency", "USD");
        data.put("settlementCurrency", null);
        data.put("counterparty", "SAILINGWOOD;;US;1800948598;;091000019");
        data.put("transactionAmount", 11);
        data.put("fee", 0);
        data.put("businessType", "Inbound");
        data.put("status", "Closed");
        data.put("transactionTime", "2021-11-22T07:34:10.997Z");
        data.put("transactionId", "124d3804-defa-4033-9f30-1d8b0468e506");
        data.put("clientTransactionId", null);
        data.put("createTime", "2021-11-22T07:34:10.997Z");
        data.put("appendFee", 0);

        String sgn = bytesToHex(sign(joinStr(data), "25d55ad283aa400af464c76d713c07ad"));

        System.out.println(sgn);
        // => 8287d5539c03918c9de51176162c2bf7065d5a8756b014e3293be1920c20d102
    }
}
package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "sort"
    "strings"
)

func getKeys(m map[string]interface{}) []string {
    j := 0
    keys := make([]string, len(m))
    for k := range m {
        keys[j] = k
        j++
    }
    return keys
}

func joinStr(params map[string]interface{}) string {
    keys := getKeys(params)
    sort.Strings(keys)
    var result []string
    for _, key := range keys {
        val := params[key]
        if val == nil {
            val = ""
        }
        result = append(result, fmt.Sprintf("%s=%s", key, fmt.Sprintf("%v", val)))
    }
    return strings.Join(result, "&")
}

func sign(message string, secret string) string {
    key := []byte(secret)
    h := hmac.New(sha256.New, key)
    h.Write([]byte(message))
    return hex.EncodeToString(h.Sum(nil))
}

func main() {
    params := map[string]interface{} {
        "id": "ee74c872-8173-4b67-81b1-5746e7d5ab88",
        "accountId": nil,
        "holderId": "d2bd6ab3-3c28-4ac7-a7c4-b7eed5eee367",
        "currency": "USD",
        "settlementCurrency": nil,
        "counterparty": "SAILINGWOOD;;US;1800948598;;091000019",
        "transactionAmount": 11,
        "fee": 0,
        "businessType": "Inbound",
        "status": "Closed",
        "transactionTime": "2021-11-22T07:34:10.997Z",
        "transactionId": "124d3804-defa-4033-9f30-1d8b0468e506",
        "clientTransactionId": nil,
        "createTime": "2021-11-22T07:34:10.997Z",
        "appendFee": 0,
    }
    fmt.Println(sign(joinStr(params), "25d55ad283aa400af464c76d713c07ad"))
    // => 8287d5539c03918c9de51176162c2bf7065d5a8756b014e3293be1920c20d102
}
import hashlib
import hmac


def sign(message, secret):
    encryption = hmac.new(bytes(secret, encoding='UTF-8'), bytes(message, encoding='UTF-8'), hashlib.sha256)
    return encryption.hexdigest()


def join_str(origin):
    keys = list(origin.keys())
    keys.sort()
    content = []
    for key in keys:
        val = origin[key]
        if val is None:
            val = ''
        content.append(key + '=' + str(val))
    return '&'.join(content)


if __name__ == '__main__':
    data = {
        "id": "ee74c872-8173-4b67-81b1-5746e7d5ab88",
        "accountId": None,
        "holderId": "d2bd6ab3-3c28-4ac7-a7c4-b7eed5eee367",
        "currency": "USD",
        "settlementCurrency": None,
        "counterparty": "SAILINGWOOD;;US;1800948598;;091000019",
        "transactionAmount": 11,
        "fee": 0,
        "businessType": "Inbound",
        "status": "Closed",
        "transactionTime": "2021-11-22T07:34:10.997Z",
        "transactionId": "124d3804-defa-4033-9f30-1d8b0468e506",
        "clientTransactionId": None,
        "createTime": "2021-11-22T07:34:10.997Z",
        "appendFee": 0,
    }
    sig = sign(join_str(data), '25d55ad283aa400af464c76d713c07ad')
    print(sig)
    # => 8287d5539c03918c9de51176162c2bf7065d5a8756b014e3293be1920c20d102