Receive Notifications
This guide provides an introduction to receiving Spell callback notifications, including how to correctly process notifications.
All callback notifications sent by Spell are delivered to your specified callback address via a POST
request. The request content includes:
- Request Headers
Content-Type
:application/json
.SPELL-Callback-Signature
: The request signature for you to verify the authenticity of the request.
- Request Body
callback
: Callback notification ID.event
: Event ID.order
: Order ID.timestamp
: Request timestamp.user
: User ID.
Verify Signature Validity
To ensure the authenticity of the request and prevent tampering or forgery, Spell signs the information so you can verify it. You need to sign the request body using the corresponding callback secret key for the registered event (recorded during registration, not account API secret) and compare it with the SPELL-Callback-Signature
in the request headers. Below are the complete verification steps:
1. Serialize the Data
First, you need to serialize all the fields in the request body into a specific string. This process includes:
- Sort by Key: Sort all the fields in the request body alphabetically by their keys.
- Format: Convert each field into a string in the format
key=value
. - Concatenate: Join all the formatted strings using
&
.
You can use the serializeData()
function below to complete this step:
/**
* Serializes a data object to generate a signature string.
* @param data - The data object to be serialized.
* @returns The serialized string in the format key1=value1&key2=value2...
*/
function serializeData(data: Record<string, any>): string {
return Object.keys(data)
.sort()
.map(key => {
const value = data[key];
const strValue = typeof value === 'object'
? JSON.stringify(value)
: String(value);
return `${key}=${strValue}`;
})
.join('&');
}
2. Calculate the Signature
Use the crypto
module to create an HMAC
object and calculate the signature of the serialized data using the SHA-256
algorithm and your secret key.
Below is example code for Node.js
:
import * as crypto from 'crypto';
/**
* Calculates the signature.
* @param serializedData - The serialized string.
* @param secretKey - Your callback notification secret key.
* @returns The signature string in hexadecimal.
*/
function calculateSignature(serializedData: string, secretKey: string): string {
const hmac = crypto.createHmac('sha256', secretKey);
hmac.update(serializedData);
return hmac.digest('hex');
}
3. Compare the Signatures
Finally, compare the signature you calculated with the value of the SPELL-Callback-Signature
field in the callback request headers. If they are identical, the request is authentic and valid.
Below is the complete example code:
// Get the signature from the request headers
const cbSignature = request.headers['SPELL-Callback-Signature'];
// Assume this is the received request body
const requestBody = {
callback: 'callback_id',
event: 'event_id',
order: 'order_id',
timestamp: 1700000000000,
user: 'user_id',
};
// Serialize the request body
const serializedData = serializeData(requestBody);
// Calculate the signature
// CALLBACK_SECRET_KEY is generated during callback registration
const mySignature = calculateSignature(serializedData, CALLBACK_SECRET_KEY);
// Compare the signatures
if (mySignature === cbSignature) {
console.log("Signature verification successful! ");
// Process your business logic
} else {
console.log("Signature verification failed! You should recreate a callback receiving address.");
// Ignore the request
}
Handle the Response
To ensure the callback notification is successfully received, Spell will retry at intervals for callbacks that do not receive a success response within a certain time frame. To avoid receiving duplicate notifications from Spell, your server must return an HTTP
success response after receiving the notification and confirming the signature is valid.
- Status Code:
200
- Response Header:
Content-Type: text/plain
- Response Body:
success
The response body must be the lowercase text
success
and must not contain any other characters.