Webhook Integration
Our system provides the ability to receive real-time updates by sending event notifications to your registered webhook endpoint. This guide will walk you through webhook configuration, response specifications, and crucial security verification.
⚙️ 1. Configuration
Before receiving event notifications, you need to provide a Webhook Endpoint.
- Configuration Method: You can configure your webhook receiving address in the merchant's API Management backend, just like how you manage your ApiKey.
- Limit: Currently, we only support creating one webhook endpoint per merchant/application.
- Protocol Requirement: To ensure data transmission security, the webhook endpoint only supports the
HTTPSprotocol, and the system will use thePOSTmethod to initiate requests.
📦 2. Event Formats
Once your webhook is set up successfully, DogPay will push JSON-formatted payload data to your endpoint whenever relevant business events occur. The general outer structure is as follows:
{
"event_id": "A globally unique event ID, which can be used for idempotency",
"event_identifier": "Event identifier, e.g., pay.transaction.update",
"data": {
// Specific business context object, varying based on the event_identifier
}
}⏱️ 3. Retry Mechanism
When your server receives a webhook push, it must respond promptly.
Response Time & Retry StrategyYou need to respond with our standard HTTP status codes
200or201within 30 seconds.
If you do not respond in a timely manner or if the status code is abnormal (e.g., 500), the system will consider the push failed and attempt to resend the webhook, with retry delays of 10s, 30s, 60s, 120s, 300s, and 600s.
🛡️ 4. Webhook Verification
Since your webhook endpoint is publicly exposed on the internet, to verify that the webhook events are indeed sent by DogPay and prevent malicious forged requests, you must verify the signature of each notification.
The payload of each webhook event is signed using the HTTP header wh-signature.
Verification Steps
- Algorithm: This signature is based on a
HMAC-SHA512(Hash-based Message Authentication Code). - Key: Use your
ApiKeyobtained from the API Management backend as the key. - Message: Use the received, unmodified JSON payload raw string (i.e., the Request Body) as the message.
- Convert your computed hash value into a lowercase hexadecimal string and compare it with the
wh-signaturein the request header. If they match, the verification is successful.
Online Debugging ToolDuring the development phase, you can use this HMAC Online Verification tool to cross-check whether the signature generated by your code is accurate.
💻 5. Code Example
Below is a complete reference code for implementing HMAC-SHA512 signature verification using Java:
package com.example.dogpay2;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
public class DogPayWebhookVerifier {
private static String bytesToHex(byte[] bytes) {
if (bytes == null) {
throw new IllegalArgumentException("Input byte array cannot be null");
}
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
public static boolean verifySignature(String apiKey, String payload, String whSignature) {
try {
// Initializing a Mac Instance with the HMAC-SHA512 Algorithm
Mac hmacSha512 = Mac.getInstance("HmacSHA512");
SecretKeySpec secretKeySpec = new SecretKeySpec(apiKey.getBytes(StandardCharsets.UTF_8), "HmacSHA512");
hmacSha512.init(secretKeySpec);
// Compute HMAC signatures
byte[] computedHash = hmacSha512.doFinal(payload.getBytes(StandardCharsets.UTF_8));
String computedSignature = bytesToHex(computedHash);
return computedSignature.equals(whSignature);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static void main(String[] args) {
String apiKey = "{{apiKey}}";
String payload = "{"
+ "\"event_id\":\"997daf9b-4162-4864-914c-960ff6cc16ad\","
+ "\"event_identifier\":\"card.transaction\","
+ "\"data\":{"
+ "\"id\":\"043fe653-e916-4989-a044-c8404cc4730c\","
+ "\"cardId\":\"9afe2c3c-306c-492f-aa99-6ce6574440bd\","
+ "\"cardChannel\":\"c_002_budget\","
+ "\"accountId\":\"1bd30ef3-0f13-468c-a9b7-61b141a02864\","
+ "\"orderNum\":\"202503101055594738096\","
+ "\"transactionId\":null,"
+ "\"currency\":\"USD\","
+ "\"fee\":\"0.65000000\","
+ "\"amount\":\"10.00000000\","
+ "\"type\":\"consumption\","
+ "\"status\":\"pending\","
+ "\"createAt\":\"2025-03-10T02:55:59.470Z\","
+ "\"transactionAt\":\"2025-03-10T02:55:59.474Z\","
+ "\"completeAt\":\"2025-03-10T02:55:59.474Z\","
+ "\"detail\":\"WECHAT*TENCENT ShenZhen CN\","
+ "\"sourceId\":\"a435-2ad446944ebe-bf04-5c86-6c3e-5d51\","
+ "\"tradeTag\":null,"
+ "\"account\":null,"
+ "\"card\":null,"
+ "\"reasonCode\":0,"
+ "\"mcc\":\"123456\""
+ "}"
+ "}";
String whSignature = "example_wh_signature";
boolean isValid = verifySignature(apiKey, payload, whSignature);
if (isValid) {
System.out.println("Success");
} else {
System.out.println("Failed");
}
}
}Updated about 11 hours ago