```html

Diagnosing and Staging a Google Apps Script Deployment Outage: Access Control and Project Recovery

On 2026-06-02, a critical booking funnel failure took down deposit collection across 11 event pages. This post details the diagnostic approach, root cause identification, and the staged fix—including why the outage happened and how to prevent it in the future.

What Happened: The Symptom

All "Reserve" widget endpoints across the sailjada and queenofsandiego domains returned either 403 Forbidden or 404 Not Found responses. This silently broke the entire deposit ingestion pipeline:

  • 10 event pages calling endpoint https://script.google.com/macros/s/.../44Pme8wCA/exec received 403
  • 1 worship page calling a separate endpoint received 404
  • No client-side errors logged—the requests failed at the server level
  • Impact: every inbound booking and deposit collection attempt was silently failing

Diagnostic Approach

Step 1: Verify HTTP Status Directly

Rather than relying on client reports, we checked both endpoints live:

# Check the primary booking endpoint
curl -I https://script.google.com/macros/s/AKfycbz...44Pme8wCA/exec

# Returns: HTTP 403 Forbidden

# Check the worship endpoint
curl -I https://script.google.com/macros/s/AKfycbz...AFsLWaO3/exec

# Returns: HTTP 404 Not Found

Step 2: Search for Project Metadata

We needed to connect the endpoint URLs to the actual Google Apps Script project. The workflow:

  • Searched /Users/cb/Library/Mobile Documents/com~apple~CloudDocs/jada-ops/ for any reference to the Apps Script project name or ID
  • Checked source repositories for clasp config files (`.clasp.json`) to identify which project matched
  • Located the project ID: 1dDpSK8JZda7XUpKIGlyyAX19KLL4JqFjYVtpcunB5ZE3-NMX_9v0lQJ5
  • Confirmed the display name by reading appsscript.json in the project root

Step 3: Identify Root Cause

The 403 on the primary endpoint indicated access control misconfiguration. The 404 on the worship endpoint suggested a deleted or incorrectly configured deployment. Both pointed to the same underlying issue: the deployment's access settings were not set to "Anyone" (anonymous public access).

This likely occurred after:

  • A manual redeploy or project update without resetting access controls
  • A permissions audit that tightened access without updating the deployment configuration
  • Or a project structure change where the deployment slot was recreated but not properly configured

Technical Details: Why This Matters

Google Apps Script deployments have two independent configuration layers:

  • Project ID (1dDpSK8JZda7XUpKIGlyyAX19KLL4JqFjYVtpcunB5ZE3-NMX_9v0lQJ5): identifies the source code
  • Deployment ID (the suffix in the /exec URL, e.g., 44Pme8wCA): points to a specific published version with its own access rules

A common mistake: confusing the project ID with the deployment ID. Knowing the project ID doesn't fix the outage—you must configure the deployment itself.

The Staged Fix

The fix requires exactly one action in the Google Apps Script console:

1. Navigate to script.google.com
2. Open project 1dDpSK8JZda7XUpKIGlyyAX19KLL4JqFjYVtpcunB5ZE3-NMX_9v0lQJ5
3. Go to Deploy → Manage deployments
4. For the active deployment:
   - Set "Who has access" to "Anyone"
   - Set "Execute as" to your account (the Apps Script owner)
   - Click Deploy

Why "Anyone" and "Execute as Me"?

  • Who has access = Anyone: allows unauthenticated calls from the public website widgets
  • Execute as = [Service Account]: the Apps Script runs with the owner's permissions, not the caller's, ensuring it can access required Google Sheets and write deposits to the backend

This configuration is intentional—the booking widget is genuinely public-facing and must accept anonymous requests from event pages.

Infrastructure Context

The Apps Script project integrates with:

  • Google Sheets backend: source of truth for bookings and deposits (not detailed in this post)
  • Frontend domains: sailjada.com and queenofsandiego.com, where the Reserve widget HTML is embedded
  • Widget delivery: the /exec endpoint serves JSON responses that populate booking forms across 11 event pages

No CloudFront, S3, or Route53 changes were needed for this fix—it's purely a Google Apps Script deployment access control issue.

Key Decisions and Rationale

Why diagnose at the HTTP level first? It isolates whether the problem is in your code, your client-side integration, or the deployment itself. A 403 from Google's servers is unambiguous.

Why not just redeploy the code? Redeploying the code (via clasp push && clasp deploy) creates a new deployment slot with fresh settings. That's overkill and risks changing the deployment URL, which would require updating all 11 event pages. Fixing the access control on the existing deployment is zero-risk and instant.

Why document the project ID separately? In a multi-project environment (e.g., staging vs. production Apps Scripts), the project ID is your source of truth for finding the right project. Deployment IDs can change; project IDs don't.

What's Next

Immediate: Apply the staged fix (flip access to "Anyone") and verify both endpoints return 200 with valid JSON.

Short-term: Add monitoring to both /exec endpoints to catch future 403 or 404 responses before they impact bookings. A simple CloudWatch or external HTTP check every 5 minutes would suffice.

Long-term: Document the deployment access configuration in your runbook so future changes (e.g., updating the Apps Script for a new feature) don't accidentally downgrade permissions.

This outage cost real bookings and deposits. The fix is seconds; the prevention is documentation and monitoring.

```