Setting Up Webhooks Without a Static IP
A step-by-step guide using the PunchConnect API to set up real-time attendance webhooks without managing local servers or static IPs.
The problem with traditional setups
Most biometric attendance systems require a local server running 24/7 with a static IP address. The device connects to your server via TCP, and if your server goes down or your IP changes, you lose punch data.
This architecture was designed in the early 2000s when on-premise servers were the norm. But today, most teams run their applications in the cloud — on AWS, GCP, Azure, or platforms like Railway and Render.
PunchConnect flips this model entirely. Instead of your server listening for device connections, PunchConnect acts as the intermediary. Your devices push data to PunchConnect, and PunchConnect pushes it to your app via webhooks.
How PunchConnect webhooks work
When an employee punches in or out on a biometric device, the device sends the event to PunchConnect's protocol engine. PunchConnect processes the event, normalizes the data, and immediately sends an HTTP POST request to your configured callback URL.
Your callback URL can be any publicly accessible endpoint — a serverless function on Vercel, a Flask route on Railway, an Express endpoint on Render, or even a Zapier webhook.
PunchConnect includes automatic retries with exponential backoff. If your server is temporarily unavailable, events are queued and retried for up to 72 hours. No data is lost.
Step 1: Create a webhook endpoint
First, create a simple endpoint on your server that accepts POST requests. Here's an example using Express.js:
app.post('/api/attendance', (req, res) => {
const { event, employee_id, timestamp, device_serial } = req.body;
// Verify the webhook signature
const signature = req.headers['x-punchconnect-signature'];
if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process the attendance event
console.log(`${event}: ${employee_id} at ${timestamp}`);
// Always respond with 200 to acknowledge receipt
res.status(200).json({ received: true });
});Step 2: Register the webhook
Use the PunchConnect API to register your webhook URL for the device:
from punchconnect import PunchConnect
client = PunchConnect(api_key="pc_live_your_api_key")
webhook = client.webhooks.create(
device_id="dev_abc123",
url="https://your-app.com/api/attendance",
events=["punch_in", "punch_out"],
secret="whsec_your_signing_secret"
)
print(f"Webhook active: {webhook.id}")Step 3: Test the integration
PunchConnect provides a test endpoint that simulates a punch event. Use it to verify your webhook is working correctly before connecting a real device.
You can also view webhook delivery logs in your dashboard — every request, response code, and retry attempt is recorded for debugging.
curl -X POST https://api.punchconnect.com/v1/webhooks/test \
-H "Authorization: Bearer pc_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"webhook_id": "whk_abc123", "event": "punch_in"}'Security considerations
Always verify webhook signatures. PunchConnect signs every webhook payload using HMAC-SHA256 with your webhook secret. This ensures the request genuinely came from PunchConnect and hasn't been tampered with.
Use HTTPS for your callback URL. PunchConnect will not deliver webhooks to plain HTTP endpoints in production mode.
Implement idempotency. In rare cases (network timeouts), PunchConnect may deliver the same event twice. Use the event_id field to deduplicate.
Conclusion
With PunchConnect webhooks, you don't need a static IP, a local server, or complex networking. Just deploy your app anywhere, expose an endpoint, and receive real-time attendance data.
The entire setup takes about 15 minutes — from creating your account to receiving your first live punch event.