Charlie Payment Operations
Reception view for Charlie payment readiness, pending payments, Stripe webhook state and fallback actions.
09/07/2026, 01:34:49
Full paid end-to-end proof before live auto-cancellation
Charlie payment links, scanner, fields/tags and booking checks
Real Stripe checkout event processed by the bridge
Dry-run booking matrix for core Charlie appointment types
All configured services map to the correct Stripe links
Controlled tracked link starter works and cleans up synthetic rows
Single-command controlled payment proof helper is runnable
No broken pending/paid payment request rows
30-minute Supabase CRON scans pending Charlie payments
Fallback GHL workflow contract is valid
GHL Voice AI actions preserve booking context and payment IDs
Stripe account, webhook URL and required events are documented
Booking/payment team notifications can email hello through HighLevel fallback
Optional fallback workflow published in HighLevel
Webhook endpoint API-verified in Stripe
Team Notifications
| Event | Status | Provider | Message / Task |
|---|---|---|---|
| Booking notification | Yes | ghl_email | ibTyYwn5U8f41i6XiASV |
| Payment received notification | Yes | ghl_email | 8yXFKj8F2jZQ82BRGxr1 |
| Cancellation notification | Yes | ghl_email | J4qN5OMLmyrURonYQXDw |
| Recipient | hello@therehabhub.co.uk | ||
| Latest proof | data/discovery/charlie-team-email-ghl-fallback-proof-2026-07-03T09-36-00-412Z.json | ||
Current solution: Charlie tries Resend first, then sends the same team email through HighLevel if Resend fails.
Still worth fixing: Resend/domain sending is still returning 403, so keep the HighLevel fallback live until therehabhub.co.uk or a sending subdomain is verified in Resend.
Go-Live Verdict
| Item | Status |
|---|---|
| Verdict | Not ready |
| Payment-link mode | Not proven |
| Real paid Stripe webhook proven | Not proven |
| Webhook paid events processed | 0 |
| Dynamic checkout ready | Not proven |
| GHL fallback workflow published | Not proven |
| Stripe endpoint API-confirmed | Not proven |
Safe To Use Now
- Manual staff lookup can check Charlie payment rows by exact Cliniko appointment ID when the staff secret is supplied.
Not Safe Yet
- Do not auto-cancel unpaid appointments yet.
- Do not claim exact appointment-paid tracking is fully proven yet.
- Do not rely on the optional GHL fallback workflow until HighLevel shows it published.
Must Do
- Fix failing core readiness gates before using Charlie payment links with patients.
- Run one controlled real paid checkout and confirm Stripe marks the exact Cliniko appointment paid through the webhook.
- Confirm or create the live Stripe webhook endpoint in Stripe Dashboard for the Charlie webhook URL.
Should Do
- Create/publish the GHL fallback workflow `Bridge - Charlie Payment Link Sent`.
- Add a valid live STRIPE_SECRET_KEY when ready for dynamic per-appointment Checkout Sessions.
- Run one controlled Charlie live call: book, send payment link, pay, check Cliniko note, then move/cancel/rebook.
Current Queue
| Metric | Value |
|---|---|
| Pending payments | 3 |
| Overdue payments | 3 |
| Overdue and unreminded | 0 |
| Next pending due | 2026-07-04 22:15:48.762+00 |
| Payment scanner CRON | Active every 30 minutes |
Stripe Webhook
| Metric | Value |
|---|---|
| Total events received | 0 |
| Processed paid events | 0 |
| Failed events | 0 |
| Latest event | None yet |
What To Do
If Charlie has just booked an appointment: the bridge should send the first SMS/email payment link directly. The GHL workflow is fallback only.
If payment still shows pending after 24 hours: the scanner should send/remind and create a team task. Check the pending queue above.
If the patient says they have paid but status is not paid: check Stripe, then use the manual reconciliation route/script with the exact Cliniko appointment ID.
Do not auto-cancel: keep auto-cancellation off until one real Stripe paid webhook has been processed successfully.
Controlled Paid Test
1. Confirm Stripe webhook first: the Stripe Dashboard endpoint must point at https://sthcteshohirdkbrcgat.supabase.co/functions/v1/voice-cliniko/stripe/webhook and listen for checkout.session.completed.
2. Make one real Charlie booking: use a low-risk controlled appointment, then copy the exact Cliniko appointment ID.
3. Run the controlled proof helper: VOICE_SHARED_SECRET=... node scripts/charlie-controlled-paid-checkout-proof.mjs --appointment <cliniko_id> --service podiatry-review. It creates or checks the exact tracked payment link, then watches the same Cliniko appointment until Stripe webhook proof lands.
4. If preparing only: run node scripts/charlie-controlled-paid-checkout-proof.mjs --appointment <cliniko_id> --service podiatry-review --no-watch. The script skips patient messages by default unless --send-messages is supplied deliberately.
5. Pay the sent link: the watcher only passes when the payment row is paid and the matching Stripe webhook audit row is processed.
6. After it passes: run node scripts/charlie-payment-readiness.mjs and node scripts/charlie-go-live-audit.mjs. Only then consider auto-cancellation rules.
Manual Paid Reconciliation
Use this only as a checked fallback: first confirm the payment in Stripe, then mark the exact Cliniko appointment paid. This updates Supabase, GHL, and the Cliniko appointment note.
Best reference: Stripe Checkout Session ID. If that is not available, use Payment Intent ID, Charge ID, or a clear Stripe/manual payment reference.
Audit rule: always include who verified it, e.g. --verified-by "Louise". The Cliniko note will show that the payment was manually reconciled after a staff Stripe check.
Still not live-proof: manual reconciliation is useful for operations, but the system is only fully proven once Stripe itself sends a processed checkout.session.completed webhook.
Live Payment Lookup
Staff-only lookup for checking one Charlie payment request by exact Cliniko appointment ID. The staff secret stays in this browser session and is not stored in this file.
Stripe Setup
| Item | Value |
|---|---|
| Stripe account | Posture Me Perfect acct_1EhnckCHuPvT4biM |
| Dashboard API keys | Open Stripe Dashboard |
| Webhook URL | https://sthcteshohirdkbrcgat.supabase.co/functions/v1/voice-cliniko/stripe/webhook |
| Required event | checkout.session.completed |
| Optional event | checkout.session.async_payment_succeeded |
| Supabase secret | STRIPE_WEBHOOK_SECRET |
Last external step: create or confirm the live Stripe Dashboard webhook endpoint above, then copy its signing secret into Supabase as STRIPE_WEBHOOK_SECRET.
Proof needed: one real Charlie payment link must be paid and a matching checkout.session.completed event must appear as processed below.
GHL Fallback Workflow
| Item | Value |
|---|---|
| Status | Not published |
| Workflow name | Bridge - Charlie Payment Link Sent |
| Trigger | bridge:charlie-payment-required tag added |
| Re-entry | Allow multiple entries |
| Latest API check | data/discovery/the-hub-charlie-payment-workflow-check-2026-07-09T00-33-53-313Z.json (not found, not published) |
Role: fallback only. The bridge already attempts first SMS/email directly and owns the 24-hour scanner/reminder/task.
Build logic: remove bridge:charlie-payment-required, end if bridge_payment_status is not pending, wait 3 minutes, end if bridge:charlie-payment-first-message-sent is present, otherwise send the fallback SMS/email using {{contact.bridge_payment_link}}.
Pass condition: after publishing in HighLevel, run node scripts/check-charlie-payment-workflow.mjs and expect found: true plus published: true.
Do not put 24-hour waits here: the hosted scanner owns that step so we do not duplicate messages.
Useful Commands
| Purpose | Command |
|---|---|
| Full readiness | node scripts/charlie-payment-readiness.mjs |
| Go-live audit | node scripts/charlie-go-live-audit.mjs |
| Stripe contract | node scripts/check-charlie-stripe-webhook-contract.mjs |
| Stripe endpoint check | STRIPE_SECRET_KEY=... node scripts/charlie-stripe-webhook-endpoint-check.mjs --create --store-supabase-secret |
| Pending queue | node scripts/charlie-pending-payment-audit.mjs --clinic the-hub-glasgow --limit 20 |
| Stripe webhook audit | node scripts/charlie-stripe-webhook-audit.mjs --clinic the-hub-glasgow --limit 5 |
| List payment services | node scripts/start-charlie-paid-test.mjs --list-services |
| Inspect a real Charlie call | node scripts/charlie-live-call-inspect.mjs --name "<caller name>" --phone "<caller phone>" --email "<caller email>" |
| Start controlled paid test | node scripts/start-charlie-paid-test.mjs --appointment <cliniko_id> --service podiatry-review |
| Start GBP 1 webhook proof | STRIPE_SECRET_KEY=... node scripts/charlie-one-pound-checkout-proof.mjs --appointment <cliniko_id> --email <test_email> |
| Watch a live paid test (HTTP) | VOICE_SHARED_SECRET=... node scripts/watch-charlie-payment-http.mjs --clinic the-hub-glasgow --appointment <cliniko_id> --timeout-seconds 600 |
| Watch a live paid test (DB) | node scripts/watch-charlie-payment.mjs --clinic the-hub-glasgow --appointment <cliniko_id> --timeout-seconds 600 |
| Manual paid reconciliation | VOICE_SHARED_SECRET=... node scripts/charlie-manual-mark-paid.mjs --appointment <cliniko_id> --reference <stripe_ref> --verified-by "Louise" |
| GHL fallback workflow check | node scripts/check-charlie-payment-workflow.mjs |
Source Proofs
| Check | Latest file |
|---|---|
| goLive | data/discovery/charlie-go-live-audit-2026-07-09T00-34-32-777Z.json |
| readiness | data/discovery/charlie-payment-readiness-2026-07-09T00-34-02-226Z.json |
| pending | data/discovery/charlie-pending-payment-audit-2026-07-08T15-35-15-280Z.json |
| webhook | data/discovery/charlie-stripe-webhook-audit-2026-07-01T09-05-43-957Z.json |
| paymentIntegrity | data/discovery/charlie-payment-integrity-audit-2026-07-09T00-34-28-212Z.json |
| paymentScheduler | data/discovery/charlie-payment-scheduler-check-2026-07-09T00-33-52-391Z.json |
| paymentMatrix | data/discovery/charlie-payment-link-matrix-2026-07-09T00-33-25-379Z.json |
| paidTestStarter | data/discovery/charlie-paid-test-starter-check-2026-07-09T00-33-30-949Z.json |
| workflowContract | data/discovery/charlie-payment-workflow-contract-2026-07-09T00-33-52-804Z.json |
| voiceActionContract | data/discovery/charlie-voice-action-contract-2026-07-09T00-33-52-849Z.json |
| stripeWebhookContract | data/discovery/charlie-stripe-webhook-contract-2026-07-09T00-33-52-894Z.json |
| workflowCheck | data/discovery/the-hub-charlie-payment-workflow-check-2026-07-09T00-33-53-313Z.json |
| endpointCheck | data/discovery/charlie-stripe-webhook-endpoint-check-2026-07-09T00-33-53-409Z.json |
| teamEmailFallback | data/discovery/charlie-team-email-ghl-fallback-proof-2026-07-03T09-36-00-412Z.json |
| paidNotificationFallback | data/discovery/charlie-paid-notification-fallback-proof-2026-07-03T09-33-18-411Z.json |