Webhook Introduction
Webhook Introduction
Why need Webhook?
At present, our client retrieves the deposit and withdrawal records through polling. However, this approach is not server-friendly as it causes the client to consume significant server resources and is also not sufficiently timely. Webhooks are designed to tackle this issue. A webhook will push the deposit and withdrawal records, but there is no guarantee that the push will occur only once. Moreover, this push is not designed to be idempotent.
How to start with The Webhook?
Webhook Setup Procedure on website
Navigate to Entity Management > Webhook Endpoint Management (after API key management) to set up a webhook endpoint
Click on the "Add Webhook Endpoint" button.
Provide an appropriate name for your webhook endpoint and specify the HTTPS URL.
Select the wallets linked to the webhook and indicate the types of events the webhook should monitor.
Click on the "Submit" button to create the webhook.
Note:
- You can create up to 30 webhooks.
- When a new webhook is created, it is disabled by default. Enable it using the toggle switch once your service is ready.
- For each event dispatched from the webhook, an HTTP status code 200 is expected to indicate successful delivery. If no response is received, the system will retry, with increasing delays between attempts: 30s, 120s, 480s, 1920s, and 7680s. If all retries fail, Ceffu will mark the delivery status as 'Failed'.
- A webhook endpoint will be suspended after 500 failed notifications (this limit resets daily, UTC+0, or each time the webhook is re-enabled). You can manually re-enable it via the user interface to resume message reception.
- Any response other than HTTP 200, including no response (“null”), is considered a failure.
- There is a "Test" button on the website. Clicking it sends a POST request with empty data to the webhook endpoint. The test is successful if an HTTP 200 OK response is received within 10 seconds; otherwise, it fails. Failures from these tests will not be counted towards the suspension limit.
Decode the data
Content type of response is in application/json
Response Example:{ "entityId": "36981140216868864", "webhookId": "1788141873578217474", "sign": "gawAT2ndVvqfyGmFmQwjHXzCRorHbcxFmz6uE/SUJHLZjmwlqUZNH2t6WiBdRHEuk9fvEREWQwBl5nN6pzsX4Q==", "event": "1", "timestamp": 1720606148847, "data": { "orderViewId": "20400454368144883712", "txId": null, "transferType": 20, "direction": 10, "fromAddress": "1544594690749788161", "toAddress": "1572553622146764801", "network": null, "coinSymbol": "TRX", "amount": "1.33000000000000000000", "feeSymbol": null, "feeAmount": null, "status": 40, "confirmedBlockCount": null, "maxConfirmBlock": null, "unlockConfirm": null, "memo": null, "txTime": 1720606148703, "walletIdStr": "1572553622146764801" } }
Response structure:
Attributes Definition entityId Institution Id webhookId Webhook Id sign Signature of response event - "1" (DEPOSIT_SUCCESS)
- "2" (DEPOSIT_FAILED)
- "3" (WITHDRAWAL_SUCCESS)
- "4" (WITHDRAWAL_FAILED)
- "11" (DELEGATION_SUCCESS)
- "12" (DELEGATION_FAILED)
- "13" (UNDELEGATION_SUCCESS)
- "14" (UNDELEGATION_FAILED)
timestamp Unix time data Detail data of corresponding event Download Key for checking signature
Java code example to verify signature:
// data should be string representation of response data with fields "sign" omitted and keys sorted in ascending order public String verify(String data, String sign) throws Exception { // key for checking signature String publicKey = ""; Signature signature = Signature.getInstance("SHA256withRSA"); signature.initVerify(publicKey); signature.update(data.getBytes()); return signature.verify(Base64.getDecoder().decode(sign.getBytes())); }
Javascript code example to verify signature:
const NodeRSA = require("node-rsa"); // key for checking signature const signPublicKeyBase64 = "..."; const sortObjectKeys = (obj) => { if (typeof obj !== "object" || obj === null) { return obj; } if (Array.isArray(obj)) { return obj.map(sortObjectKeys); } return Object.keys(obj) .sort() .reduce((result, key) => { result[key] = sortObjectKeys(obj[key]); return result; }, {}); }; const stringify = (data) => JSON.stringify(sortObjectKeys(data)); const verify = (data) => { const publicKey = new NodeRSA(); publicKey.importKey( Buffer.from(signPublicKeyBase64, "base64"), "pkcs8-public-der" ); const { encoded, sign, ...rest } = data; return publicKey.verify( Buffer.from(stringify(rest), "utf-8"), Buffer.from(sign, "base64") ); }; // webhook response data const data = ...; console.log("verified:", verify(data));
Python code example to verify signature:
from cryptography.exceptions import InvalidSignature from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.backends import default_backend import base64 import json # key for checking signature signPublicKeyBase64 = "..." def sort_keys(o): if isinstance(o, dict): return {k: sort_keys(v) for k, v in sorted(o.items())} if isinstance(o, list): return [sort_keys(v) for v in o] else: return o def stringify(data): sorted_data = sort_keys(data) return json.dumps(sorted_data, separators=(',', ':')) def verify(data): sign = data.pop('sign', None) encoded = data.pop('encoded', None) data_string = stringify(data) publicKey = serialization.load_der_public_key( base64.b64decode(signPublicKeyBase64), default_backend() ) try: publicKey.verify( base64.b64decode(sign), data_string.encode(), padding.PKCS1v15(), hashes.SHA256() ) return True except InvalidSignature: return False # webhook response data data = "..." print('verified:', verify(data))
Last modified: 4 个月前