Webhook Authentication
To ensure the integrity and authenticity of notifications, each webhook sent by Ecart Pay includes security headers that you can use to verify its origin.
Security Headers
Each webhook includes headers to verify the authenticity of the notification:
Content-Type: application/json
x-pay-timestamp: 1642234567890
x-pay-signature: SHA256=abc123def456...
x-pay-webhook-id: hook_12345678-1234-1234-1234-123456789abc
Header Description
- Content-Type: Always
application/json
- x-pay-timestamp: Request timestamp (in milliseconds, UTC) of when the webhook was sent.
- x-pay-signature: HMAC SHA256 signature to validate the integrity and authenticity of the notification.
- x-pay-webhook-id: Unique webhook identifier
Verify Signatures
To verify that the webhook comes from Ecart Pay, you must follow these steps:
1. Get the Secret
Each account has a unique secret that you can obtain from your administration panel. This secret is unique and must be stored securely.
2. Build the Base String
Concatenate the timestamp, webhook_id and the data body with the following format:
{timestamp}.{webhook_id}.{JSON.stringify(data)}
3. Generate the Signature
Use your secret key and the HMAC-SHA256 algorithm:
const crypto = require('crypto');
function verifyWebhookSignature(timestamp, webhookId, body, secret) {
const signatureString = `${timestamp}.${webhookId}.${JSON.stringify(body)}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signatureString)
.digest('hex');
return `SHA256=${expectedSignature}`;
}
4. Compare Signatures
Compare the generated value with the one received in the x-pay-signature header. Ignore the SHA256= prefix when comparing.
Implementation Examples
Node.js
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = 'your_webhook_secret';
app.post('/webhook', (req, res) => {
try {
// 1. Get headers
const timestamp = req.headers['x-pay-timestamp'];
const signature = req.headers['x-pay-signature'];
const webhookId = req.headers['x-pay-webhook-id'];
if (!timestamp || !signature || !webhookId) {
return res.status(400).json({ error: 'Missing headers' });
}
// 2. Verify signature
const signatureString = `${timestamp}.${webhookId}.${JSON.stringify(req.body)}`;
const expectedSignature = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(signatureString)
.digest('hex');
if (signature !== `SHA256=${expectedSignature}`) {
return res.status(401).json({ error: 'Invalid signature' });
}
// 3. Process webhook
console.log('Verified webhook:', req.body);
// 4. Respond successfully
res.status(200).json({ success: true });
} catch (error) {
console.error('Error verifying signature:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});
Security Best Practices
- Always verify the signature before processing the webhook.
- Use HTTPS to receive notifications.
- Keep the secret secure (use environment variables, don't share it).
- Validate critical headers (x-pay-timestamp, x-pay-signature, x-pay-webhook-id).
- Handle errors correctly (respond with 401 if the signature is invalid).
Troubleshooting
Invalid signature
- Verify that you are using the correct secret.
- Make sure you are building the base string correctly.
- Use UTF-8 as encoding.
- Verify that you are using HMAC-SHA256 and not another algorithm.
Missing headers
- Check that your server is correctly receiving all headers.
- If you use a proxy or load balancer, make sure the headers are not being removed.
- Verify how your framework exposes headers (some change the format or hide them).
This documentation is updated regularly. For the latest version, consult our documentation repository.
Updated 1 day ago