Agent Skills: HubSpot Multi-Environment Setup

|

UncategorizedID: jeremylongshore/claude-code-plugins-plus-skills/hubspot-multi-env-setup

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/HEAD/plugins/saas-packs/hubspot-pack/skills/hubspot-multi-env-setup

Skill Files

Browse the full folder contents for hubspot-multi-env-setup.

Download Skill

Loading file tree…

plugins/saas-packs/hubspot-pack/skills/hubspot-multi-env-setup/SKILL.md

Skill Metadata

Name
hubspot-multi-env-setup
Description
|

HubSpot Multi-Environment Setup

Overview

Configure HubSpot integrations across dev/staging/production using separate HubSpot portals (test accounts), environment-specific tokens, and configuration management.

Prerequisites

  • HubSpot developer account (for test portals)
  • Secret management solution (Vault, AWS SM, GCP SM)
  • CI/CD pipeline with environment variables

Instructions

Step 1: Environment Strategy

| Environment | HubSpot Portal | Token Type | Data | |-------------|---------------|------------|------| | Development | Developer test account | Test private app token | Fake/seed data | | Staging | Sandbox portal | Staging private app token | Anonymized copy | | Production | Production portal | Production private app token | Real customer data |

Create a free developer test account at developers.hubspot.com.

Step 2: Environment Configuration

// src/config/hubspot.ts
import * as hubspot from '@hubspot/api-client';

type Environment = 'development' | 'staging' | 'production';

interface HubSpotEnvConfig {
  accessToken: string;
  portalId: string;
  retries: number;
  cacheTtlMs: number;
}

const ENV_CONFIG: Record<Environment, Partial<HubSpotEnvConfig>> = {
  development: {
    retries: 1,
    cacheTtlMs: 0, // no cache in dev for fresh data
  },
  staging: {
    retries: 3,
    cacheTtlMs: 60000,
  },
  production: {
    retries: 5,
    cacheTtlMs: 300000,
  },
};

function getEnvironment(): Environment {
  const env = process.env.NODE_ENV || 'development';
  if (['development', 'staging', 'production'].includes(env)) {
    return env as Environment;
  }
  return 'development';
}

export function getHubSpotConfig(): HubSpotEnvConfig {
  const env = getEnvironment();
  return {
    accessToken: process.env.HUBSPOT_ACCESS_TOKEN!,
    portalId: process.env.HUBSPOT_PORTAL_ID!,
    ...ENV_CONFIG[env],
  } as HubSpotEnvConfig;
}

export function createHubSpotClient(): hubspot.Client {
  const config = getHubSpotConfig();
  return new hubspot.Client({
    accessToken: config.accessToken,
    numberOfApiCallRetries: config.retries,
  });
}

Step 3: Per-Environment Secrets

# .env.development (git-ignored)
HUBSPOT_ACCESS_TOKEN=pat-na1-test-xxxxx    # developer test account
HUBSPOT_PORTAL_ID=12345678

# .env.staging (git-ignored)
HUBSPOT_ACCESS_TOKEN=pat-na1-staging-xxxxx  # sandbox portal
HUBSPOT_PORTAL_ID=23456789

# .env.production (NEVER in files -- use secret manager)
# Stored in AWS Secrets Manager / GCP Secret Manager / Vault
# AWS Secrets Manager
aws secretsmanager create-secret \
  --name hubspot/production \
  --secret-string '{"access_token":"pat-na1-xxxxx","portal_id":"34567890"}'

# Load at runtime
aws secretsmanager get-secret-value --secret-id hubspot/production \
  --query SecretString --output text | jq -r .access_token

# GCP Secret Manager
echo -n "pat-na1-xxxxx" | gcloud secrets create hubspot-access-token --data-file=-
gcloud secrets versions access latest --secret=hubspot-access-token

Step 4: Environment Isolation Guards

// Prevent accidental production operations in non-prod
function requireProduction(operation: string): void {
  if (getEnvironment() !== 'production') {
    throw new Error(
      `"${operation}" is only allowed in production. ` +
      `Current environment: ${getEnvironment()}`
    );
  }
}

// Prevent destructive operations in production without confirmation
function requireNonProduction(operation: string): void {
  if (getEnvironment() === 'production') {
    throw new Error(
      `"${operation}" is blocked in production. ` +
      `Use the staging environment instead.`
    );
  }
}

// Usage
async function bulkDeleteContacts(ids: string[]) {
  requireNonProduction('bulkDeleteContacts'); // safety guard
  for (const id of ids) {
    await client.crm.contacts.basicApi.archive(id);
  }
}

async function sendMarketingEmail(emailId: string) {
  requireProduction('sendMarketingEmail'); // only send real emails in prod
  // ...
}

Step 5: CI/CD Environment Matrix

# .github/workflows/deploy.yml
jobs:
  deploy:
    strategy:
      matrix:
        environment: [staging, production]
    environment: ${{ matrix.environment }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to ${{ matrix.environment }}
        env:
          HUBSPOT_ACCESS_TOKEN: ${{ secrets[format('HUBSPOT_{0}_TOKEN', matrix.environment)] }}
          HUBSPOT_PORTAL_ID: ${{ secrets[format('HUBSPOT_{0}_PORTAL_ID', matrix.environment)] }}
          NODE_ENV: ${{ matrix.environment }}
        run: |
          npm ci
          npm run build
          npm run deploy

Output

  • Separate HubSpot portals per environment
  • Environment-specific configuration with proper defaults
  • Secrets stored in platform secret managers (not env files)
  • Guards preventing cross-environment mistakes
  • CI/CD deploying to correct environment

Error Handling

| Issue | Cause | Solution | |-------|-------|----------| | Wrong portal in staging | Env var pointing to prod | Verify HUBSPOT_PORTAL_ID matches environment | | Guard triggered | Running prod code in dev | Check NODE_ENV is set correctly | | Secret not found | Missing secret manager entry | Create secret with aws secretsmanager create-secret | | Test data in production | Environment leak | Add portal ID validation at startup |

Resources

Next Steps

For observability setup, see hubspot-observability.