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

  1. Subscribe: You create a webhook subscription for a specific calendar using the Calendar Subscriptions API.
  2. Receive: When changes occur in the calendar, OneCal Unified sends a POST request to your configured endpoint.
  3. Verify: Your endpoint verifies the webhook signature using the endpoint secret.
  4. 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 TypeDescription
calendar.event.changedA calendar event was created, updated, or deleted.
calendar.event.unknownAn unknown change occurred in the calendar.

End User Account Events

Event TypeDescription
enduseraccount.createdA new End User Account was created.
enduseraccount.updatedAn End User Account was updated.
enduseraccount.deletedAn End User Account was deleted.
enduseraccount.credential.updatedAn 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


GET/v1/calendarSubscriptions/:endUserAccountId

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

GET
/v1/calendarSubscriptions/:endUserAccountId
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
}


POST/v1/calendarSubscriptions/:endUserAccountId

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

POST
/v1/calendarSubscriptions/:endUserAccountId
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/v1/calendarSubscriptions/:endUserAccountId

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

DELETE
/v1/calendarSubscriptions/:endUserAccountId
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"
}

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:

HeaderDescription
svix-idUnique identifier for this webhook message.
svix-timestampTimestamp when the webhook was sent.
svix-signatureSignature 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

  1. Always verify signatures: Never trust incoming webhooks without verifying their signatures.
  2. Respond quickly: Return a 2xx response within a few seconds to acknowledge receipt. Process the webhook asynchronously if needed.
  3. Handle duplicates: Webhooks may be delivered more than once. Use the svix-id header to deduplicate.
  4. Use HTTPS: Always use HTTPS endpoints for webhook URLs to ensure secure delivery.
  5. Implement retry handling: If your endpoint returns an error, Svix will retry the delivery with exponential backoff.

Was this page helpful?