Receive real-time notifications when submissions are graded, leads are scored, or routing decisions are made.
Webhooks provide real-time HTTP notifications when events occur in Grader.io. Use them to trigger workflows, update external systems, or notify team members instantly when high-value leads arrive.
submission.created - New form submission receivedsubmission.scored - Lead has been evaluated and scoredsubmission.routed - Lead assigned to sales rep or teamsubmission.updated - Lead information modifiedgrader.activated - Grader went livegrader.paused - Grader stopped processinggrader.performance_alert - Conversion rate changed significantlyintegration.connected - New platform connectedintegration.failed - Connection error occurredintegration.sync_completed - Data synchronization finishedYour endpoint must accept POST requests and return a 200 status code:
// Node.js/Express example app.post('/grader-webhook', (req, res) => { const { event, data, timestamp } = req.body; console.log(`Received ${event} at ${timestamp}`); // Process the webhook data switch (event) { case 'submission.scored': handleNewLead(data); break; case 'submission.routed': notifyAssignedRep(data); break; default: console.log('Unhandled event:', event); } res.status(200).json({ received: true }); });
Use the webhook tester to verify your endpoint:
# Test payload example { "event": "submission.scored", "webhook_id": "wh_abc123", "timestamp": "2023-10-15T14:30:00Z", "data": { "submission_id": "sub_xyz789", "score": 87, "grade": "hot", "form_data": { "email": "john.doe@acme.com", "company": "Acme Corporation", "jobTitle": "VP Marketing" }, "grader": { "id": "grader_123", "name": "Enterprise Lead Grader" } } }
All webhook payloads include:
| Field | Type | Description |
|---|---|---|
| string | Event type identifier |
| string | Unique webhook identifier |
| string | ISO 8601 timestamp |
| object | Event-specific data |
{ "event": "submission.scored", "webhook_id": "wh_abc123", "timestamp": "2023-10-15T14:30:00Z", "data": { "submission": { "id": "sub_xyz789", "created_at": "2023-10-15T14:29:30Z", "score": 87, "grade": "hot", "source": "website_form", "form_data": { "email": "john.doe@acme.com", "firstName": "John", "lastName": "Doe", "company": "Acme Corporation", "jobTitle": "VP Marketing", "phone": "+1-555-0123", "website": "https://acme.com" } }, "grader": { "id": "grader_123", "name": "Enterprise Lead Grader", "version": "1.2" }, "routing": { "assigned_to": "rep_john_smith", "team": "enterprise_sales", "territory": "west_coast" } } }
Verify webhook authenticity using HMAC signatures:
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), Buffer.from(expectedSignature) ); } // Express middleware function validateWebhook(req, res, next) { const signature = req.headers['x-grader-signature']; const payload = JSON.stringify(req.body); if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) { return res.status(401).json({ error: 'Invalid signature' }); } next(); }
# Python/Django example import requests from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST @csrf_exempt @require_POST def grader_webhook(request): data = json.loads(request.body) if data['event'] == 'submission.scored': submission = data['data']['submission'] # Create lead in CRM crm_data = { 'email': submission['form_data']['email'], 'company': submission['form_data']['company'], 'lead_score': submission['score'], 'lead_source': 'Grader.io', 'status': 'New' } # Send to CRM API response = requests.post( 'https://api.crm.com/leads', json=crm_data, headers={'Authorization': f'Bearer {CRM_API_KEY}'} ) if response.status_code == 201: print(f"Lead created in CRM: {submission['id']}") else: print(f"CRM error: {response.text}") return JsonResponse({'status': 'received'})
// High-value lead alerts async function handleHighValueLead(data) { const submission = data.submission; if (submission.score >= 85) { const slackPayload = { channel: '#hot-leads', username: 'Grader.io', icon_emoji: ':fire:', text: `🔥 Hot Lead Alert! Score: ${submission.score}`, attachments: [{ color: 'good', fields: [ { title: 'Company', value: submission.form_data.company, short: true }, { title: 'Contact', value: submission.form_data.email, short: true }, { title: 'Title', value: submission.form_data.jobTitle, short: true }, { title: 'Score', value: submission.score, short: true } ], actions: [{ type: 'button', text: 'View in Grader.io', url: `https://app.grader.io/submissions/${submission.id}` }] }] }; await fetch(process.env.SLACK_WEBHOOK_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(slackPayload) }); } }
// PHP example for Mailchimp integration function handleLeadRouting($data) { $submission = $data['submission']; $routing = $data['routing']; // Add to appropriate Mailchimp list based on score $listId = ''; if ($submission['score'] >= 80) { $listId = 'hot-leads-list'; } elseif ($submission['score'] >= 60) { $listId = 'warm-leads-list'; } else { $listId = 'nurture-list'; } $mailchimp = new MailchimpAPI($apiKey); $mailchimp->addListMember($listId, [ 'email_address' => $submission['form_data']['email'], 'status' => 'subscribed', 'merge_fields' => [ 'FNAME' => $submission['form_data']['firstName'], 'LNAME' => $submission['form_data']['lastName'], 'COMPANY' => $submission['form_data']['company'], 'SCORE' => $submission['score'] ], 'tags' => ['grader-io', 'lead-' . $submission['grade']] ]); }
Track webhook performance in the dashboard:
Common failure reasons:
Grader.io automatically retries failed webhooks:
// For Google Sheets integration function doPost(e) { const data = JSON.parse(e.postData.contents); if (data.event === 'submission.scored') { const submission = data.data.submission; // Add to Google Sheet const sheet = SpreadsheetApp.getActiveSheet(); sheet.appendRow([ new Date(), submission.form_data.email, submission.form_data.company, submission.score, submission.grade ]); } return ContentService.createTextOutput(JSON.stringify({received: true})); }
Create a Zapier webhook trigger:
Once webhooks are configured: