Skip to content

Ad & billing OAuth setup (operator)

Register one OAuth app per provider, once. The credentials become platform secrets (wrangler secret put), set on both the staging and production API workers. Until they're set, the connect flow shows "… isn't enabled on this workspace yet" and the OAuth start endpoint returns 503 CONNECTOR_OAUTH_NOT_CONFIGURED (it never redirects to a broken provider page).

Clients never see these — they just click Connect and approve their own account.

Callback (redirect) URIs

Whitelist these exactly (they're derived from ENVIRONMENT):

ProviderStagingProduction
Meta Adshttps://api-sta.kordox.com/api/oauth/facebook-ads/callbackhttps://api.kordox.com/api/oauth/facebook-ads/callback
Google Adshttps://api-sta.kordox.com/api/oauth/google-ads/callbackhttps://api.kordox.com/api/oauth/google-ads/callback
Stripehttps://api-sta.kordox.com/api/oauth/stripe/callbackhttps://api.kordox.com/api/oauth/stripe/callback
Shopifyhttps://api-sta.kordox.com/api/oauth/shopify/callbackhttps://api.kordox.com/api/oauth/shopify/callback

Meta Ads — Meta for Developers

  1. developers.facebook.com → Apps → Create app → type Business.
  2. Add the Facebook Login product; under its settings add the two Meta redirect URIs above.
  3. Permissions used by the connector: ads_read, leads_retrieval, pages_manage_ads (spend sync + lead-gen forms). ads_read/leads_retrieval are advanced-access scopes → require App Review + a Business verification before non-test users can grant them. Test users work immediately.
  4. Set secrets:
    bash
    cd apps/api
    npx wrangler secret put FACEBOOK_APP_ID
    npx wrangler secret put FACEBOOK_APP_SECRET
    # prod: append  --env production

Spend now syncs per campaign (level=campaign insights) → powers per-campaign ROAS. First sync pulls ~30 days.

  1. Google Cloud Console → OAuth client (Web application); add the two Google redirect URIs above. Scope: https://www.googleapis.com/auth/adwords.
  2. Apply for a Google Ads API developer token (Google Ads account → API Center). Starts in test access; basic access needs an application review.
  3. Set secrets:
    bash
    cd apps/api
    npx wrangler secret put GOOGLE_ADS_CLIENT_ID
    npx wrangler secret put GOOGLE_ADS_CLIENT_SECRET
    npx wrangler secret put GOOGLE_ADS_DEVELOPER_TOKEN
    # prod: append  --env production

Spend syncs per campaign (FROM campaign, metrics.cost_micros).

Stripe Connect — Stripe dashboard

  1. Stripe → Settings → Connect → enable; copy the Connect client ID (ca_…). Add the Stripe redirect URIs above.
  2. Set secrets:
    bash
    cd apps/api
    npx wrangler secret put STRIPE_CLIENT_ID        # ca_...
    npx wrangler secret put STRIPE_SECRET_KEY       # sk_... (token exchange)
    # prod: append  --env production

Shopify — Partners dashboard

  1. partners.shopify.com → Apps → Create app; add the Shopify redirect URIs.
  2. Set secrets:
    bash
    cd apps/api
    npx wrangler secret put SHOPIFY_CLIENT_ID
    npx wrangler secret put SHOPIFY_CLIENT_SECRET
    # prod: append  --env production

Verify

After setting secrets, GET /api/financial/accounts returns oauthConfigured: { stripe, shopify, "facebook-ads", "google-ads" } — the connect modal reads this and enables the provider. Connect a test account, then Sync now; per-campaign spend appears on Finance → Campaign attribution.

Routes: apps/api/src/routes/oauth.ts; connectors: apps/api/src/connectors/{facebook-ads,google-ads,stripe,shopify}.ts; config gate: oauthProvidersConfigured() in apps/api/src/connectors/base.ts.

Every project, one cockpit.