Diagnosing and Staging a Critical Deposit-Processing Outage: Apps Script Redeployment Strategy
Executive Summary
During a June 2026 operations session, we identified a silent but total failure in the booking deposit funnel across 11 public event pages. The "Reserve" widget—powered by Google Apps Script endpoints—was returning 403 Forbidden and 404 Not Found responses, causing all inbound deposit attempts to fail silently. This post details the diagnostic approach, infrastructure audit, and staged remediation strategy.
What Was Done
We discovered and mapped a multi-endpoint Apps Script deployment problem affecting revenue directly:
- Primary endpoint (
https://script.google.com/macros/s/.../44Pme8wCA/exec): Returning 403 Forbidden on all event pages - Secondary endpoint (worship charter page): Returning 404 Not Found—deployment likely deleted
- Root cause: Deployment access revoked or redeployed without updating the linked
/execURLs across the page fleet
The fix has been staged but requires a single manual action in the Google console to activate across production.
Technical Diagnostic Approach
Step 1: Endpoint Inventory and HTTP Testing
We systematically tested live HTTP status across both production endpoints:
# Test primary endpoint (used by 10 event pages)
curl -I https://script.google.com/macros/s/[PROJECT_ID]/44Pme8wCA/exec
# Result: 403 Forbidden
# Test secondary endpoint (worship charter)
curl -I https://script.google.com/macros/s/[PROJECT_ID]/AFsLWaO3/exec
# Result: 404 Not Found
The 403/404 split indicated two separate failures: one deployment with revoked access, one completely deleted.
Step 2: Source-of-Truth Mapping
We traced the deployment IDs back to their origins:
- Searched
/Users/cb/Library/Mobile Documents/com~apple~CloudDocs/jada-ops/for any deployment references - Scanned all source repos for
claspconfigs (Clasp stores Apps Script project IDs locally) - Read
appsscript.jsonfiles to confirm project display names and associated metadata - Cross-referenced project ID
1dDpSK8JZda7XUpKIGlyyAX19KLL4JqFjYVtpcunB5ZE3-NMX_9v0lQJ5as the canonical source
This inventory told us: one Apps Script project, two deployment slots, two different /exec URLs embedded across the page fleet.
Step 3: Dry-Run Endpoint Rewrite Testing
Before touching production S3, we simulated the fix by rewriting endpoint URLs locally:
# Dry-run: test endpoint URL substitution logic
# Old endpoint: https://script.google.com/macros/s/[OLD_ID]/exec
# New endpoint: https://script.google.com/macros/s/[NEW_ID]/exec
grep -r "script.google.com/macros" /Users/cb/Documents/repos/sites/ --include="*.html"
# Found 11 occurrences across event pages
This confirmed the blast radius: every public-facing event page would need updating once the new deployment was live.
Infrastructure Details
S3 and CloudFront Architecture
The event pages are hosted as static HTML in S3, fronted by CloudFront for caching and distribution:
- S3 bucket: Stores source HTML files for all event pages (sailjada.com and queenofsandiego.com)
- CloudFront distributions: Multiple distributions (one per domain) cache HTML content with TTL optimized for template changes
- Invalidation strategy: After applying endpoint rewrites to S3, CloudFront cache invalidation is required to force edge nodes to refresh
The outage was invisible to users because:
- The HTML pages themselves load fine (static, cached)
- The JavaScript event handlers on those pages call the Apps Script endpoint
- Silently failing HTTP 403/404 responses mean no error toast, no console log to users—just a non-functional button
Apps Script Project Structure
The project at 1dDpSK8JZda7XUpKIGlyyAX19KLL4JqFjYVtpcunB5ZE3-NMX_9v0lQJ5 contains:
- Google Sheets backend: Append-only deposit log; serves as source-of-truth for all bookings
- doPost() handler: Receives form submissions from the "Reserve" widget; validates, deduplicates, writes to Sheets
- Multiple deployments: Different
/execURLs for different purposes (main event flow vs. worship-specific flow)
Key Decisions and Reasoning
Why This Is a Revenue Stopper
Unlike single-deal blockers (e.g., one charter's pricing), this is a total funnel leak:
- Every inbound reserve attempt across 11 pages is failing silently
- You cannot see the volume of lost deposits because the funnel is dark (403/404 instead of logged attempt + error message)
- Recovery requires: (1) redeployment, (2) endpoint URL inventory, (3) S3 + CloudFront updates, (4) cache invalidation
Why We Staged Before Going Live
The fix involves two atomic steps:
- In Google Apps Script console: Redeploy the project with
Who has access = Anyone,Execute as = Me - Live test: Verify the new
/execURL returns 200 OK - Mass rewrite: Update all 11 HTML files in S3 with the new endpoint URL
- CloudFront invalidation: Clear cached HTML to force browsers to fetch the new endpoint
Staging means testing each step locally and in dry-run mode before touching production data or paying CloudFront invalidation costs.
Deployment ID vs. Execution URL
A common confusion: the project ID (1dDpSK8J...) is permanent, but the deployment ID (the segment in the `/exec` URL) changes when you redeploy. Both must exist and match for the endpoint to return 200.
# Project ID (stable):
1dDpSK8JZda7XUpKIGlyyAX19KLL4JqFjYVtpcunB5ZE3-NMX_9v