domain_purchase.renewal_failed
Fires when a renewal attempt fails. Domain may still expire.
Fires when a renewal attempt failed — either the Stripe charge declined, or the registrar refused after we'd charged (in which case we automatically refunded).
If this fires within the renewal window (30 days before expiry) and
isn't resolved, the domain will expire on its expiresAt date.
Payload
{
"id": "<event-id>",
"type": "domain_purchase.renewal_failed",
"createdAt": "2027-04-17T15:42:11.000Z",
"data": {
"purchase": { /* unchanged purchase row */ },
"error": "Payment failed: Your card was declined."
}
}
| Field | Notes |
|---|---|
data.purchase | The purchase row, unchanged (the renewal didn't happen). |
data.error | Why it failed. Plain text, safe to surface to your support tooling. |
Common failure modes
| Error contains | What to do |
|---|---|
Your card was declined | Acme's saved Stripe card needs updating. Email Acme. |
Insufficient funds (in Namecheap response) | Domainee's Namecheap balance is low. Internal issue — top up. |
domain is locked | Rare. The domain is registrar-locked in a way that prevents renewal. Contact support. |
Use it for
- Email Acme: "Your card was declined, the next renewal won't go through"
- Email the end-user: "Your domain janesbakery.com will expire on X. Update your payment method"
- Mark the workspace in your CRM for billing follow-up
- Disable any features tied to a soon-to-expire custom domain
Auto-retry
The worker doesn't retry automatically — once a renewal_failed fires,
nothing else happens until either Acme manually calls
POST /:id/renew or the
domain expires. Build your own retry logic if you need it.