1. Webhooks
  • Welcome to the Cold Mail Reseller API
  • Get Started
    • Overview
    • Authentication
    • Quick Start
  • Core Concepts
    • Users
    • Domains
    • DNS Management
    • Mailboxes
    • Subscriptions
    • Pre-Warmup
    • Domain Renewal
    • 1+ Year Subscriptions
    • Mailbox Warmup
    • Platform Exports
    • OAuth Exports
    • Sandbox API
  • API Reference
    • Users
      • List Users
      • Get User
      • Create User
      • Update User
      • Delete User
    • Geo
      • List Countries
      • List States
    • Domains
      • Domain Renewal
        • Get Domain Renewal Prices
        • Renew Domains
        • Toggle Domain Auto-Renew
      • Get Domains by User
      • Check Domain Availability
      • Check Single Domain Availability
      • Check Workspace Existence
      • Set Domain Forwarding
      • Set Email Forwarding
      • Delete Domains
    • DNS
      • Get DNS Records
      • Add DNS Records
      • Update DNS Record
      • Update Nameservers
      • Delete DNS Record
    • Mailboxes
      • List Mailboxes
      • Get Mailboxes by User
      • Get Mailbox
      • Get Admin Mailbox Details
      • Update Mailbox Details
      • Delete Mailbox
    • Mailbox Warmup
      • Add Warmup to Mailbox
      • Toggle Warmup
      • Update Warmup Settings
      • Set Warmup Status
      • Disable Warmup
    • Orders
      • Get Order Status
      • Get Order Details
      • Create Order
      • Create Order (JSON)
      • Create Mailbox Order (JSON)
      • Process Order
    • Subscriptions
      • 1+ Year Subscription
        • Recreate Subscription
      • Get Subscriptions
      • Renew Subscriptions
      • Cancel Subscription
      • Toggle Auto-Renewal
    • Exports
      • Platform Exports
        • Get Platform Credentials
        • Add Platform Credential
        • Export Mailboxes to Platform
        • Remove Platform Credential
      • OAuth Exports
        • Perform OAuth
        • Add Client ID to Domains
    • Pre-Warmup
      • Sandbox
        • Get Sandbox Pre-warmup Domains
        • Order Sandbox Pre-warmup
        • Reset Sandbox Pre-warmup
      • Get Pre-warmup Domains
      • Order Pre-warmup
    • Placement Test
      • Create Placement Order
      • Get Placement Reports
  • Resources
    • Errors
    • Rate Limits
    • Pagination
    • Sandbox
    • MCP
  • Webhooks
    • Overview
    • Events
      • Domain Events
      • Mailbox Events
      • Subscription Events
      • Prewarmup Events
      • Mailbox Warmup Events
  • Schemas
    • Error
    • Success
    • MessageResponse
    • User
    • Domain
    • ErrorResponse
    • Mailbox
    • Subscription
    • DnsRecord
    • Error Response
    • Pagination Meta
    • Action Error Response
    • PrewarmupOrderResult
    • OrderCreationResult
  1. Webhooks

Overview

Webhooks notify your system in real-time when events occur on our platform. Instead of polling for updates, your application receives instant notifications when orders are placed, domains are registered, mailboxes are created, and subscriptions change. This allows you to automatically sync data, provision user accounts, and handle failures gracefully.

Event Lifecycles#

Our platform generates webhooks through three distinct lifecycles. Each workflow has success and failure paths.

1. Normal Order Lifecycle (Domain + Mailboxes)#

When a user places an order for both a domain and mailbox accounts:
Step 1: Domain Registration
Your order triggers domain provisioning with the registrar
You receive either domain.order.success or domain.order.failed
Step 2: Mailbox Creation (only if domain succeeds)
If domain succeeded, mailbox accounts are provisioned at Google/Microsoft
You receive either mailbox.order.success or mailbox.order.failed
If domain failed, this step is skipped — no mailbox events are sent
Step 3: Individual Mailbox Ready Notifications
For each mailbox successfully created, you receive mailbox.created
This event fires once per mailbox with full credentials and account details
If you ordered 3 mailboxes and all succeed, you get 3 separate mailbox.created events
Step 4: Future Updates
Whenever a user modifies mailbox details (first name, profile picture, etc.), you receive mailbox.updated
Event sequence example:
Order placed
    ↓
domain.order.success ✓
    ↓
mailbox.order.success ✓
    ↓
mailbox.created (mailbox 1)
mailbox.created (mailbox 2)
mailbox.created (mailbox 3)
    ↓
(Later, if user updates details)
mailbox.updated
If domain fails:
Order placed
    ↓
domain.order.failed ✗
    ↓
(No mailbox events sent)

2. Subscription Lifecycle (Renewal, Cancellation & Updates)#

