Skip to main content

Webhooks

Webhooks are automated, real-time notifications sent from VanityCert to an endpoint (a URL) that you define. They are a powerful way to integrate VanityCert into your own applications, allowing you to react instantly to events like certificate failures, domain creations, and more, without needing to constantly poll our API.

Webhook Events Summary

This table lists all the events you can subscribe to and when they are triggered. Click on an event name to view its detailed payload structure.

EventTriggers When
domain.createdA new custom domain is successfully added to your account.
domain.deletedAn existing custom domain is deleted from your account.
certificate.issuedAn SSL certificate is successfully issued for a domain.
renewal.succeededA scheduled, automated certificate renewal is successful.
renewal.failedAn automated certificate renewal fails.
certificate.expiredAn active certificate has reached its expiration date.
api_key.createdA new API key is generated in your developer portal.

Security

Every webhook request from VanityCert is sent with a signature header, which you can use to verify that the request originated from us. This protects your endpoint from malicious requests.

Verifying the Payload

We sign every payload using a secret key you can optionally define for your webhook. The signature is provided in the X-VanityCert-Signature header of the request, prefixed with the hash algorithm used (e.g., sha256=...).

The payload verification process is as follows:

  1. Retrieve the X-VanityCert-Signature header and the X-VanityCert-Event header.
  2. Take the raw JSON body of the webhook request.
  3. Compute the HMAC SHA-256 hash of the JSON body, using your webhook secret as the key.
  4. Compare your computed hash with the hash provided in the X-VanityCert-Signature header.
  5. If they match, you can be sure the request is from VanityCert.

Below is a conceptual example in pseudo-code:

secret = "your_webhook_secret"
signature_header = request.headers["X-VanityCert-Signature"] // e.g., "sha256=..."
signature_parts = signature_header.split("=")
algorithm = signature_parts[0]
given_signature = signature_parts[1]
payload = request.body

// Compute your own hash
computed_signature = hmac_sha256(payload, secret)

if computed_signature == given_signature:
// Signature is valid
else:
// Signature is invalid. Reject the request.

Event Details and Payloads

Event: domain.created

Trigger: Fired immediately after a new custom domain is added and successfully configured in VanityCert.

{
"event": "domain.created",
"timestamp": "2025-08-01T13:23:00Z",
"data": {
"domain_id": 12345,
"domain_name": "app.theircompany.com",
"status": "pending_issuance",
"added_by_user_id": 101,
"cname_target": "customer-abcde.vanitycert-cdn.com"
}
}

Event: domain.deleted

Trigger: Fired when a custom domain is deleted from an account, either manually or via the API.

{
"event": "domain.deleted",
"timestamp": "2025-08-01T13:23:00Z",
"data": {
"domain_id": 12345,
"domain_name": "app.theircompany.com",
"deleted_by_user_id": 101
}
}

Event: certificate.issued

Trigger: Fired once an SSL certificate is successfully issued for a domain.

{
"event": "certificate.issued",
"timestamp": "2025-08-01T13:23:00Z",
"data": {
"domain_id": 12345,
"domain_name": "app.theircompany.com",
"certificate_expiry_date": "2025-10-30T13:23:00Z",
"issuer": "Let's Encrypt"
}
}

Event: renewal.succeeded

Trigger: Fired after a successful automated renewal of an existing certificate.

{
"event": "renewal.succeeded",
"timestamp": "2025-08-01T13:23:00Z",
"data": {
"domain_id": 12345,
"domain_name": "app.theircompany.com",
"certificate_expiry_date": "2025-10-30T13:23:00Z"
}
}

Event: renewal.failed

Trigger: Fired when a scheduled, automated certificate renewal fails.

{
"event": "renewal.failed",
"timestamp": "2025-08-01T13:23:00Z",
"data": {
"domain_id": 12345,
"domain_name": "app.theircompany.com",
"failure_reason": "DNS validation failed: CNAME record not found."
}
}

Event: certificate.expired

Trigger: Fired when an SSL certificate has officially expired, and the system has failed to renew it.

{
"event": "certificate.expired",
"timestamp": "2025-08-01T13:23:00Z",
"data": {
"domain_id": 12345,
"domain_name": "app.theircompany.com"
}
}

Event: api_key.created

Trigger: Fired when a new API key is generated in the developer portal.

{
"event": "api_key.created",
"timestamp": "2025-08-01T13:23:00Z",
"data": {
"key_id": "vc_pk_abc12345",
"key_name": "Main App Integration",
"organization_id": 6789
}
}