Interlace API Notifications
This document list and describes the events and data models used in Interlace Notifications.
WebHook
Interlace uses Webhooks to notify a single callback URL provided by the client in a specified format. Interlace will send different payloads according to the scenarios described further below, and the trigger event can be understood in terms of the eventType field in the payload body.
After receiving a notification, needs to return a reply packet within 5 seconds. Otherwise, Interlace considers the notification failed and sends the notification repeatedly.
The same notification may be sent multiple times, and duplicate notifications must be handled correctly. If it has been processed, return success directly to Interlace.
You will receive an HTTP request like this.
POST /webhook HTTP/1.1
Host: xxx
Content-Type: application/json
Signature-Method: HMAC-SHA256
Signature: D29qUeeyV14HFG6DiuyFRsGLILlxzL8s7okeRMHjzFU=
Timestamp: 1756879969964
{
"eventType": "CARD_TRANSACTION.CREATED",
"apiVersion": "v3",
"code": "000000",
"message": "",
"resource": "{\"id\":\"1234567890\",\"cardId\":\"4111111111111111\",\"createTime\":\"1756879969964\",\"processingCode\":\"00\",\"accountId\":\"ACC987654321\",\"transactionAmount\":\"150.00\",\"transactionCurrency\":\"USD\",\"billingAmount\":\"150.00\",\"billingCurrency\":\"USD\",\"merchantName\":\"Example Store\",\"merchantCity\":\"New York\",\"merchantCountry\":\"USA\",\"transactionType\":\"authorization\",\"mcc\":\"5812\"}",
"createTime": "1756879969964",
"id": "60633733-2b0d-41a2-a6b4-12b3ba085428"
}
The client should return the specified return code. If no corresponding return code is received after sending the callback URL, the Interlace system will consider the push unsuccessful. The return fields are as follows:
| Field | Type | Description |
|---|---|---|
| received | boolean | Receiving identifier |
Example:
{
"received": true
}Retry interval
| Retry number | Interval | Retry number | Interval |
|---|---|---|---|
| 1 | 10 seconds | 9 | 7 minutes |
| 2 | 30 seconds | 10 | 8 minutes |
| 3 | 1 minute | 11 | 9 minutes |
| 4 | 2 minutes | 12 | 10 minutes |
| 5 | 3 minutes | 13 | 20 minutes |
| 6 | 4 minutes | 14 | 30 minutes |
| 7 | 5 minutes | 15 | 1 hour |
| 8 | 6 minutes | 16 | 2 hours |
Common Considerations
All current implementations of notification messages have the following attributes:
💡 💡 Use resource field to check sign
| Name | Type | Description | Sample |
|---|---|---|---|
| id | string | notification identifier | 32b0216b-66d9-498b-a4bc-17612d9cb6cd |
| eventType | string | The eventType of notification | CARD.CREATED |
| createTime | string | create time | 1757657700094 |
| resource | string | JSON format of resource | JSON format, Use this field to check sign |
| apiVersion | string | webhook version | v3 |
| code | string | code info | 000000 |
| message | string | message | success |
Signature
Each request initiated by Interlace contains a sign parameter that can be used to verify the authenticity of the request from Interlace. For each request, the data of the data parameter is fetched and processed through the HMAC-SHA256 hash function.
Signature Verification Steps
- Log in to the Interlace merchant portal.
- Go to Development > Integration Settings page, and obtain the Client Secret. Use this value as
secret. - Get the
Signaturevalue from the request header. - Get the
resourceobject from the request body. Use this value asdata. - Use
dataandsecretto generate a signature with the sign method in the code example based on the HMAC-SHA256 algorithm. Use the generated value ascomputedSignature. - Compare
computedSignaturewith theSignaturevalue obtained from the request header. The request is considered authentic only when the two values match.
The following example shows how to verify the signature.
secret: The Client Secret obtained from the merchant portal.data: Theresourceobject in the request body.signature: TheSignaturevalue in the request header.
Example
@Slf4j
public class Example {
private static final String HMAC_SHA256 = "HmacSHA256";
// generate sign
public static String sign(String data, String secret) {
try {
Mac mac = Mac.getInstance(HMAC_SHA256);
SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), HMAC_SHA256);
mac.init(secretKey);
byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hash);
} catch (Exception e) {
log.error("sign error", e);
return null;
}
}
// verify sign
public static boolean verify(String data, String signature, String secret) {
try {
String computedSignature = sign(data, secret);
return computedSignature != null && computedSignature.equals(signature);
} catch (Exception e) {
return false;
}
}
public static void main(String[] args) {
String data = "{\"a\":\"b\"}";
String secret = "6d8557a0cded4483b8d9c3cea0272cd7";
String signature = sign(data, secret);
System.out.println(signature);
}
//sign = Sj972aD0pmG+zClb7mKoUBZbQd5KlAyxaCKHUSMpBME=
}
const crypto = require('crypto');
/**
* Generates HMAC-SHA256 signature
* @param {string} data - The data to be signed
* @param {string} secret - The secret key for signing
* @returns {string|null} Base64 encoded signature, null if error occurs
*/
function sign(data, secret) {
try {
// Create HMAC-SHA256 hash object
const hmac = crypto.createHmac('sha256', secret);
// Update with data using UTF-8 encoding
hmac.update(data, 'utf8');
// Calculate signature and return as Base64
return hmac.digest('base64');
} catch (error) {
console.error('Signing error:', error);
return null;
}
}
/**
* Verifies HMAC-SHA256 signature
* @param {string} data - The original data
* @param {string} signature - The signature to verify
* @param {string} secret - The secret key for verification
* @returns {boolean} True if verification succeeds, false otherwise
*/
function verify(data, signature, secret) {
try {
const computedSignature = sign(data, secret);
return computedSignature !== null && computedSignature === signature;
} catch (error) {
console.error('Verification error:', error);
return false;
}
}
// Example usage
function main() {
const data = '{"a":"b"}';
const secret = '6d8557a0cded4483b8d9c3cea0272cd7';
const signature = sign(data, secret);
console.log('Generated signature:', signature);
// Verify the generated signature
const isValid = verify(data, signature, secret);
console.log('Signature valid:', isValid);
}
// Run example
main();
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"log"
)
// sign generates an HMAC-SHA256 signature for the given data using the secret key
// Returns the base64-encoded signature or an error if something fails
func sign(data, secret string) (string, error) {
// Create a new HMAC-SHA256 hasher using the secret key
h := hmac.New(sha256.New, []byte(secret))
// Write the data to be signed
_, err := h.Write([]byte(data))
if err != nil {
return "", fmt.Errorf("failed to write data: %w", err)
}
// Calculate the HMAC hash and encode it as base64
signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
return signature, nil
}
// verify checks if the provided signature matches the computed signature for the data
// Returns true if verification succeeds, false otherwise
func verify(data, signature, secret string) bool {
// Compute the expected signature
computedSignature, err := sign(data, secret)
if err != nil {
log.Printf("Verification error: %v", err)
return false
}
// Compare the computed signature with the provided one
return computedSignature == signature
}
func main() {
data := `{"a":"b"}`
secret := "6d8557a0cded4483b8d9c3cea0272cd7"
// Generate signature
signature, err := sign(data, secret)
if err != nil {
log.Fatalf("Failed to generate signature: %v", err)
}
fmt.Println("Generated signature:", signature)
// Verify signature
isValid := verify(data, signature, secret)
fmt.Println("Signature valid:", isValid)
}