Connect Stripe
The restricted key HeyCMO needs, what each permission is for, and the webhook it sets up for you.
HeyCMO is an invitation-only, $0 operational Alpha for Stripe and Resend recovery emails. A person approves every message before it is sent. The guides also describe implementation capabilities outside the Alpha. Their presence here does not make them available in the pilot. Start with the Alpha checklist. Help: alpha@heycmo.ai.
Setup → Connect Stripe and Email sending, or Settings → Connections → Stripe and email sending (the same forms). One paste per provider: HeyCMO checks the key with the provider, stores it encrypted (envelope encryption; AWS KMS once the operator turns it on), creates this workspace's webhook through the provider's API and stores the signing secret the provider returns. You never copy a tenant id or build a webhook by hand.
Create a restricted key
Stripe → Developers → API keys → Create restricted key:
| Permission | Why |
|---|---|
| Invoices: Read | required — the dunning loop senses failed payments |
| Webhook Endpoints: Write | lets HeyCMO create its recovered-revenue webhook for you |
| Subscriptions: Read | optional, but without it the dunning loop cannot see that a subscription is paused, cancelled or set to cancel, so it may still email about that subscription's invoice; also the billing loops (churn, trial, expansion) |
| Customers: Read | optional — the billing loops (churn, trial, expansion); Customers: Read also lets HeyCMO email a customer whose card expires before a renewal (pre-dunning) |
| PaymentIntents: Read, Charges: Read | optional — lets a recovery email say why the payment failed (an expired card, a 3D Secure check, insufficient funds) and pick its button; without them the email uses the general copy and the invoice link |
| Customer portal: Write | optional — the recovery email's "Update card in 1 click" opens Stripe's card-update page directly (with Subscriptions: Read, so HeyCMO can check the subscription is charged to the customer's default card, the one that page changes); without it the button opens the invoice, where a new card pays |
Everything else: None. Paste the rk_live_… key → Connect Stripe. A key
Stripe rejects, or one that cannot read invoices, is refused and nothing is
stored. (API: POST /v1/connect/stripe with {"restrictedKey":"rk_live_…"}.)
Connecting again is safe: the existing webhook is reused, not duplicated. If Stripe ever reports failed signature checks on the HeyCMO endpoint, tick Recreate the webhook and connect again.
Webhooks — usually nothing to do
Connecting Stripe and your email provider created both webhooks: the
Stripe one feeds recovered-revenue
attribution (invoice.paid, invoice.payment_succeeded), drafts the first
recovery email as soon as a payment fails (invoice.payment_failed), the
card-expiry email before a renewal (invoice.upcoming, and
customer.source.expiring for a saved card that expires at the end of the
month), sees new trials and subscriptions for the conversions you send back
to your ad platforms (customer.subscription.created), and withdraws a
waiting recovery draft when the invoice is paid, the subscription is paused
or cancelled, or the invoice is written off (invoice.marked_uncollectible,
customer.subscription.paused, customer.subscription.updated,
customer.subscription.deleted); your email provider's one
records delivery events and suppresses bounced and complained recipients.
If you connected Stripe before an event was added to this list, HeyCMO adds
it to the webhook it created in your Stripe account within a day (connecting
again with the same key does it at once). Until Stripe has sent one failed payment, the first email goes with
the next daily run, and the loop's run note says so.
Setup's Connect Stripe and Email sending steps turn green only once
their webhooks are set up, and Setup → Advanced / manual setup shows
your workspace id and both endpoint URLs.
Only if a connect answered "One manual step left" — a Stripe key without
Webhook Endpoints: Write, or a sending-only Resend key — the form shows the
exact endpoint URL and events with copy buttons. Add that endpoint in the
provider (Stripe → Developers → Webhooks → Add endpoint; Resend → Webhooks),
then store the signing secret (whsec_…) it gives you in Setup →
Advanced / manual setup or Settings → Advanced → Integration
secrets → Stripe webhook signing secret / Resend event webhook signing
secret (Postmark and SendGrid have their own fields there for a webhook
added by hand). The URL is also on GET /v1/connect (webhookUrl), and
your workspace id is on Settings → Team & API keys, with a copy button.
Without the email provider's webhook, dunning still runs but bounces and complaints cannot produce suppression. Without the Stripe one, recoveries are not attributed.