This documentation explains how to integrate with and process payment notifications from dSociopay. When a payment is completed successfully, dSociopay sends a webhook notification to your specified endpoint. The webhook payload includes key transaction details such as payment status, amount, sender, receiver, and other pertinent information.
Webhook Notification Format
The webhook sends a JSON payload to your endpoint structured as follows:
{
"event": "payment_received",
"data": {
"transaction_id": "PLwUu2dPJ2kSJSHcUNn3cT",
"amount": "10.0",
"fee": "0.0992",
"settlement": "9.9008",
"currency": "NGN",
"customer": {
"name": "dSocio (dSociosms)",
"email": "[email protected]",
"account_number": "0776620402"
}
}
}
Webhook Data Breakdown
-
transaction_id: A unique identifier assigned to the transaction.
-
amount: The total amount paid by the customer in the transaction currency.
-
settlement: The net amount to be settled after applicable fees have been deducted.
-
fee: The fee charged and deducted from the payment before settlement.
Customer Details
Information about the customer associated with the transaction:
-
name: Customer's full name.
-
email: Customer's email address.
-
account_number: Customer's account number.
Webhook Integration Examples
import hashlib
import hmac
import json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
# Secret key shared between dSociopay and the webhook receiver
# This is used to generate and verify HMAC signatures
security_key = 'xxx' # Move this to environment variables in production
@csrf_exempt # Disable CSRF because webhooks are server-to-server requests
def webhook(request):
# Only allow POST requests for webhook delivery
if request.method != 'POST':
return JsonResponse({"error": "Invalid method"}, status=405)
# Retrieve signature sent by dSociopay in request headers
signature = request.headers.get('dSociopay-Signature')
# Reject request if signature is missing
if not signature:
return JsonResponse({"error": "Missing signature"}, status=400)
# Raw request body (IMPORTANT: must use raw bytes for signature verification)
webhook_data = request.body
# Generate our own signature using the same secret key and payload
calculated_signature = hmac.new(
security_key.encode('utf-8'), # Convert secret key to bytes
webhook_data, # Raw request body (bytes)
hashlib.sha256 # Hashing algorithm
).hexdigest()
# Compare signatures securely (prevents timing attacks)
if not hmac.compare_digest(calculated_signature, signature):
return JsonResponse({"error": "Invalid signature"}, status=403)
try:
# Convert JSON bytes into Python dictionary
data = json.loads(webhook_data.decode("utf-8"))
# Extract transaction details from webhook payload
transaction_id = data.get('transaction_id')
amount_paid = data.get('amount')
settlement_amount = data.get('settlement')
currency = data.get('currency')
# OPTIONAL: Prevent duplicate processing (idempotency check)
# This ensures the same transaction is not credited twice
# if Transaction.objects.filter(transaction_id=transaction_id).exists():
# return JsonResponse({"status": "duplicate"}, status=200)
# Process the transaction (e.g., update wallet, store record, etc.)
print(f"Transaction ID: {transaction_id}")
print(f"Amount Paid: {amount_paid}")
print(f"Settlement Amount: {settlement_amount}")
print(f"Currency: {currency}")
# Return success response to acknowledge webhook receipt
return JsonResponse({"status": "success"}, status=200)
except json.JSONDecodeError:
# Handle cases where payload is not valid JSON
return JsonResponse({"error": "Invalid JSON format"}, status=400)```php
<?php
// Secret key shared between dSociopay and your application
// Store this in an environment variable in production
$securityKey = 'xxx';
// Only allow POST requests
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode([
'error' => 'Invalid method'
]);
exit;
}
// Retrieve signature from request headers
$signature = $_SERVER['HTTP_DSOCIOPAY_SIGNATURE'] ?? null;
// Reject request if signature is missing
if (!$signature) {
http_response_code(400);
echo json_encode([
'error' => 'Missing signature'
]);
exit;
}
// Get the raw request body
$webhookData = file_get_contents('php://input');
// Generate HMAC-SHA256 signature
$calculatedSignature = hash_hmac(
'sha256',
$webhookData,
$securityKey
);
// Compare signatures securely
if (!hash_equals($calculatedSignature, $signature)) {
http_response_code(403);
echo json_encode([
'error' => 'Invalid signature'
]);
exit;
}
// Decode JSON payload
$data = json_decode($webhookData, true);
if (json_last_error() !== JSON_ERROR_NONE) {
http_response_code(400);
echo json_encode([
'error' => 'Invalid JSON format'
]);
exit;
}
// Extract transaction details
$transactionId = $data['transaction_id'] ?? null;
$amountPaid = $data['amount_paid'] ?? null;
$settlementAmount = $data['settlement_amount'] ?? null;
$currency = $data['currency'] ?? null;
// OPTIONAL: Prevent duplicate processing
// if (transactionExists($transactionId)) {
// http_response_code(200);
// echo json_encode(['status' => 'duplicate']);
// exit;
// }
// Process the transaction
error_log("Transaction ID: " . $transactionId);
error_log("Amount Paid: " . $amountPaid);
error_log("Settlement Amount: " . $settlementAmount);
error_log("Currency: " . $currency);
// Acknowledge successful receipt
http_response_code(200);
echo json_encode([
'status' => 'success'
]);
```
To verify that a webhook request was genuinely sent by dSociopay and has not been modified in transit, you should validate the webhook signature. This is done by generating a hash of the webhook payload using your secret security key and comparing the result with the value provided in the dSociopay-Signature request header.
Below is the updated webhook documentation, including a Python and PHP example that demonstrates how to perform signature verification.
Verifying the dSociopay Signature
How Signature Verification Works
To ensure that a webhook request originates from dSociopay and has not been altered during transmission, every webhook request includes a dSociopay-Signature header. This signature is generated by hashing the raw JSON payload using your private key.
When your server receives a webhook request, it should independently generate a hash from the received payload using the same private key and compare it with the signature provided in the request header. A matching signature confirms that the request is authentic and has not been tampered with.
Steps to Verify the Signature
-
Retrieve the Signature
- Extract the
dSociopay-Signaturevalue from the incoming request headers.
- Extract the
-
Obtain the Raw Payload
- Read the raw JSON payload exactly as it was received in the request body.
-
Generate a Verification Hash
- Using your private key and the same hashing algorithm used by dSociopay (for example, HMAC-SHA256), generate a hash from the raw payload.
-
Compare the Signatures
- Compare the hash you generated with the value of the
dSociopay-Signatureheader.
- Compare the hash you generated with the value of the
-
Validate the Request
- If both signatures match, the webhook request is valid and can be processed.
- If the signatures do not match, reject the request as it may have been modified or originated from an unauthorized source.