Mailbox subscriptions follow their own lifecycle separate from domain registration.
Renewal Trigger
When the billing period ends (based on the subscription term)
The system attempts to renew for the next period
You receive subscription.renewing when renewal is initiated
Renewal Outcome
subscription.renewal.success — Subscription successfully renewed
subscription.renewal.failed — Renewal blocked. Usually because the linked domain is in GRACE_PERIOD or EXPIRED
Payment Failure
If the renewal payment fails, you receive subscription.past_due
The subscription enters a 7-day grace window during which recovery is still possible
After 7 days, behaviour depends on autoRenew:
If autoRenew is false — you receive subscription.expired and mailboxes are deactivated
If autoRenew is true — the subscription stays PAST_DUE and retries renewal once the issue is resolved; subscription.expired is not sent
One Plus Year Update
When a subscription crosses the 12-month mark at renewal, the pricing tier updates to $5 per mailbox per month
You receive subscription.updated at this point — fired once, the first time the subscription qualifies
Use this event to notify your customers of the price change or to trigger a subscription recreation if needed
Cancellation
When a user explicitly calls the cancel endpoint, the subscription is immediately cancelled and you receive subscription.cancelled
This fires regardless of whether autoRenew was enabled or disabled at the time of cancellation — it is triggered by the cancellation action itself, not by the billing period ending
If a user simply disables auto-renewal without cancelling, the subscription runs until the period ends, then transitions to PAST_DUE, and if unresolved after 7 days, fires subscription.expired
Event sequence example (successful renewal):
Billing period ends
    ↓
subscription.renewing
    ↓
subscription.renewal.success ✓
    ↓
Next period active
Event sequence example (failed renewal — domain issue):
Billing period ends
    ↓
subscription.renewal.failed ✗
(Reason: domain is in GRACE_PERIOD or EXPIRED)
    ↓
subscription.past_due (26-hour safety net fires)
    ↓
User must renew domain at registrar before subscription can renew
Event sequence example (payment failure):
Billing period ends
    ↓
Subscription payment fails
    ↓
subscription.past_due ✗  (7-day grace begins)
    ↓
7 days pass without recovery
    ↓
autoRenew = false → subscription.expired ✗ → Mailboxes deactivated
autoRenew = true  → Stays PAST_DUE, retries renewal when issue is resolved
Event sequence example (one plus year transition):
Subscription reaches 12 months
    ↓
subscription.renewing
    ↓
subscription.renewal.success ✓
    ↓
subscription.updated  (price updated to $5/mailbox/month)
    ↓
Partner notifies customer — continue or recreate
Event sequence example (explicit cancellation):
Cancel endpoint called (autoRenew: true or false)
    ↓
subscription.cancelled ✗  (fires immediately)
    ↓
Mailboxes deactivated
Event sequence example (auto-renewal disabled, period expires naturally):
autoRenew set to false
    ↓
Billing period ends
    ↓
subscription.past_due ✗  (7-day grace begins)
    ↓
7 days pass without recovery
    ↓
subscription.expired ✗ → Mailboxes deactivated

3. Pre-Warmed Mailboxes Lifecycle#

Pre-warmed mailboxes are a specialized product — accounts that are pre-created and "warmed up" to improve deliverability.
Order Trigger
User orders pre-warmed mailbox accounts
Assignment Processing
The system allocates from an existing pool or creates new accounts from scratch
Assignment Outcome
prewarmup.order.success — Accounts assigned immediately with full credentials
prewarmup.order.failed — Assignment failed (no pool available, insufficient wallet balance, or domain restrictions)
Important: A single order may include multiple domains. Some domains can succeed while others fail, resulting in both prewarmup.order.success and prewarmup.order.failed being triggered for the same order. Check the domain field in each event to identify which domains succeeded or failed.
Event sequence example:
Pre-warmup order placed
    ↓
prewarmup.order.success ✓
    ↓
Mailboxes assigned and ready to use
(User receives credentials immediately)
Event sequence example (with multiple domains):
Order placed for domain-a.com + domain-b.com
    ↓
prewarmup.order.success (domain-a.com) ✓
prewarmup.order.failed (domain-b.com) ✗
    ↓
domain-a.com mailboxes available, domain-b.com assignment failed

Getting Started#

Step 1: Create a webhook endpoint#

Create a POST endpoint on your server that accepts webhook requests:
POST https://your-domain.com/webhooks
The endpoint should:
Accept JSON payloads
Verify the request signature
Respond with 200 OK to acknowledge receipt
Handle asynchronously for long-running operations

Step 2: Subscribe to events#

In the admin dashboard:
1.
Go to Settings → Webhooks
2.
Enter your webhook URL
3.
Select which events you want to receive
4.
Copy your API key (used for signature verification)

