# \[Bug\]: T3 Connect doc gives the relay webhook path as /v1/hooks/:environmentId/\.\.\., but the relay routes on :endpointKey · Issue \#16988 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/issues/16988)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: completed

Priority: 0

## Description

[Discussion and activity](https://git.cafe/pingdotgg/t3code/issues/16988)

---

### Before submitting

- [x] I searched existing issues and did not find a duplicate.
- [x] I included enough detail to reproduce or investigate the problem.

### Area

Docs

### Steps to reproduce

**Summary:** `docs/internals/t3-connect.md` says the relay forwards `/v1/hooks/:environmentId/:hookId/:token` to the environment's tunnel. The relay route and the server's URL builder both use a managed-tunnel endpoint key in that segment, not the environment ID, and the relay answers 404 `hook_not_found` when the environment ID is placed there. A reader who builds or debugs a relay webhook URL from this doc uses the wrong identifier and puts the environment ID into a URL that the code deliberately keeps it out of. The defect is limited to the documentation; webhook URLs the server hands out are correct.

1. On `main`, read `docs/internals/t3-connect.md` lines 7-8: "the relay forwards `/v1/hooks/:environmentId/:hookId/:token` to the environment's tunnel".
2. Compare with the route the relay serves: `packages/contracts/src/relay.ts` line 1245 defines `const RELAY_HOOK_PATH = "/v1/hooks/:endpointKey/:hookId/:token";`.
3. Compare with the server's URL builder: `relayHookBaseUrl` in `apps/server/src/scheduledTasks/ScheduledTaskService.ts` (about lines 80-95) builds `${relayUrl}/v1/hooks/${endpointKey}`, where `endpointKey` is the last `-` segment of the managed tunnel name and must match `/^[0-9a-f]{16}$/`.
4. Run the relay forwarder tests: `cd infra/relay && npx vp test run src/hooks/HookForwarder.test.ts`. The case "returns 404 for unknown endpoints and unready endpoints" sends `POST /v1/hooks/<environmentId>/hook-1/token` and expects 404 `{"error":"hook_not_found"}`.
5. Run the server webhook tests: `cd apps/server && npx vp test run src/scheduledTasks/ScheduledTaskService.webhook.test.ts`. The case "builds the relay hook URL from the managed tunnel's key, never the environment id" expects `https://relay.example.com/v1/hooks/0123456789abcdef` for a tunnel name ending in `-0123456789abcdef`.

### Expected behavior

The T3 Connect internals doc should name the identifier the relay actually routes on: the managed endpoint key, the 16-hex hash suffix of the environment's managed tunnel name. The code states this design in `infra/relay/src/deploymentConfig.ts`: the key "covers user and environment, so one key names exactly one link, unlike the environment id, which any account can claim". `relayHookBaseUrl`'s doc comment adds that "the URL never reveals the environment id".

### Actual behavior

The doc names `:environmentId` as the first path parameter. Following it produces a URL the relay rejects: in a local run on `main`, `HookForwarder.test.ts` passed 26/26, including the case that confirms a request with the environment ID in the key slot gets 404 `hook_not_found` and is not forwarded. `ScheduledTaskService.webhook.test.ts` passed 32/32, including the case that confirms the server builds hook URLs from the tunnel key. On a running Nightly server (observation reported to me, not rerun for this report), a webhook task created with `schedule_task` returned a `webhookUrl` of the shape `https://relay.t3.codes/v1/hooks/<16-hex key>/<url-encoded task id>/<token>`; the 16-hex segment is not the environment ID, which is a UUID.

History: #15086 added the sentence when the route really was `/v1/hooks/:environmentId/:hookId/:token`. #15487 (commit `f33b060caf`) changed `RELAY_HOOK_PATH` to `:endpointKey` and rewrote the same doc sentence in the same commit, but kept `:environmentId`.

#### Evidence

- Expected source: `packages/contracts/src/relay.ts` line 1245 (`RELAY_HOOK_PATH`), `relayHookBaseUrl` in `apps/server/src/scheduledTasks/ScheduledTaskService.ts`, `resolveEndpoint` in `infra/relay/src/hooks/HeldHooks.ts`, and the `MANAGED_ENDPOINT_KEY_PATTERN` comment in `infra/relay/src/deploymentConfig.ts`.
- Failure source: `docs/internals/t3-connect.md` lines 7-8.
- Evidence provenance: observed
- Local verification: reproduced
- Reproduction completeness: complete

Primary violation evidence (observed): the `:environmentId` path in `docs/internals/t3-connect.md` lines 7-8, read on `main` against `RELAY_HOOK_PATH`, and the relay's 404 `hook_not_found` for an environment ID in that position in `HookForwarder.test.ts`, run locally. Both test suites are the project's own in-process harnesses, not a deployed relay. The live `webhookUrl` shape comes from the reported Nightly observation; no real key, token, task ID, or environment ID is included here.

#### Restoration check

Failing: `docs/internals/t3-connect.md` describes the relay hook path with `:environmentId` as its first parameter, which disagrees with `RELAY_HOOK_PATH` and with the 404 the relay returns for an environment ID in that position. Passing: the doc's hook path matches `RELAY_HOOK_PATH` (`/v1/hooks/:endpointKey/:hookId/:token`) and identifies the endpoint key as the managed tunnel's key rather than the environment ID, while the forwarder and webhook test suites above still pass unchanged.

### Impact

Minor bug or occasional failure

Only an internals document is wrong; the relay, the server's URL builder, and the URLs handed to users agree with each other, so product behavior is unaffected. Following the doc gives a 404 `hook_not_found` for a hand-built URL and exposes an environment ID in a URL the design keeps it out of.

### Version or commit

`main` @ 300f7f9d45ff19c01bc987dbf1c3bc3e9a3a59ee; also present in the latest nightly `v0.0.46-nightly.20261007.2787`. The latest stable release `v0.0.45` predates relay webhook forwarding (neither #15086 nor #15487 is in it), so it is not affected.

### Environment

Source inspection plus the repo's own tests: Node 22.23.2, `vp test run` (Vitest 5.0.1) after `pnpm install --frozen-lockfile`. Reported runtime observation: T3 Code Nightly `0.0.46-nightly.20261007.2774` server on macOS arm64.

### Logs or stack traces

```shell
# infra/relay
npx vp test run src/hooks/HookForwarder.test.ts
 Test Files  1 passed (1)
      Tests  26 passed (26)

# apps/server
npx vp test run src/scheduledTasks/ScheduledTaskService.webhook.test.ts
 Test Files  1 passed (1)
      Tests  32 passed (32)
```

### Screenshots, recordings, or supporting files

_No response_

### Workaround

Use the `webhookUrl` the server returns for a webhook task, or read `RELAY_HOOK_PATH` in `packages/contracts/src/relay.ts`; both give the correct endpoint-key path.

