Receive import data directly on your server in real-time.
Webhooks allow you to receive import data on your backend as soon as an import completes. This is useful for processing data server-side, syncing with databases, or triggering automated workflows.
Configure your webhook URL in the dashboard under Settings → Webhooks.
Used to verify webhook signatures
When an import completes, we send a POST request to your webhook URL with the following payload:
{
"event": "import.completed",
"timestamp": "2024-01-15T10:30:00.000Z",
"importId": "imp_abc123xyz",
"templateId": "tpl_def456uvw",
"organizationId": "org_ghi789rst",
"file": {
"name": "contacts.csv",
"type": "csv",
"size": 15234
},
"stats": {
"totalRows": 150,
"validRows": 145,
"skippedRows": 5,
"errorRows": 5
},
"metadata": {
"source": "onboarding",
"campaign": "q1-2024",
"userId": "user-123"
},
"user": {
"id": "user-123",
"email": "user@example.com",
"name": "John Doe"
},
"columnMapping": {
"Email Address": "email",
"Full Name": "name",
"Phone Number": "phone"
},
"data": {
"columns": ["email", "name", "phone"],
"rows": [
{
"email": "john@example.com",
"name": "John Doe",
"phone": "+1-555-0123"
},
{
"email": "jane@example.com",
"name": "Jane Smith",
"phone": "+1-555-0456"
},
// ... more rows
]
}
}| Event | Description |
|---|---|
| import.completed | Import finished successfully |
| import.failed | Import failed due to an error |
To ensure webhooks are coming from Rowporter, verify the signature using your webhook secret.
Every webhook request includes an X-Rowporter-Signature header containing an HMAC-SHA256 signature of the request body.
X-Rowporter-Signature: sha256=abc123def456...
import crypto from 'crypto';
function verifyWebhook(payload, signature, secret) {
const expectedSignature = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Express.js example
app.post('/api/webhooks/rowporter', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['x-rowporter-signature'];
const payload = req.body.toString();
if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(payload);
// Process the webhook
if (event.event === 'import.completed') {
console.log('Import completed:', event.importId);
console.log('Rows:', event.data.rows.length);
// Save to your database
await saveContacts(event.data.rows);
}
res.status(200).json({ received: true });
});import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
# Flask example
@app.route('/api/webhooks/rowporter', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-Rowporter-Signature')
payload = request.get_data()
if not verify_webhook(payload, signature, os.environ['WEBHOOK_SECRET']):
return jsonify({'error': 'Invalid signature'}), 401
event = request.get_json()
if event['event'] == 'import.completed':
print(f"Import completed: {event['importId']}")
save_contacts(event['data']['rows'])
return jsonify({'received': True}), 200If your webhook endpoint returns a non-2xx status code or times out, we'll automatically retry.
| Retry attempts | Up to 5 retries |
| Retry schedule | 1 min, 5 min, 30 min, 2 hours, 24 hours |
| Timeout | 30 seconds |
| Success response | Any 2xx status code |
Acknowledge the webhook immediately, then process data asynchronously. Don't make the webhook wait for your database operations.
Use the importId to deduplicate. Webhooks may be delivered more than once in rare cases.
Always verify the webhook signature to ensure requests are authentic.
Keep logs of received webhooks for debugging and audit purposes.
For imports with more than 10,000 rows, the data.rows array may be paginated. Check the pagination field and use the API to fetch remaining data if needed.
You can test your webhook endpoint using tools like:
Expose your local server to the internet for testing.
ngrok http 3000Free tool to inspect webhook payloads.
webhook.site →curl -X POST https://your-app.com/api/webhooks/rowporter \
-H "Content-Type: application/json" \
-H "X-Rowporter-Signature: sha256=test" \
-d '{
"event": "import.completed",
"importId": "imp_test123",
"templateId": "tpl_test456",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"columns": ["email", "name"],
"rows": [
{"email": "test@example.com", "name": "Test User"}
]
}
}'