Google Tag Manager — Discovery Recipe (Pipedream Connect gap-fill)
Google Tag Manager — Discovery Recipe (Pipedream Connect gap-fill)
GTM is NOT in Composio’s catalog (verified 2026-05-19). It is served via Pipedream Connect as the sanctioned gap-fill vendor per ADR-061. This file is a recipe, not a snapshot — re-verify connection IDs and tool surface before relying on them.
Auth model
- OAuth client: BYO Google OAuth client (separate from
googlesuper). GCP projectascend-gtm. Client ID prefix705816965171-qumivcaeqi2ad13opj9.... - Redirect URI:
https://api.pipedream.com/connect/oauth/oa_88iV2v/callback - Scopes (sensitive):
https://www.googleapis.com/auth/tagmanager.readonlyhttps://www.googleapis.com/auth/tagmanager.edit.containershttps://www.googleapis.com/auth/tagmanager.edit.containerversionshttps://www.googleapis.com/auth/tagmanager.publish
- Pipedream OAuth client:
ascend-gtm-gtm(wired to the GCP client above) - Multi-tenant model:
external_user_id={client_slug}mirrors Composio’suser_id={slug}pattern.
Secrets (Infisical — project 1c1907fa-ee74-4d52-ba1a-839fc71e855d, env prod)
| Key | Purpose |
|---|---|
PIPEDREAM_CLIENT_ID | Workspace API OAuth client ID (server-side auth) |
PIPEDREAM_CLIENT_SECRET | Workspace API OAuth client secret |
PIPEDREAM_WORKSPACE_ID | Workspace ID — o_JvI9PZE |
PIPEDREAM_PROJECT_ID | Required for MCP server header x-pd-project-id. Current value: proj_ELsVB0b (verified 2026-05-19). |
Connection-verify recipe
Server-side workspace OAuth token (needed before any API or MCP call):
source ~/.zprofilecurl -X POST https://api.pipedream.com/v1/oauth/token \ -H "Content-Type: application/json" \ -d "{\"grant_type\":\"client_credentials\",\"client_id\":\"$PIPEDREAM_CLIENT_ID\",\"client_secret\":\"$PIPEDREAM_CLIENT_SECRET\"}"Expected: {"access_token":"...","token_type":"Bearer","expires_in":3600}.
Resolved 2026-05-19: workspace OAuth previously returned
invalid_client— root cause was conflating the BYO GCP OAuth client (for Google end-user consent, namespaced under Pipedream OAuth clientascend-gtm-gtm) with the workspace API OAuth client (forapi.pipedream.comitself). These are distinct artifacts. Workspace API clientascendgtm-connectwas created 2026-05-19 and credentials stored via Infisical MCP (noecho/newline issues since MCP path bypasses shell). Token endpoint now returns a valid Bearer token.
End-user connect flow (per tenant)
ACCESS_TOKEN="<from step above>"PROJECT_ID="<proj_xxx from PIPEDREAM_PROJECT_ID>"EXTERNAL_USER_ID="ascend" # or kahuna, or any client slug
# 1. Create a Connect Tokencurl -X POST https://api.pipedream.com/v1/connect/$PROJECT_ID/tokens \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "X-PD-Environment: production" \ -H "Content-Type: application/json" \ -d "{\"external_user_id\":\"$EXTERNAL_USER_ID\"}"Returns {token, connect_link_url, expires_at}. Open connect_link_url in a browser → click through Google consent → Pipedream stores the refresh token under external_user_id.
Manual UI alternative: from Pipedream dashboard → Connect → Users → pick the user → “Connect a new account” → Google Tag Manager.
Smoke test (after connect)
Step 1 — List connected accounts to get the apn_* ID for this tenant:
curl -sS -G "https://api.pipedream.com/v1/connect/$PROJECT_ID/accounts" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "x-pd-environment: production" \ --data-urlencode "external_user_id=$EXTERNAL_USER_ID" \ --data-urlencode "app=google_tag_manager"Returns {"data":[{"id":"apn_xxxxxxx","healthy":true,"authorized_scopes":[…],…}]}. Capture the id.
Step 2 — Proxy a GET to GTM via base64url-encoded target URL in the path:
ACCOUNT_ID="apn_xxxxxxx" # from step 1URL_B64=$(printf 'https://tagmanager.googleapis.com/tagmanager/v2/accounts' | base64 | tr '+/' '-_' | tr -d '=')
curl -sS -X GET "https://api.pipedream.com/v1/connect/$PROJECT_ID/proxy/$URL_B64?external_user_id=$EXTERNAL_USER_ID&account_id=$ACCOUNT_ID" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "x-pd-environment: production"Expect {"account":[{"path":"accounts/…","accountId":"…","name":"…","features":{…}}]}. If data:[] from step 1: consent wasn’t completed, or external_user_id doesn’t match what was passed to the connect token.
Verified working 2026-05-20T00:57Z for external_user_id=ascend against connected account apn_JjhBPDA — returned {"account":[{"accountId":"4703167523","name":"Kahuna",…}]}.
Important — Connect tokens vs workspace tokens: the
ctok_*token fromPOST /v1/connect/{project_id}/tokensis one-shot and consumed by the user’s browser atconnect.html. For data-plane calls, always use the workspace OAuth Bearer (mint a fresh one — 1h TTL) plusexternal_user_id+account_idquery params to identify the stored grant. Don’t passctok_*to the proxy — it returns"The Pipedream Connect token is invalid".
MCP equivalent
https://remote.mcp.pipedream.net/v3 with headers:
Authorization: Bearer <workspace access token>x-pd-project-id: <proj_xxx>x-pd-environment: productionx-pd-external-user-id: ascendx-pd-app-slug: google_tag_managerOnce stable, add to .mcp.json as a new server entry pipedream-gtm. Re-issue access tokens before expiry (≤1h).
GTM v2 endpoints — what to call
Base: https://tagmanager.googleapis.com/tagmanager/v2/
| Audit primitive | Endpoint |
|---|---|
| Accounts | GET accounts |
| Containers | GET accounts/{a}/containers |
| Workspaces | GET accounts/{a}/containers/{c}/workspaces |
| Tags | GET .../workspaces/{w}/tags |
| Triggers | GET .../workspaces/{w}/triggers |
| Variables | GET .../workspaces/{w}/variables |
| Create version | POST .../workspaces/{w}:create_version |
| Publish version | POST .../versions/{v}:publish |
Full reference: https://developers.google.com/tag-platform/tag-manager/api/v2/reference
Per-tenant rollout
Repeat the connect flow for each new tenant slug. The connection ID returned by accounts.list (Pipedream proxy) for the external_user_id is the lookup key. Treat connection IDs as ephemeral — they rotate on re-auth.
Last-known values (assume stale, re-verify before use)
PIPEDREAM_WORKSPACE_ID = o_JvI9PZE(verified 2026-05-19)PIPEDREAM_PROJECT_ID = proj_ELsVB0b(verified 2026-05-19)- Pipedream workspace API OAuth client name:
ascendgtm-connect(verified 2026-05-19) - GCP OAuth client ID:
705816965171-qumivcaeqi2ad13opj9ns2eounrokdqq.apps.googleusercontent.com(verified 2026-05-19) - GCP redirect URI:
https://api.pipedream.com/connect/oauth/oa_88iV2v/callback - Pipedream Connect app slug (GTM):
google_tag_manager(Pipedreamoa_G1MiyV) - ascend connected account:
apn_JjhBPDA(live, healthy, verified 2026-05-20T00:57Z) — scopes granted:tagmanager.readonly,tagmanager.edit.containers,tagmanager.publish+email,profile.tagmanager.edit.containerversionsNOT granted in initial consent — re-consent needed beforeworkspaces:create_versioncan be called. - Pipedream proxy
allowed_domains(whitelist enforced server-side):www.googleapis.com,tagmanager.googleapis.com.
Rotation triggers
- Pipedream workspace OAuth client secret →
printf 'new' | wrangler ...is unrelated; rotate inside Pipedream dashboard thenmcp__infisical__update-secret. - GCP OAuth client secret rotation → update Pipedream BYO client config + Infisical at
google/gtm/client_secret. - Re-evaluation triggers: see ADR-061 “Re-evaluation triggers” section.