Core Features
Webhooks
Webhooks allow you to receive real-time notifications about important events in your MyBerryFlow integration, such as successful payments, KYC requirements, and seller status changes.
MyBerryFlow sends webhooks as HTTP POST requests to your configured endpoint. Your endpoint should return a 2xx status code to acknowledge receipt.
Setting up webhooks
Configure your webhook endpoint in the MyBerryFlow dashboard under Settings → Webhooks. You can specify which events you want to receive.
Webhook endpoint requirements
- Must be accessible over HTTPS
- Should respond with a 2xx status code
- Should respond within 10 seconds
- Should be idempotent (handle duplicate events gracefully)
Event types
Payment Events
payment.succeeded
{
"type": "payment.succeeded",
"data": {
"paymentId": "pay_abc123",
"sellerId": "seller_xyz789",
"amount": 2999,
"currency": "usd",
"customerEmail": "customer@example.com",
"metadata": {
"productName": "Premium Service"
}
},
"created": "2024-01-15T14:30:00Z"
}payment.failed
{
"type": "payment.failed",
"data": {
"paymentId": "pay_abc123",
"sellerId": "seller_xyz789",
"amount": 2999,
"currency": "usd",
"failureReason": "card_declined",
"failureMessage": "Your card was declined."
},
"created": "2024-01-15T14:30:00Z"
}Seller Events
seller.created
{
"type": "seller.created",
"data": {
"sellerId": "seller_abc123",
"email": "seller@example.com",
"country": "US",
"status": "active",
"onboardingType": "deferred"
},
"created": "2024-01-15T10:30:00Z"
}seller.kyc_required
{
"type": "seller.kyc_required",
"data": {
"sellerId": "seller_abc123",
"email": "seller@example.com",
"totalRevenue": 10000,
"kycThreshold": 10000,
"onboardingUrl": "https://connect.stripe.com/setup/s/...",
"message": "Complete your account setup to continue receiving payments"
},
"created": "2024-01-15T12:00:00Z"
}seller.verified
{
"type": "seller.verified",
"data": {
"sellerId": "seller_abc123",
"email": "seller@example.com",
"kycCompletedAt": "2024-01-15T16:45:00Z",
"canReceivePayouts": true
},
"created": "2024-01-15T16:45:00Z"
}seller.kyc_failed
{
"type": "seller.kyc_failed",
"data": {
"sellerId": "seller_abc123",
"email": "seller@example.com",
"failureReason": "document_verification_failed",
"requirements": [
"identity_document",
"address_verification"
]
},
"created": "2024-01-15T17:00:00Z"
}Handling webhooks
Basic webhook handler
Node.js/Express Example
app.post('/webhook/myberryflow', express.raw({type: 'application/json'}), (req, res) => {
const event = JSON.parse(req.body);
// Handle the event
switch (event.type) {
case 'payment.succeeded':
console.log('Payment succeeded:', event.data.paymentId);
// Update your database, send confirmation email, etc.
break;
case 'seller.kyc_required':
console.log('Seller needs KYC:', event.data.sellerId);
// Send notification email to seller with onboarding link
sendKycNotification(event.data.email, event.data.onboardingUrl);
break;
case 'seller.verified':
console.log('Seller verified:', event.data.sellerId);
// Enable additional features, send congratulations email
break;
default:
console.log('Unhandled event type:', event.type);
}
// Return 200 to acknowledge receipt
res.json({received: true});
});Idempotency
MyBerryFlow may send the same webhook multiple times. Include an idempotency key to handle duplicates:
Idempotent Handler
const processedEvents = new Set();
app.post('/webhook/myberryflow', (req, res) => {
const event = req.body;
const eventId = event.id; // Use event ID for idempotency
// Check if we've already processed this event
if (processedEvents.has(eventId)) {
return res.json({received: true});
}
// Process the event
handleEvent(event);
// Mark as processed
processedEvents.add(eventId);
res.json({received: true});
});Webhook security
Verify webhook signatures
Always verify webhook signatures to ensure they're from MyBerryFlow and haven't been tampered with.
MyBerryFlow signs webhooks with your webhook secret. Verify the signature:
Signature Verification
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSignature, 'hex')
);
}
app.post('/webhook/myberryflow', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['myberryflow-signature'];
const payload = req.body;
if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(400).send('Invalid signature');
}
// Process the verified webhook
const event = JSON.parse(payload);
handleEvent(event);
res.json({received: true});
});Testing webhooks
Using ngrok for local development
For local testing, use ngrok to create a public URL for your local server:
ngrok setup
# Install ngrok
npm install -g ngrok
# Start your local server
node server.js
# In another terminal, expose port 3000
ngrok http 3000
# Use the ngrok URL in MyBerryFlow dashboard
# Example: https://abc123.ngrok.io/webhook/myberryflowManual webhook testing
You can test webhook handling by sending POST requests to your endpoint:
Test webhook
curl -X POST https://yourapp.com/webhook/myberryflow \
-H "Content-Type: application/json" \
-d '{
"type": "payment.succeeded",
"data": {
"paymentId": "pay_test123",
"sellerId": "seller_test456",
"amount": 1000,
"currency": "usd"
},
"created": "2024-01-15T14:30:00Z"
}'