Webhooks
Webhooks allow you to receive real-time notifications when events occur in your users' calendars. Instead of polling the API for changes, you can configure a webhook endpoint to receive push notifications whenever calendar events are created, updated, or deleted.
How Webhooks Work
- Subscribe: You create a webhook subscription for a specific calendar using the Calendar Subscriptions API.
- Receive: When changes occur in the calendar, OneCal Unified sends a POST request to your configured endpoint.
- Verify: Your endpoint verifies the webhook signature using the endpoint secret.
- Process: Your application processes the notification and fetches the updated calendar data if needed.
Webhook Event Types
OneCal Unified supports the following webhook event types:
Calendar Events
| Event Type | Description |
|---|---|
calendar.event.changed | A calendar event was created, updated, or deleted. |
calendar.event.unknown | An unknown change occurred in the calendar. |
End User Account Events
| Event Type | Description |
|---|---|
enduseraccount.created | A new End User Account was created. |
enduseraccount.updated | An End User Account was updated. |
enduseraccount.deleted | An End User Account was deleted. |
enduseraccount.credential.updated | An End User Account's credentials were updated. |
The Webhook Subscription model
Properties
- Name
webhookSubscriptionId- Type
- string
- Description
Unique identifier for the webhook subscription. Read-Only
- Name
endpointSecret- Type
- string
- Description
Secret key used to verify webhook signatures. Store this securely. Read-Only
List Calendar Subscriptions
This endpoint retrieves a paginated list of all webhook subscriptions for a specific End User Account.
Path parameters
- Name
endUserAccountId- Type
- string
- Description
The unique identifier of the End User Account to retrieve subscriptions for.
Optional query parameters
- Name
pageToken- Type
- string
- Description
Token for pagination to retrieve the next page of results.
- Name
limit- Type
- number
- Description
Maximum number of subscriptions to return per page.
Request
curl -X GET https://api.onecalunified.com/api/v1/calendarSubscriptions/:endUserAccountId \
-H "x-api-key: {apiKey}"
Response
{
"data": [
{
"id": "sub_abc123",
"provider": "GOOGLE",
"url": "https://yourapp.com/webhooks/calendar",
"calendarId": "primary",
"expiration": "2025-01-15T00:00:00.000Z",
"subscriptionId": "subscription_id",
"resourceId": "resource_id",
"endUserAccountId": "user_account_1",
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z"
}
],
"nextPageToken": null
}
Create a Calendar Subscription
Creates a new webhook subscription for calendar events. When events are created, updated, or deleted in the specified calendar, a webhook notification will be sent to the provided URL.
Path parameters
- Name
endUserAccountId- Type
- string
- Description
The unique identifier of the End User Account to create the subscription for.
Request body
- Name
calendarId- Type
- string
- Description
The unique identifier of the Calendar to subscribe to. (Required)
- Name
webhookUrl- Type
- string
- Description
The URL where webhook notifications will be sent. Must be a valid HTTPS URL. (Required)
- Name
rateLimit- Type
- number
- Description
Rate limit for webhook delivery (messages per second). Minimum value is 1. (Optional)
Request
curl https://api.onecalunified.com/api/v1/calendarSubscriptions/:endUserAccountId \
-H "x-api-key: {apiKey}" \
-H "Content-Type: application/json" \
-X POST \
-d '{"calendarId": "primary", "webhookUrl": "https://yourapp.com/webhooks/calendar"}'
Response
{
"webhookSubscriptionId": "subscription_id",
"endpointSecret": "endpoint_secret"
}
Delete a Calendar Subscription
Deletes an existing webhook subscription. Once deleted, you will no longer receive notifications for calendar changes.
Path parameters
- Name
endUserAccountId- Type
- string
- Description
The unique identifier of the End User Account.
Request body
- Name
subscriptionId- Type
- string
- Description
The unique identifier of the webhook subscription to delete. (Required)
Request
curl https://api.onecalunified.com/api/v1/calendarSubscriptions/:endUserAccountId \
-H "x-api-key: {apiKey}" \
-H "Content-Type: application/json" \
-X DELETE \
-d '{"subscriptionId": "sub_123"}'
Response
{
"success": true
}
Webhook Payload
When a calendar event changes, OneCal Unified sends a POST request to your webhook URL with the following payload:
Webhook Payload
{
"eventType": "calendar.event.changed",
"timestamp": "2025-01-08T12:00:00.000Z"
}
The webhook notification indicates that a change occurred, but does not
include the full event details. After receiving a notification, you should
fetch the updated calendar events using the Calendar Events
API with a syncToken to get only the changed events.
Verifying Webhook Signatures
To ensure that webhook notifications are genuinely from OneCal Unified, you should verify the signature of each incoming request using the endpointSecret provided when you created the subscription.
Webhooks are delivered through Svix and include the following headers:
| Header | Description |
|---|---|
svix-id | Unique identifier for this webhook message. |
svix-timestamp | Timestamp when the webhook was sent. |
svix-signature | Signature to verify the webhook authenticity. |
Verification Example
You can use the official Svix library to verify webhook signatures:
Node.js
import { Webhook } from 'svix'
const webhook = new Webhook(endpointSecret)
try {
const payload = webhook.verify(body, {
'svix-id': request.headers['svix-id'],
'svix-timestamp': request.headers['svix-timestamp'],
'svix-signature': request.headers['svix-signature'],
})
// Webhook is valid, process the payload
console.log('Verified webhook:', payload)
} catch (err) {
// Invalid signature
console.error('Invalid webhook signature:', err)
return response.status(400).send('Invalid signature')
}
Python
from svix.webhooks import Webhook
webhook = Webhook(endpoint_secret)
try:
payload = webhook.verify(body, {
'svix-id': request.headers['svix-id'],
'svix-timestamp': request.headers['svix-timestamp'],
'svix-signature': request.headers['svix-signature'],
})
# Webhook is valid, process the payload
print('Verified webhook:', payload)
except Exception as e:
# Invalid signature
print('Invalid webhook signature:', e)
return 'Invalid signature', 400
For more information on webhook verification, see the Svix documentation.
Best Practices
- Always verify signatures: Never trust incoming webhooks without verifying their signatures.
- Respond quickly: Return a 2xx response within a few seconds to acknowledge receipt. Process the webhook asynchronously if needed.
- Handle duplicates: Webhooks may be delivered more than once. Use the
svix-idheader to deduplicate. - Use HTTPS: Always use HTTPS endpoints for webhook URLs to ensure secure delivery.
- Implement retry handling: If your endpoint returns an error, Svix will retry the delivery with exponential backoff.