Skill #24 — Integrations (Stripe → HubSpot, 2026)
Written 30 Oct 2026 (bizdev run cd3f1a8c).
What we tested (30 Oct, dry run)
- tools/stripe_events_note.py reads Stripe /v1/events filtered by type (checkout.session.completed, .async_payment_succeeded, .expired; 5 each) through the connected Stripe app and builds one HubSpot note for the Cedwyn growth deal ([record]). Dry run by default; --live posts and moves a cursor (stripe-events-cursor.json).
- Result: 0 completed sessions; 3 expired (unpaid) sessions expired today 13:36Z and 14:14Z: two £4.99 e-book links and one £25.00 voucher link (plink_1USk6M…, success_url /wales/vouchers/thank-you). Stripe expires an unpaid Checkout Session after 24 h, so these were opened about 13:36Z and 14:14Z on 29 Oct.
Lessons
- connected_apps returns only the first 8 KB of a response, and one Stripe event is ~2.5 KB: filter by
typeand keeplimit≤ 5, then parse leniently (fields deep in the object can be cut off: the first expired row came back without its payment_link). - Expired sessions are the only abandoned-checkout signal we have, but some are our own: every GET of a buy.stripe.com link creates a session (CONVENTIONS 29 Oct). Before reading an expired session as a lost buyer, check the run logs for a link check at that minute (24 h earlier).
- A real sale shows as checkout.session.completed with payment_status=paid; the root tells the project lead at once; buyers_sync.py then records the buyer so we never sell the same book twice.
- Webhooks would be instant, but they need an endpoint and a signing secret on the Worker (an owner step: the STRIPE_KEY secret is still unset). Polling events every run is the zero-setup route until then.
How we apply it
- Each execute run:
python3 tools/stripe_events_note.py(dry run) after kpi_snapshot; add--liveonly when there is a completed session or ≥3 new expired ones, so the deal timeline is not spammed.
Raw Markdown: 24.md · version and changes: changelog · machine index: agents.json