Webhooks
Receive real-time notifications for events in your AccessIQ organization. Build integrations that react to user, organization, and security events.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /webhooks | List webhooks |
GET | /webhooks/:id | Get webhook |
POST | /webhooks | Create webhook |
PATCH | /webhooks/:id | Update webhook |
DELETE | /webhooks/:id | Delete webhook |
POST | /webhooks/:id/test | Send test event |
Create Webhook
POST /v1/organizations/:org/webhooksbash
curl -X POST https://api.accessiq.io/v1/organizations/acme-corp/webhooks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "User Events",
"url": "https://your-app.com/webhooks/accessiq",
"events": [
"user.created",
"user.updated",
"user.deleted",
"user.login"
],
"enabled": true,
"secret": "whsec_your_secret_key"
}'
# Response (201 Created)
{
"data": {
"id": "wh_abc123",
"name": "User Events",
"url": "https://your-app.com/webhooks/accessiq",
"events": ["user.created", "user.updated", "user.deleted", "user.login"],
"enabled": true,
"secret": "whsec_your_secret_key",
"createdAt": "2024-01-15T12:00:00Z"
}
}Available Events
User Events
user.created- New user createduser.updated- User profile updateduser.deleted- User deleteduser.suspended- User suspendeduser.activated- User activateduser.login- User logged inuser.login_failed- Login attempt faileduser.logout- User logged outuser.password_changed- Password changeduser.mfa_enabled- MFA enableduser.mfa_disabled- MFA disabled
Organization Events
organization.created- Organization createdorganization.updated- Organization updatedorganization.deleted- Organization deletedorganization.member_added- Member addedorganization.member_removed- Member removed
Role Events
role.created- Role createdrole.updated- Role updatedrole.deleted- Role deletedrole.assigned- Role assigned to userrole.revoked- Role revoked from user
Security Events
security.suspicious_activity- Suspicious activity detectedsecurity.api_key_created- API key createdsecurity.api_key_revoked- API key revokedsecurity.session_revoked- Session revokedsecurity.break_glass_requested- Emergency access requested
Webhook Payload
Example Webhook Payloadjson
{
"id": "evt_abc123",
"type": "user.created",
"timestamp": "2024-01-15T12:00:00Z",
"organization": {
"id": "org_acme",
"name": "Acme Corp"
},
"data": {
"id": "user_def456",
"email": "jane@acme.com",
"firstName": "Jane",
"lastName": "Smith",
"status": "pending",
"createdAt": "2024-01-15T12:00:00Z"
},
"actor": {
"type": "user",
"id": "user_abc123",
"email": "admin@acme.com"
},
"metadata": {
"ipAddress": "192.168.1.100",
"userAgent": "Mozilla/5.0...",
"source": "api"
}
}Signature Verification
Verify webhook signatures to ensure requests come from AccessIQ:
Node.js Signature Verificationjavascript
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const timestamp = signature.split(',')[0].split('=')[1];
const receivedSig = signature.split(',')[1].split('=')[1];
// Check timestamp is within 5 minutes
const currentTime = Math.floor(Date.now() / 1000);
if (currentTime - parseInt(timestamp) > 300) {
throw new Error('Webhook timestamp too old');
}
// Verify signature
const signedPayload = `${timestamp}.${JSON.stringify(payload)}`;
const expectedSig = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
if (receivedSig !== expectedSig) {
throw new Error('Invalid webhook signature');
}
return true;
}
// Express middleware
app.post('/webhooks/accessiq', (req, res) => {
const signature = req.headers['accessiq-signature'];
try {
verifyWebhookSignature(req.body, signature, process.env.WEBHOOK_SECRET);
// Process the webhook
const { type, data } = req.body;
console.log(`Received ${type} event`, data);
res.status(200).json({ received: true });
} catch (error) {
console.error('Webhook verification failed:', error.message);
res.status(400).json({ error: error.message });
}
});Always Verify Signatures
Never process webhook payloads without verifying the signature. This prevents attackers from sending fake events to your endpoint.
Retry Policy
If your endpoint returns an error (non-2xx status), AccessIQ will retry:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry (final) | 24 hours |
Webhook Logs
View delivery attempts, response codes, and retry history in the dashboard under Settings → Webhooks → Logs.
Test Webhook
POST /v1/organizations/:org/webhooks/:id/testbash
curl -X POST https://api.accessiq.io/v1/organizations/acme-corp/webhooks/wh_abc123/test \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"eventType": "user.created"
}'
# Response
{
"success": true,
"deliveryId": "del_xyz789",
"responseCode": 200,
"responseTime": 245,
"responseBody": "{ \"received\": true }"
}Webhook Schema
Webhook Objecttypescript
interface Webhook {
id: string;
name: string;
url: string;
events: string[];
enabled: boolean;
secret: string;
headers?: Record<string, string>;
metadata?: {
lastDelivery?: string;
successRate?: number;
failureCount?: number;
};
createdAt: string;
updatedAt: string;
}
interface WebhookEvent {
id: string;
type: string;
timestamp: string;
organization: {
id: string;
name: string;
};
data: Record<string, any>;
actor?: {
type: 'user' | 'system' | 'api';
id?: string;
email?: string;
};
metadata?: Record<string, any>;
}Best Practices
- Always return 2xx quickly, then process async
- Implement idempotency using the event ID
- Store webhook secrets securely
- Monitor webhook health in your observability stack