API og Webhook-integrationer – Automatiser din adgangskontrol med SnapKey
Komplet teknisk guide til SnapKey's REST API, webhooks, MQTT og integrationer. Perfekt til udviklere der vil automatisere adgangskontrol og integrere med eksisterende systemer.

SnapKey tilbyder et fuldt RESTful API og real-time webhooks for at integrere adgangskontrol med jeres eksisterende systemer. Denne guide er skrevet til udviklere og IT-arkitekter der vil automatisere adgangsstyring.
Integration-muligheder
REST API
Fuldt CRUD API til nøgler, brugere, låse, logs og konfiguration
Webhooks
Real-time push-notifikationer når events sker
MQTT
IoT-protocol til real-time kommunikation med devices
GraphQL
Fleksibel query-språk for complex data fetching
OAuth 2.0
Moderne autentifikation med scoped access tokens
Bulk operations
Batch-import/export via CSV, JSON og 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)
Organizations:
├─ GET /organizations # List organizations
└─ GET /organizations/{id} # Get org details
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"]}
# Usage
snapkey = SnapKeyIntegration(api_key="your_api_key")
new_employee = {
"email": "jens@firma.dk",
"first_name": "Jens",
"last_name": "Jensen",
"department": "IT",
"role": "Developer",
"start_date": "2025-12-01"
}
result = snapkey.onboard_employee(new_employee)
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: {
// Only during business hours
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: `Din adgang til ${project.name} er nu aktiv.
Scan QR-koden: ${keyResponse.data.qr_code_url}`,
qr_code_url: keyResponse.data.qr_code_url
});
// 4. Schedule automatic cleanup
scheduleKeyRevocation(keyResponse.data.id, project.end_date);
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;
}
}
// Usage
grantContractorAccess(
{
email: 'contractor@firma.dk',
first_name: 'Peter',
last_name: 'Pedersen',
company: 'Pedersen Bygning ApS',
phone: '+4512345678'
},
{
name: 'Renovering Bygning A',
authorized_locks: ['lock_building_a_entrance', 'lock_building_a_basement'],
start_date: '2025-12-01T00:00:00Z',
end_date: '2025-12-31T23:59:59Z'
}
);
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'])
elif event_type == 'key.revoked':
handle_key_revocation(event['data'])
# 4. Acknowledge receipt
return jsonify({"status": "received"}), 200
def handle_access_granted(data):
"""Log successful access to SIEM"""
send_to_siem({
"event_type": "physical_access",
"result": "success",
"user": data['user_email'],
"location": data['lock_name'],
"timestamp": data['timestamp']
})
def handle_access_denied(data):
"""Alert on repeated failed access attempts"""
failed_attempts = count_recent_failures(data['user_id'], minutes=10)
if failed_attempts >= 3:
send_alert({
"severity": "high",
"message": f"Multiple failed access attempts by {data['user_email']}",
"location": data['lock_name']
})
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'])
if __name__ == '__main__':
app.run(port=5000)
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)
# Integrate SnapKey with BMS for climate control
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)
# Log occupancy
bms.mark_occupied(room, user=access_event['user'])
# Schedule auto-off after 2 hours
schedule_room_reset(room, delay_minutes=120)
Pattern 3: Visitor Management
// Complete visitor flow integration
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,
purpose: visitor.purpose
}
});
// 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,
company: visitor.company,
host: host.first_name + ' ' + host.last_name,
qr_code: key.qr_code_url,
valid_until: key.valid_until
});
// 4. Notify host
await sendEmail(host.email, {
subject: 'Your visitor has arrived',
body: `${visitor.first_name} ${visitor.last_name} from ${visitor.company} has checked in.`
});
return key;
}
MQTT for IoT Integration
import paho.mqtt.client as mqtt
import json
# Connect to SnapKey MQTT broker
client = mqtt.Client()
client.username_pw_set("your_api_key", "")
client.connect("mqtt.snapkey.dk", 8883)
# Subscribe to lock events
client.subscribe("snapkey/locks/+/status")
client.subscribe("snapkey/locks/+/access")
def on_message(client, userdata, msg):
topic = msg.topic
payload = json.loads(msg.payload)
if 'status' in topic:
# Lock status changed
lock_id = topic.split('/')[2]
print(f"Lock {lock_id} is now {payload['status']}")
elif 'access' in topic:
# Access event
print(f"Access: {payload['result']} by {payload['user']}")
client.on_message = on_message
client.loop_forever()
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
Er API-adgang inkluderet i alle licenser?
API-adgang er inkluderet i Enterprise-licenser. Contact us for pricing på andre tiers.
Hvor hurtigt leveres webhooks?
Webhooks sendes typisk inden for 1 sekund efter event. Vi garanterer delivery med automatic retries.
Kan jeg teste API'en uden at påvirke produktion?
Ja, vi tilbyder et komplet sandbox-miljø på https://sandbox-api.snapkey.dk/v1
Kontakt os
Brug for hjælp til at komme i gang med SnapKey API? Vores udviklerteam står klar.
Relaterede artikler
Digital adgangskontrol for detailhandel og selvbetjeningsboder
Moderne adgangsløsninger til unmanned stores, 24/7 butikker, vending operations og selvbetjening. SnapKey til retail automation.
Integration af fysisk og digital sikkerhed – Fremtidens helhedsorienterede sikkerhedsmodel
Lær hvordan moderne sikkerhedssystemer kombinerer adgangskontrol med cybersikkerhed gennem SIEM-integration, korrelation af hændelser og unified security operations.
6.000 danske virksomheder skal sikre kritisk infrastruktur – Er du omfattet?
Nye EU-direktiver betyder at ca. 6.000 danske virksomheder skal opfylde skærpede sikkerhedskrav. Tjek om din virksomhed er omfattet af NIS2 og CER-direktiverne.