Step 3: Verify signatures#

Every webhook request includes two security headers:
cmr-x-signature — HMAC-SHA256 signature of the payload
cmr-x-timestamp — Unix timestamp when the request was sent
Verify both before trusting the webhook:
JavaScript example:

Step 4: Implement idempotency#

Webhooks may be retried if your endpoint doesn't respond with 200 OK. Always store the eventId and skip duplicate processing:
Example:

Webhook Structure#

All webhooks follow the same structure:
{
  "event": "domain.order.success",
  "eventId": "6SSHBXWR3N4JEKGRQSG3KW3D76N6",
  "data": {
    "userId": "PWM7Y25RYZ450YNM8K8FX9GK5AHX",
    "userEmail": "johndoe@company.com",
    "orderId": "NQ682GAVFTMYC2H6C87PPKPG5WXV",
    ...event-specific fields...
  }
}
Fields:
event — Type of event (e.g., domain.order.success)
eventId — Unique identifier for this webhook event (use for deduplication)
data — Event-specific payload with details

Event Reference#

EventLifecycleTriggered whenRetry?
domain.order.successNormal orderDomain successfully registeredNo
domain.order.failedNormal orderDomain registration failedNo
mailbox.order.successNormal orderMailbox provisioning succeededNo
mailbox.order.failedNormal orderMailbox provisioning failedNo
mailbox.createdNormal orderIndividual mailbox is readyNo
mailbox.updatedNormal orderUser updates mailbox detailsNo
subscription.renewingSubscriptionRenewal initiated, payment in progressNo
subscription.renewal.successSubscriptionSubscription renewed successfullyNo
subscription.renewal.failedSubscriptionRenewal blocked by domain statusNo
subscription.past_dueSubscriptionPayment failed or period ended without renewalNo
subscription.expiredSubscription7-day grace period ended with autoRenew: false, mailboxes deactivatedNo
subscription.cancelledSubscriptionCancel endpoint explicitly called by user or partnerNo
subscription.updatedSubscriptionSubscription crosses 12-month mark — updates to $5/mailbox/monthNo
prewarmup.order.successPre-warmupPre-warmed accounts assignedNo
prewarmup.order.failedPre-warmupPre-warmup assignment failedNo

Best Practices#

1. Respond quickly#

Respond with 200 OK immediately after receiving the webhook. Process asynchronously in the background:

2. Store the eventId#

Always persist eventId in your database to prevent duplicate processing:

3. Log everything#

Log all incoming webhooks with timestamps and outcomes for debugging:

4. Handle retries gracefully#

We retry failed webhooks up to 3 times. The same eventId may arrive multiple times. Your idempotency check prevents duplicate processing automatically.

5. Set appropriate timeouts#

Your endpoint must respond within 60 seconds. If processing will take longer, queue it:

6. Validate data, don't assume#

Always validate that expected fields exist in the payload:

Security & Reliability#

Signature Verification#

Every webhook is cryptographically signed using HMAC-SHA256. The signature is included in the cmr-x-signature header. Always verify this before processing.
Why: This proves the webhook came from us and wasn't tampered with.

Replay Protection#

The cmr-x-timestamp header contains the Unix timestamp when we sent the webhook. Reject any request older than 5 minutes.
Why: This prevents attackers from replaying old webhooks.

Retry Policy#

If your endpoint returns a non-2xx response, we automatically retry:
Attempt 1: Immediate
Attempt 2: After 30 seconds
Attempt 3: After 5 minutes
After 3 attempts, the webhook is marked failed. You can retry manually from the dashboard.

Rate Limiting#

We send webhooks at a controlled rate. No rate limits are enforced on your end, but webhook delivery is throttled to prevent overwhelming your service.

Common Issues & Troubleshooting#

Not receiving webhooks?#

Check 1: Is your endpoint publicly accessible?
Check 2: Verify signature verification isn't rejecting valid webhooks
Temporarily log the computed signature vs. received signature
Ensure you're using the correct API key
Check 3: Check the webhook logs in admin dashboard
Look for failed delivery attempts
Check error messages

Receiving duplicate events?#

This is expected. Both success and failure scenarios can produce duplicates due to retries. Always implement idempotency checks using eventId.

Next Steps#

Learn the details of each event type:
Domain Events
domain.order.* and domain.renewal.*
Mailbox Events
mailbox.order.*, mailbox.created, mailbox.updated
Subscription Events
subscription.renewing, subscription.renewal.*, subscription.past_due, subscription.expired, subscription.updated, and subscription.cancelled
Pre-Warmed Mailboxes
prewarmup.order.*
Modified at 2026-08-05 16:12:50
Previous
MCP
Next
Domain Events
Built with