API and Webhook Integrations – Automate Your Access Control with SnapKey
Complete technical guide to SnapKey's REST API, webhooks, MQTT, and integrations. Perfect for developers who want to automate access control and integrate with existing systems.

SnapKey offers a fully RESTful API and real-time webhooks to integrate access control with your existing systems. This guide is written for developers and IT architects who want to automate access management.
Integration Options
REST API
Full CRUD API for keys, users, locks, logs, and configuration
Webhooks
Real-time push notifications when events occur
MQTT
IoT protocol for real-time communication with devices
GraphQL
Flexible query language for complex data fetching
OAuth 2.0
Modern authentication with scoped access tokens
Bulk Operations
Batch import/export via CSV, JSON, and XML
REST API Overview
Authentication
# Obtain access token
curl -X POST https://api.snapkey.dk/v1/auth/token \
-H "Content-Type: application/json" \
-d '{
"client_id": "your_client_id",
"client_secret": "your_client_secret",
"grant_type": "client_credentials"
}'
# Response
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
Core Endpoints
Base URL: https://api.snapkey.dk/v1
Authentication:
├─ POST /auth/token # Get access token
└─ POST /auth/refresh # Refresh token
Users:
├─ GET /users # List users
├─ GET /users/{id} # Get user details
├─ POST /users # Create user
├─ PATCH /users/{id} # Update user
└─ DELETE /users/{id} # Delete user
Keys:
├─ GET /keys # List keys
├─ GET /keys/{id} # Get key details
├─ POST /keys # Issue new key
├─ PATCH /keys/{id} # Update key permissions
└─ DELETE /keys/{id} # Revoke key
Locks:
├─ GET /locks # List all locks
├─ GET /locks/{id} # Get lock details
├─ GET /locks/{id}/status # Get real-time status
└─ POST /locks/{id}/unlock # Remote unlock (emergency)
Access Logs:
├─ GET /logs/access # Query access logs
├─ GET /logs/access/{id} # Get specific event
└─ GET /logs/access/export # Export logs (CSV/JSON)
Webhooks:
├─ GET /webhooks # List webhook subscriptions
├─ POST /webhooks # Create webhook
├─ PATCH /webhooks/{id} # Update webhook
└─ DELETE /webhooks/{id} # Delete webhook
Common Use Cases
Use Case 1: Automatic Onboarding
Scenario: New employee in HR system → automatic key provisioning
import requests
class SnapKeyIntegration:
def __init__(self, api_key):
self.base_url = "https://api.snapkey.dk/v1"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def onboard_employee(self, employee_data):
# 1. Create user in SnapKey
user_payload = {
"email": employee_data["email"],
"first_name": employee_data["first_name"],
"last_name": employee_data["last_name"],
"department": employee_data["department"],
"role": employee_data["role"]
}
user_response = requests.post(
f"{self.base_url}/users",
json=user_payload,
headers=self.headers
)
user_id = user_response.json()["id"]
# 2. Issue keys based on department
locks = self.get_locks_for_department(employee_data["department"])
key_payload = {
"user_id": user_id,
"locks": locks,
"valid_from": employee_data["start_date"],
"valid_until": None, # Permanent until terminated
"time_restrictions": {
"monday": {"start": "07:00", "end": "19:00"},
"tuesday": {"start": "07:00", "end": "19:00"},
"wednesday": {"start": "07:00", "end": "19:00"},
"thursday": {"start": "07:00", "end": "19:00"},
"friday": {"start": "07:00", "end": "19:00"}
}
}
key_response = requests.post(
f"{self.base_url}/keys",
json=key_payload,
headers=self.headers
)
# 3. Send welcome email with QR code
self.send_welcome_email(user_id, key_response.json()["qr_code_url"])
return {"user_id": user_id, "key_id": key_response.json()["id"]}
Use Case 2: Temporary Contractor Access
// Node.js example: Issue temporary key to contractor
const axios = require('axios');
async function grantContractorAccess(contractor, project) {
const snapkey = axios.create({
baseURL: 'https://api.snapkey.dk/v1',
headers: {
'Authorization': `Bearer ${process.env.SNAPKEY_API_KEY}`,
'Content-Type': 'application/json'
}
});
try {
// 1. Create temporary user
const userResponse = await snapkey.post('/users', {
email: contractor.email,
first_name: contractor.first_name,
last_name: contractor.last_name,
company: contractor.company,
tags: ['contractor', 'temporary']
});
const userId = userResponse.data.id;
// 2. Issue time-limited key
const keyResponse = await snapkey.post('/keys', {
user_id: userId,
locks: project.authorized_locks,
valid_from: project.start_date,
valid_until: project.end_date,
time_restrictions: {
monday: { start: '08:00', end: '17:00' },
tuesday: { start: '08:00', end: '17:00' },
wednesday: { start: '08:00', end: '17:00' },
thursday: { start: '08:00', end: '17:00' },
friday: { start: '08:00', end: '17:00' }
},
max_uses: 50 // Maximum 50 uses
});
// 3. Send SMS with access instructions
await sendSMS(contractor.phone, {
message: `Your access to ${project.name} is now active.
Scan QR code: ${keyResponse.data.qr_code_url}`
});
return {
user_id: userId,
key_id: keyResponse.data.id,
expires: project.end_date
};
} catch (error) {
console.error('Failed to grant contractor access:', error.response.data);
throw error;
}
}
Webhooks
Setting Up Webhooks
# Create webhook subscription
curl -X POST https://api.snapkey.dk/v1/webhooks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/snapkey",
"events": [
"access.granted",
"access.denied",
"key.created",
"key.revoked",
"door.forced"
],
"secret": "your_webhook_secret_for_verification"
}'
Available Events
Access Events:
├─ access.granted # Successful access
├─ access.denied # Access denied
├─ access.expired # Attempted use of expired key
└─ access.invalid # Invalid credentials
Key Events:
├─ key.created # New key issued
├─ key.updated # Key permissions changed
├─ key.revoked # Key revoked
└─ key.expired # Key reached expiration
Lock Events:
├─ lock.online # Lock came online
├─ lock.offline # Lock went offline
├─ door.forced # Door forced open (sensor)
└─ door.left_open # Door left open (timeout)
User Events:
├─ user.created # New user added
├─ user.updated # User details changed
└─ user.deleted # User removed
Webhook Handler Example
from flask import Flask, request, jsonify
import hmac
import hashlib
app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_secret"
@app.route('/webhooks/snapkey', methods=['POST'])
def snapkey_webhook():
# 1. Verify signature
signature = request.headers.get('X-SnapKey-Signature')
payload = request.get_data()
expected_signature = hmac.new(
WEBHOOK_SECRET.encode(),
payload,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected_signature):
return jsonify({"error": "Invalid signature"}), 401
# 2. Parse event
event = request.json
event_type = event['type']
# 3. Handle different event types
if event_type == 'access.granted':
handle_access_granted(event['data'])
elif event_type == 'access.denied':
handle_access_denied(event['data'])
elif event_type == 'door.forced':
handle_security_alert(event['data'])
return jsonify({"status": "received"}), 200
def handle_security_alert(data):
"""Immediate response to forced door"""
send_sms_to_security({
"message": f"ALARM: Door forced at {data['lock_name']}",
"location": data['location_coordinates']
})
trigger_video_recording(data['lock_id'])
Integration Patterns
Pattern 1: HR System Sync
HR System → API → SnapKey
├─ Employee hired → Create user + issue keys
├─ Department change → Update key permissions
├─ Employee terminated → Revoke all keys immediately
└─ Daily sync → Verify consistency
Pattern 2: Building Management System (BMS)
def access_event_handler(access_event):
"""When someone enters a room, adjust HVAC"""
if access_event['type'] == 'access.granted':
room = access_event['lock']['room']
# Turn on lights
bms.set_lights(room, state='on')
# Adjust temperature
bms.set_temperature(room, target=21)
# Schedule auto-off after 2 hours
schedule_room_reset(room, delay_minutes=120)
Pattern 3: Visitor Management
async function registerVisitor(visitor, host, duration_hours) {
// 1. Create temporary user
const user = await snapkey.post('/users', {
email: visitor.email,
first_name: visitor.first_name,
last_name: visitor.last_name,
tags: ['visitor'],
metadata: {
host_employee: host.email,
company: visitor.company
}
});
// 2. Issue time-limited key
const key = await snapkey.post('/keys', {
user_id: user.id,
locks: ['lobby_entrance', 'meeting_room_a'],
valid_from: new Date().toISOString(),
valid_until: new Date(Date.now() + duration_hours * 3600000).toISOString()
});
// 3. Print visitor badge with QR code
await printBadge({
name: visitor.first_name + ' ' + visitor.last_name,
qr_code: key.qr_code_url,
valid_until: key.valid_until
});
return key;
}
Rate Limits & Best Practices
Rate Limits
Standard tier:
├─ 1000 requests/hour
└─ 100 webhook deliveries/minute
Enterprise tier:
├─ 10,000 requests/hour
├─ 1000 webhook deliveries/minute
└─ Dedicated API endpoints
Best Practices
- Cache responses – Don't fetch the same data repeatedly
- Use webhooks instead of polling when possible
- Implement exponential backoff for retries
- Batch operations when creating multiple keys
- Use GraphQL for complex queries to reduce roundtrips
- Monitor API usage to avoid rate limits
FAQ
Is API access included in all licenses?
API access is included in Enterprise licenses. Contact us for pricing on other tiers.
How fast are webhooks delivered?
Webhooks are typically sent within 1 second of the event. We guarantee delivery with automatic retries.
Can I test the API without affecting production?
Yes, we offer a complete sandbox environment at https://sandbox-api.snapkey.dk/v1
Contact Us
Need help getting started with the SnapKey API? Our developer team is ready to help.
Related articles
CER Directive – Complete Guide to Critical Infrastructure Compliance
Understand the CER Directive (EU 2022/2557) and learn how SnapKey helps secure your critical infrastructure with advanced access control and compliance.
Access Control for District Heating – Secure Access to Substations and Cabinets
Digital access control for district heating companies. Replace lockboxes with traceable access to heat substations, exchanger stations, and technical rooms.
Access Control for Electricity Grid and Substations – CER & NIS2 Ready
Secure access to transformer stations, grid components, and technical rooms. Meet CER and NIS2 with battery-free, offline access control from SnapKey.