Documentation Index
Fetch the complete documentation index at: https://docs.spike.ac/llms.txt
Use this file to discover all available pages before exploring further.
Webhooks let you send form submissions to your own server or third-party services.
Setup
- Go to your form settings
- Enable webhooks
- Enter your webhook URL
- Optionally add a webhook secret for signature verification
Spike sends a POST request with JSON body:
{
"event": "submission.created",
"formId": "clx123abc",
"formName": "Contact Form",
"formSlug": "abc123xyz",
"submissionId": "sub_xyz789",
"data": {
"email": "user@example.com",
"name": "John Doe",
"message": "Hello, I have a question..."
},
"metadata": {
"ip": "1.2.3.4",
"userAgent": "Mozilla/5.0...",
"referrer": "https://yoursite.com/contact",
"country": "US",
"timestamp": "2024-01-15T10:30:00.000Z"
}
}
Signature Verification
If you set a webhook secret, Spike includes a signature header for verification:
X-Spike-Signature: sha256=abc123...
Verify the signature in your webhook handler:
import crypto from 'crypto';
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return `sha256=${expected}` === signature;
}
// Express.js example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-spike-signature'];
const isValid = verifySignature(req.body, signature, process.env.WEBHOOK_SECRET);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
const data = JSON.parse(req.body);
// Process the webhook...
res.status(200).send('OK');
});
Retries
Spike automatically retries failed webhooks with exponential backoff:
| Attempt | Delay |
|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
A webhook is considered failed if:
- Response status is not 2xx
- Request times out (30 seconds)
- Connection error
Response
Your webhook should return a 2xx status code to acknowledge receipt. The response body is ignored.
Testing
Test your webhook locally using ngrok:
Then use the ngrok URL as your webhook URL during development.
Example Handlers
Node.js / Express
const express = require('express');
const app = express();
app.post('/webhook', express.json(), (req, res) => {
const { event, data, metadata } = req.body;
console.log('New submission:', data.email);
// Process the submission...
res.status(200).send('OK');
});
Python / Flask
from flask import Flask, request
app = Flask(__name__)
@app.route('/webhook', methods=['POST'])
def webhook():
data = request.json
print(f"New submission: {data['data']['email']}")
# Process the submission...
return 'OK', 200
Next.js API Route
// app/api/webhook/route.ts
import { NextResponse } from 'next/server';
import crypto from 'crypto';
export async function POST(request: Request) {
const body = await request.text();
const signature = request.headers.get('x-spike-signature');
// Verify signature
const expected = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET!)
.update(body)
.digest('hex');
if (`sha256=${expected}` !== signature) {
return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
}
const data = JSON.parse(body);
// Process the submission...
console.log('New submission:', data.data.email);
return NextResponse.json({ received: true });
}