MayaRamp Webhook v2
The MayaRamp Webhook v2 service allows your application to receive real-time updates on the status of transactions initiated through the MayaRamp platform. This document provides an overview of the webhook v2 workflow and instructions for integrating it into your application.
Overview
When a user initiates a transaction on the MayaRamp platform, your application will receive a webhook notification via an HTTP POST request. These notifications will keep you informed about the progress of the transaction.
Registration
All products support webhook v2. Currently available webhook types include:
- Deposit transaction
- Disbursement transaction
- Offramp transaction
- Onramp transaction
You can register for each webhook type individually. To start receiving webhook notifications or switch to v2, you can configure your webhook settings using the MayaRamp dashboard at https://dashboard.mayaramp.com. Follow these steps:
- Navigate to the Webhook Configuration page in your dashboard
- For each webhook type, enter your webhook URL where your application will receive the webhook notifications
- Use the version switch button to toggle between v1 and v2 webhook format. Select v2 to use the simplified signature format and receive the
additionalInfofield in webhook payloads - Save your configuration. The dashboard will provide you with a verification key, which will be used to verify the authenticity of incoming webhook requests
Schema
Each webhook request will include the following headers:
Content-Type: application/json: Indicates that the request body is in JSON format.X-TIMESTAMP: <ISO_8601_timestamp>: The timestamp when the webhook was generated, in ISO 8601 format (e.g.,2024-08-23T10:00:00Z).X-SIGNATURE: <base64_signature>: A digital signature used to verify the authenticity of the request. This signature is generated using the verification key provided during registration.
Request Body
The webhook request body will contain information about the transaction status. transactionStatus will be based on transaction current status. Status reference for offramp, onramp, deposit, and disbursement.
All products in webhook v2 include an additionalInfo field that contains product-specific information. The structure of additionalInfo varies by product type and is detailed in the Additional Info section below.
{
"orderId": "orderId",
"responseCode": "200",
"responseMessage": "success",
"transactionStatus": "processed",
"additionalInfo": {}
}
Differences between v1 and v2
The main difference between webhook v1 and v2 is how the stringToSign is constructed for signature verification. This affects how you verify incoming webhook requests in your code. Both versions include timestamp in the signature to prevent replay attacks.
String to Sign Construction
v1 Format: The string to sign in v1 includes the HTTP method, URL, hashed request body, and timestamp:
function createStringToSign(timestamp, url, body) {
// Minify the request body to a JSON string
const minifyBody = JSON.stringify(body)
// Create a SHA256 hash of the minified body
const hashBody = crypto.createHash('sha256').update(minifyBody)
// Get the hexadecimal representation of the hash
const hexBody = hashBody.digest('hex')
// Convert the hexadecimal string to lowercase
const lowerCaseBody = hexBody.toLowerCase()
// Construct the string to sign: POST:url:hashedBody:timestamp
return `POST:${url}:${lowerCaseBody}:${timestamp}`
}
v2 Format: The string to sign in v2 is simplified and includes the orderId, transactionStatus, and timestamp from the request headers:
function createStringToSign(orderId, transactionStatus, timestamp) {
// Construct the string to sign: orderId:transactionStatus:timestamp
return `${orderId}:${transactionStatus}:${timestamp}`
}
Request Body
v1 Request Body:
{
"orderId": "orderId",
"responseCode": "200",
"responseMessage": "success",
"transactionStatus": "processed"
}
v2 Request Body:
{
"orderId": "orderId",
"responseCode": "200",
"responseMessage": "success",
"transactionStatus": "processed",
"additionalInfo": {}
}
The v2 request body includes an additional additionalInfo field that contains product-specific information.
Verification Function
The verifySignature function remains the same for both v1 and v2. Only the createStringToSign function differs between versions.
Additional Info
The additionalInfo field contains product-specific information that varies by webhook type. Below are the structures for each product type:
Deposit
The additionalInfo for deposit transactions contains the following structure. All fields are optional and can be null if the data does not exist:
{
"additionalInfo": {
"reference": "string | null",
"transactionCode": "string | null",
"name": "string | null",
"bankName": "string | null",
"accountNumber": "string | null",
"mid": "string | null"
}
}
Properties:
reference(string | null): Client reference ID for the deposit transactiontransactionCode(string | null): RRN for QRIS transactionsname(string | null): Payer name for the deposit transactionbankName(string | null): Bank name used for the depositaccountNumber(string | null): Account number used for the depositmid(string | null): Merchant identifier for the deposit transaction
Disbursement
The additionalInfo for disbursement transactions contains the following structure. The field is optional and can be null if the data does not exist:
{
"additionalInfo": {
"reference": "string | null"
}
}
Properties:
reference(string | null): Reference identifier for the disbursement transaction
Verify incoming webhook
To ensure the authenticity of incoming webhook requests, you should verify the digital signature included in the X-SIGNATURE header. Here's an example of how to do this in Node.js:
/**
* This function verifies the digital signature of an incoming webhook request.
* It takes the string to sign, the signature, and the public key to verify the authenticity of the request.
*
* @param {string} stringToSign - The string that was signed for verification.
* @param {string} signature - The base64 encoded signature to verify.
* @returns {boolean} - Returns true if the signature is valid, indicating the request is authentic, and false otherwise.
*/
function verifySignature(stringToSign, signature) {
// Replace newline escape sequences with actual newline characters in the public key
const pubKey = jwtPubKey.replace(/\\n/g, '\n')
// Create a Verify object with the SHA256 algorithm
const verify = crypto.createVerify('SHA256')
// Update the Verify object with the string to sign
verify.update(stringToSign)
// End the Verify object
verify.end()
// Verify the signature against the public key
return verify.verify(pubKey, Buffer.from(signature, 'base64'))
}
/**
* This function generates the string that needs to be signed for webhook v2 verification.
* It takes the orderId and transactionStatus from the webhook request body, and timestamp from the request headers.
*
* @param {string} orderId - The order ID from the webhook request body.
* @param {string} transactionStatus - The transaction status from the webhook request body.
* @param {string} timestamp - The timestamp from the X-TIMESTAMP header in ISO 8601 format.
* @returns {string} - The string to sign for verification.
*/
function createStringToSign(orderId, transactionStatus, timestamp) {
// Construct the string to sign in the format specified by the webhook v2 service
return `${orderId}:${transactionStatus}:${timestamp}`
}
/**
* This is the main function to demonstrate the webhook v2 verification process.
* It simulates a webhook request with headers, body, and signature, then verifies the signature.
*/
function main() {
// Simulate a webhook request
const timestamp = '2024-08-23T10:00:00Z' // timestamp from X-TIMESTAMP header
const body = {
orderId: 'orderId',
responseCode: '200',
responseMessage: 'success',
transactionStatus: 'processed',
additionalInfo: {}
}
const signature = 'signature' // signature from X-SIGNATURE header
// Generate the string to sign based on the webhook request body and timestamp
const stringToSign = createStringToSign(body.orderId, body.transactionStatus, timestamp)
// Verify the signature
console.log(verifySignature(stringToSign, signature))
}
Next Steps
After verifying the incoming webhook, your application can process the transaction status and take appropriate actions based on the provided information.