Vercel Protection Bypass
Audience: Henry (or any team Owner with Vercel dashboard access) Time required: < 5 minutes
Symptom
Inngest Cloud cannot sync against a Vercel deployment that sits behind deployment protection, or you want browser access to preview deployments without an SSO login. Provisioning the bypass secret requires the Vercel dashboard — it cannot be done from this environment.
Diagnosis
1. Why a human is needed
The Vercel API token available to automation in
this environment returns 403 forbidden on the bypass-secret endpoint
(PATCH /v1/projects/{id}/protection-bypass) and on two related
account-level endpoints (GET /v5/user/tokens, GET /v1/integrations/configurations), while every other project/env
read-write call on the same token succeeds. This is a token-scope
restriction, not a role or plan limitation — confirmed Owner role, Pro
team plan. Only the Vercel dashboard (or a differently-scoped token) can
complete this step.
2. Check whether you need this at all
Use the custom domain. https://launch.lynkr.cc/api/inngest is the only
sync URL that works.
ssoProtection.deploymentType is all_except_custom_domains, and only a
custom domain is exempt. The project's assigned .vercel.app domain is
NOT — it is gated like any hash URL.
Measured 2026-08-14:
| URL | Result |
|---|---|
GET https://launch.lynkr.cc/api/health | 200 |
PUT https://launch.lynkr.cc/api/inngest | 200 {"message":"Successfully registered","modified":true} |
GET https://launcpadv2-scaled.vercel.app/api/inngest | 302 → vercel.com/sso-api?... |
GET https://launcpadv2-scaled.vercel.app/ | 302 → vercel.com/sso-api?... |
GET https://creative-ingest.vercel.app | 307 → scaled-launchpad-v2.vercel.app |
APP_BASE_URL is already https://launch.lynkr.cc, and
src/app/api/inngest/route.ts pins serveHost to it, so a correctly
registered app advertises the custom domain regardless of which host served
the registration request.
Practical implication: for day-to-day operation the bypass secret below is
not required, provided Inngest Cloud syncs against launch.lynkr.cc.
Provision it only if you additionally want ordinary browser access to preview
deployments without an SSO login, or as defence-in-depth in case
ssoProtection.deploymentType is ever tightened to all.
An earlier version of this runbook stated that
https://launcpadv2-scaled.vercel.app/api/inngest was "reachable from the
public internet without any bypass secret", inferring that the project's
assigned .vercel.app domain counted as a custom domain for the purposes of
all_except_custom_domains. That was wrong — it does not, and the host now
returns a 302 to the Vercel SSO gate. Anything relying on that claim
(notably an Inngest sync URL pointed at the .vercel.app host) is broken.
The same revision reported a blocking Inngest error — The function 'Write ClickUp Custom Field' has higher concurrency limits (8) than your plan limit of 5. That is resolved. Every function in src/inngest/* now declares
concurrency: 5 or lower (clickup-functions.ts:34, creative-check.ts:49,
functions.ts:55, marketing-functions.ts:933), and the PUT above
registers cleanly.
Fix
Steps to generate and wire the bypass secret
-
Open the project settings. Go to:
https://vercel.com/scaled/launcpadv2/settings/deployment-protection(Dashboard path: scaled team → launcpadv2 project — note the typo in the project slug; the GitHub repo iscreative-ingestbut the Vercel project islauncpadv2— → Settings tab → Deployment Protection in the left sidebar.) -
Find "Protection Bypass for Automation." Scroll to the section titled Protection Bypass for Automation (below the Vercel Authentication / Password Protection / Trusted IPs sections).
-
Generate the secret. Click Add Bypass Rule (or Generate Secret — label varies slightly by dashboard version). Optionally add a note, e.g.
Inngest Cloud webhook delivery. Vercel generates and displays a secret value once — copy it now. -
Store it as a Vercel env var. Go to Settings → Environment Variables (same project). Click Add New:
- Name:
INNGEST_SERVE_ORIGIN_BYPASS_SECRET - Value: the secret copied in step 3
- Environments: check Production and Preview (leave Development unchecked unless local dev also needs it) Click Save.
Note: Vercel also automatically exposes the current bypass secret to every deployment as the system env var
VERCEL_AUTOMATION_BYPASS_SECRET— you don't need to reference it in code either way, since Vercel intercepts the header/query param before Next.js routing runs. - Name:
-
Redeploy so the new env var is baked into the build. Dashboard → Deployments tab → click the ⋯ menu on the latest Production deployment → Redeploy. (Not strictly required for the bypass secret itself to work — Vercel's edge checks the secret against its own stored value, not the env var — but redeploy anyway so
INNGEST_SERVE_ORIGIN_BYPASS_SECRETis available to any app code that references it later.) -
Tell Inngest Cloud about the secret (only needed if syncing against a hash/preview URL — skip if already using the stable
.vercel.appdomain as confirmed reachable above):- If the Vercel↔Inngest integration is installed: Inngest dashboard → Settings → Integrations → Vercel → select this project → paste the secret into the "Deployment Protection Key" field → Save.
- If not installed: Inngest dashboard → Apps → select the
creative-ingestapp → Edit → change the sync URL to:https://launch.lynkr.cc/api/inngest?x-vercel-protection-bypass=<secret>&x-vercel-set-bypass-cookie=samesitenone(the custom domain — do NOT uselauncpadv2-scaled.vercel.app, it is SSO-gated) → Save → click Resync.
-
Verify:
- From the dashboard's Deployment Protection page, confirm the new bypass rule shows status "Active."
- In Inngest dashboard → Apps →
creative-ingest, confirm the app shows "Synced" (green) rather than an error/unreachable state. - Trigger a test check (
POST /api/admin/checks/triggeron the live deployment, or via the app's admin UI) and confirm a new event shows up in the Inngest dashboard's Runs tab, executing (not stuck "queued"). - Confirm a new row lands in
creative_check_resultsin ClickHouse sourced from the live Vercel deployment.
A separate, unrelated Inngest error you may see
PUT /api/inngest can independently return:
{"message":"The function 'Write ClickUp Custom Field' has higher concurrency
limits (8) than your plan limit of 5","modified":false}
This means the Write ClickUp Custom Field Inngest function is configured
with concurrency: 8 (or similar) in code, but the connected Inngest Cloud
plan only allows 5. Either lower the function's concurrency setting in code
(outside this runbook's scope — belongs to whoever owns
src/inngest/*) or upgrade the Inngest plan. This does not block the
protection-bypass work above; it's a separate sync failure worth flagging
to the team.
Prevent
To rotate the secret later: repeat steps 1–3 to generate a new one, update the env var in step 4, update Inngest's stored key in step 6, then return to the Deployment Protection page and revoke the old bypass rule so it can no longer be used.