Skip to main content
Version: v1 (Current)

Outgoing Webhooks

Outgoing webhooks allow GxP to send HTTP callbacks to your servers when specific events occur.

Overview

Configure outgoing webhooks to:

  • Sync data to external systems in real-time
  • Trigger workflows in other applications
  • Build integrations with CRMs, marketing tools, etc.
  • Create audit logs in external systems

Subscribing to Webhooks

Via API

curl -X POST "https://api.gramercy.cloud/api/v1/webhook/subscribe" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/gxp",
"events": ["attendee.created", "attendee.updated", "access.granted"],
"project_id": 123,
"secret": "your-webhook-secret"
}'

Response

{
"data": {
"id": "wh_abc123",
"url": "https://your-server.com/webhooks/gxp",
"events": ["attendee.created", "attendee.updated", "access.granted"],
"project_id": 123,
"is_active": true,
"created_at": "2024-01-15T10:00:00Z"
}
}

Unsubscribing

curl -X DELETE "https://api.gramercy.cloud/api/v1/webhook/unsubscribe/wh_abc123" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"

Available Events

Attendee Events

EventTriggered When
attendee.createdNew attendee is created
attendee.updatedAttendee data is modified
attendee.deletedAttendee is removed

Access Control Events

EventTriggered When
access.grantedAccess is granted at an access point
access.deniedAccess is denied at an access point

Form Events

EventTriggered When
form.response.createdNew form response is submitted
form.response.updatedForm response is modified

Credential Events

EventTriggered When
credential.createdCredential is assigned to attendee
credential.revokedCredential is removed from attendee

Webhook Payload Format

All webhooks follow a standard envelope format:

{
"id": "evt_abc123",
"event": "attendee.created",
"timestamp": "2024-01-15T10:30:00Z",
"project_id": 123,
"data": {
// Event-specific payload
}
}

Payload Examples

attendee.created

{
"id": "evt_abc123",
"event": "attendee.created",
"timestamp": "2024-01-15T10:30:00Z",
"project_id": 123,
"data": {
"attendee_id": 12345,
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@example.com",
"attendee_type_id": 1,
"created_at": "2024-01-15T10:30:00Z"
}
}

access.granted

{
"id": "evt_def456",
"event": "access.granted",
"timestamp": "2024-01-15T14:30:00Z",
"project_id": 123,
"data": {
"attendee_id": 12345,
"access_point_id": 1,
"access_zone_id": 2,
"credential_id": 100,
"granted_at": "2024-01-15T14:30:00Z"
}
}

access.denied

{
"id": "evt_ghi789",
"event": "access.denied",
"timestamp": "2024-01-15T14:31:00Z",
"project_id": 123,
"data": {
"credential_value": "INVALID123",
"access_point_id": 1,
"reason": "invalid_credential",
"denied_at": "2024-01-15T14:31:00Z"
}
}

Signature Verification

All outgoing webhooks include an HMAC signature for verification.

Headers

HeaderDescription
X-GxP-SignatureHMAC-SHA256 signature of the payload
X-GxP-EventEvent type (e.g., attendee.created)
X-GxP-Delivery-IDUnique delivery identifier
X-GxP-TimestampUnix timestamp of the request

Verifying Signatures

// PHP
function verifyWebhook($payload, $signature, $secret) {
$expectedSignature = 'sha256=' . hash_hmac('sha256', $payload, $secret);
return hash_equals($expectedSignature, $signature);
}

$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_GXP_SIGNATURE'];

if (!verifyWebhook($payload, $signature, $webhookSecret)) {
http_response_code(401);
exit('Invalid signature');
}

$event = json_decode($payload, true);
// Process event...
// Node.js
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
const expectedSignature = 'sha256=' +
crypto.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}

app.post('/webhooks/gxp', (req, res) => {
const payload = JSON.stringify(req.body);
const signature = req.headers['x-gxp-signature'];

if (!verifyWebhook(payload, signature, webhookSecret)) {
return res.status(401).send('Invalid signature');
}

// Process event...
res.status(200).send('OK');
});

Retry Policy

If your endpoint fails to respond, GxP will retry:

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours

After 5 failed attempts, the delivery is marked as failed.

Success Criteria

A delivery is considered successful when:

  • HTTP status code is 2xx
  • Response is received within 30 seconds

Idempotency

Use the X-GxP-Delivery-ID header to handle duplicate deliveries:

const deliveryId = req.headers['x-gxp-delivery-id'];

// Check if already processed
if (await isDeliveryProcessed(deliveryId)) {
return res.status(200).send('Already processed');
}

// Process and mark as processed
await processWebhook(req.body);
await markDeliveryProcessed(deliveryId);

Filtering Events

Subscribe to specific event subtypes:

{
"url": "https://your-server.com/webhooks/gxp",
"events": [
"attendee.created",
"access.granted"
],
"filters": {
"attendee_type_id": [1, 2],
"access_zone_id": [5]
}
}

Debugging Webhooks

View Delivery History

In the dashboard:

  1. Navigate to Project Settings > Webhooks
  2. Select your webhook subscription
  3. Click View Deliveries

Delivery Log Entry

{
"id": "del_abc123",
"event_id": "evt_abc123",
"event_type": "attendee.created",
"url": "https://your-server.com/webhooks/gxp",
"status": "delivered",
"response_code": 200,
"response_time_ms": 150,
"attempts": 1,
"delivered_at": "2024-01-15T10:30:05Z"
}

Testing Your Endpoint

Use the webhook testing tool in the dashboard:

  1. Navigate to Project Settings > Webhooks
  2. Select your webhook subscription
  3. Click Test Webhook
  4. Choose an event type to send

Best Practices

  1. Respond quickly: Return 200 OK as soon as possible, process async
  2. Verify signatures: Always validate the HMAC signature
  3. Handle duplicates: Use delivery IDs for idempotency
  4. Log everything: Keep records of all received webhooks
  5. Monitor failures: Set up alerts for failed deliveries
  6. Use HTTPS: Always use secure endpoints
  7. Handle retries gracefully: Your endpoint may receive the same event multiple times

Error Handling

Common Issues

IssueSolution
TimeoutProcess events asynchronously
Invalid signatureCheck your webhook secret
SSL certificate errorEnsure valid SSL certificate
Connection refusedCheck firewall and server status

Disabling Webhooks

Webhooks are automatically disabled after:

  • 100 consecutive failures
  • 7 days of failures

Re-enable in the dashboard after fixing the issue.