Skip to content

SPRINT-7 T5-C — Edge webhook URLs + SMS cron decision

Date: 2026-08-30
Status: T5-C COMPLETE. STOP — await Ryan review before T5-D (RadioCheck iOS pointer).
Prerequisite: T5-B Phase 2 PASS (api.last1.app live, public RLS 0-row proof).


Executive summary

Workstream Result
Edge inbound webhooks (Twilio) Repointed hosted → https://api.last1.app/functions/v1/*
last1.id radiocheck revoke webhook Updated → https://api.last1.app/functions/v1/revoke-from-last1
Edge runtime env (TWILIO_*, UNIT_REQUEST_*) Updated + functions container recreated
Monolith webhooks (last1.app/api/*) Confirmed unchanged (T-4 hostname-stable cutover)
Stripe dashboard No edge-hosted endpoint found; monolith last1.app/api/stripe/webhook only
Sovereign pg_cron URL rewrite Done → public api.last1.app/functions/v1/*
Sovereign SMS crons Rewritten but INACTIVE (Option B — hold until T-6)
check-in-proof-events-cron Active on public URL (internal proof path, no SMS)
Hosted pg_cron (rollback net) Still active until T-6 teardown (PAT expired — not queried live)

Scripts: t5-c-update-last1id-webhook.sh, t5-c-update-twilio-webhooks.py, t5-c-update-edge-webhook-env.sh, t5-c-rewrite-crons.sh


1. Webhook inventory

1.1 Edge-hosted (was tcthzakppndkykatoefx.supabase.co/functions/v1/*)

Callback Old URL New URL How updated
Twilio inbound (primary) …/sms-webhook https://api.last1.app/functions/v1/sms-webhook Twilio API — phone +15203532111, messaging service MG9ee6f9096dfebc0263967c1de0ce4316
Twilio check-in reply …/sms-checkin https://api.last1.app/functions/v1/sms-checkin Twilio API — phone +18586660633
last1.id revoke delivery …/revoke-from-last1 https://api.last1.app/functions/v1/revoke-from-last1 Postgres UPDATE on last1id_prod.app_clients (app_id=radiocheck)
Unit request email links LAN/internal https://api.last1.app/functions/v1/unit-request-actions Edge .env (UNIT_REQUEST_ACTION_BASE_URL)
Twilio status callback LAN/internal https://api.last1.app/functions/v1/sms-webhook Edge .env (TWILIO_STATUS_CALLBACK_URL)

Edge stripe-webhook function: deployed and reachable at https://api.last1.app/functions/v1/stripe-webhook (unsigned probe → 400). No Stripe Dashboard endpoint currently registers a *.supabase.co/functions/v1/stripe-webhook URL (Stripe API lists only monolith + other products). RadioCheck subscription events today flow through https://last1.app/api/stripe/webhook (T2-3 rotation, unchanged hostname). No Stripe dashboard action required unless Ryan decides to split RadioCheck Edge billing webhooks later.

1.2 Monolith (last1.app/api/*) — confirm only, not re-touched

Endpoint Expected behavior T5-C probe
POST /api/stripe/webhook Signature gate 400 (unsigned) — R940 monolith via CF
POST /api/webhooks/bundle HMAC gate 401 (unsigned)
POST /api/webhooks/radiocheck-org-access HMAC gate (same class as bundle — not re-probed)

T-4 cutover already routes these hostnames to R940. No URL change.

1.3 Ryan-side dashboard vs API-updatable

Item Owner T5-C action
Twilio phone SMS URLs API (done) t5-c-update-twilio-webhooks.py
Twilio Messaging Service inbound API (done) same
last1.id app_clients.webhook_url DB/API (done) t5-c-update-last1id-webhook.sh
Edge function env URLs VM script (done) t5-c-update-edge-webhook-env.sh
Stripe monolith webhook Already correct No change
Stripe Edge stripe-webhook endpoint N/A today No dashboard row found
Deactivate hosted pg_cron SMS jobs Ryan — Supabase Dashboard Deferred to T-6 (see §3)
Twilio Studio / other numbers Ryan audit API scan found 2 numbers + 1 messaging service only

2. Public webhook smoke (through CF)

Log: /tmp/last1app-gate-b/t5c-webhook-smoke-20260830T232703Z.txt

POST HTTP CF path Notes
/functions/v1/sms-webhook (form, no sig) 403 cf-ray + server: cloudflare Twilio signature gate ✓
/functions/v1/sms-checkin (JSON anon) 200 CF ✓ Reachable (check-in TwiML path)
/functions/v1/stripe-webhook (JSON anon) 400 CF ✓ Missing stripe-signature ✓
/functions/v1/revoke-from-last1 (JSON anon) 401 CF ✓ HMAC gate ✓

3. SMS cron decision — Option B applied (pending Ryan confirm)

Double-fire risk

Hosted Supabase (tcthzakppndkykatoefx) pg_cron jobs sms-checkin-cron and org-sms-cron remain active on hosted URLs until T-6 teardown (documented T2-0; live query blocked — Management API PAT returned Unauthorized).

If both hosted and sovereign SMS crons were active at 14:00 UTC, users would double-text.

Recommendation (Option B)

Option Sovereign SMS crons Hosted SMS crons Risk
(a) Activate now active=true Must deactivate hosted NOW Double-fire if hosted not disabled
(b) Hold until T-6 ✓ applied active=false (URLs rewritten) Keep firing (dormant app OK) No sovereign SMS until T-6 activation

Applied state on VM 103 (last1app-db):

jobname schedule active URL target
sms-checkin-cron 0 14 * * * false https://api.last1.app/functions/v1/sms-cron (+ cron Bearer)
org-sms-cron 0 14 * * * false https://api.last1.app/functions/v1/org-sms-cron (+ cron Bearer)
check-in-proof-events-cron */5 * * * * true https://api.last1.app/functions/v1/check-in-proof-events (+ cron Bearer)

Cron rewrite log: /tmp/last1app-gate-b/t5c-cron-rewrite-20260830T232649Z.log

Ryan decision needed: Confirm Option B (hold sovereign SMS until T-6 + hosted teardown), or reply Option A to activate sovereign SMS now and authorize hosted cron deactivation in Supabase Dashboard.


4. Backups

Artifact Path
last1.id webhook pre-image /tmp/last1app-gate-b/t5c-radiocheck-webhook-pre-20260830T232615Z.csv
Twilio update report /tmp/last1app-gate-b/t5c-twilio-webhook-update.json
Edge .env pre-T5-C /opt/supabase/docker/.env.pre-t5c-webhook-* on VM 103

Rollback last1.id revoke URL:

UPDATE app_clients
SET webhook_url = 'https://tcthzakppndkykatoefx.supabase.co/functions/v1/revoke-from-last1'
WHERE app_id = 'radiocheck';

5. Deferred (T5-D / T-6)

Item Gate
RadioCheck iOS EXPO_PUBLIC_SUPABASE_URL → https://api.last1.app T5-D
Activate sovereign SMS crons + disable hosted SMS crons T-6 (or Ryan Option A now)
Hosted Supabase teardown T-6
Optional: dedicated Stripe endpoint for Edge stripe-webhook Product decision

6. Ryan review checklist

  1. Accept Twilio inbound URLs now hit api.last1.app through CF (live inbound SMS path on sovereign).
  2. Accept last1.id revoke deliveries now target sovereign revoke-from-last1 (HMAC unchanged).
  3. Confirm Option B for SMS crons, or authorize Option A (+ hosted cron disable).
  4. Acknowledge monolith Stripe/webhooks unchanged at last1.app/api/*.

STOP. No T5-D iOS work until Ryan replies.