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.
| Event | Triggers When |
|---|---|
| domain.created | A new custom domain is successfully added to your account. |
| domain.deleted | An existing custom domain is deleted from your account. |
| certificate.issued | An SSL certificate is successfully issued for a domain. |
| renewal.succeeded | A scheduled, automated certificate renewal is successful. |
| renewal.failed | An automated certificate renewal fails. |
| certificate.expired | An active certificate has reached its expiration date. |
| api_key.created | A 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:
- Retrieve the
X-VanityCert-Signatureheader and theX-VanityCert-Eventheader. - Take the raw JSON body of the webhook request.
- Compute the HMAC SHA-256 hash of the JSON body, using your webhook secret as the key.
- Compare your computed hash with the hash provided in the
X-VanityCert-Signatureheader. - 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
}
}