Claude Code Plugins

Community-maintained marketplace

Feedback

violetconnect-woocommerce

@violetio/violet-ai-plugins
0
0

WooCommerce REST API authentication and credential-based onboarding patterns for VioletConnect

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name violetconnect-woocommerce
description WooCommerce REST API authentication and credential-based onboarding patterns for VioletConnect

VioletConnect: WooCommerce Integration

Overview

VioletConnect integrates with WooCommerce via REST API Keys (not centralized OAuth). Each WooCommerce store is self-hosted on WordPress, so merchants must generate API keys manually and enter them in VioletConnect.

Integration Type: REST API Keys (no centralized OAuth) Store Identifier: Store URL (any WordPress domain) Credential Storage: consumerKey + consumerSecret Authentication: HTTP Basic Auth Pre-Registration Support: Flows B and C only (no Flow A - WC has no OAuth)

Related Skills:

  • violetconnect: Core VioletConnect features and architecture
  • violetconnect-patterns: Code patterns (Redux, axiosWrapper, AppContext)
  • v-woocommerce: General WooCommerce API patterns and integration details

WooCommerce Authentication Flow

Key Difference: No OAuth

WooCommerce does NOT have centralized OAuth like Shopify or BigCommerce. Instead:

  • Each WooCommerce store is self-hosted on WordPress
  • No central OAuth server exists
  • Merchants generate REST API keys in WordPress admin
  • Keys are entered manually in VioletConnect
  • Validation via test API call

Why No OAuth: WooCommerce is open-source software installed on merchants' own servers. There's no central authority like Shopify or BigCommerce to manage OAuth.


REST API Credentials Flow

1. Merchant lands on VioletConnect: connect.violet.io/{appAlias}/platforms/woocommerce
2. Merchant enters email → Creates session
3. Merchant selects "WooCommerce" platform
4. Merchant enters store URL (e.g., "https://mystore.com")
5. VioletConnect validates URL format (any domain)
6. VioletConnect shows credential entry form
7. Merchant enters WooCommerce REST API credentials:
   - Consumer Key (e.g., "ck_abc123...")
   - Consumer Secret (e.g., "cs_xyz789...")
8. VioletConnect validates credentials via test API call
9. If valid: Create merchant record in MerchantService
10. Merchant completes commission/payout setup
11. Merchant redirected to success page

Security Note: Credentials are never stored client-side. They are sent directly to the backend via API proxy.


REST API Implementation Details

Dynamic Routing

Page Files:

pages/[appAlias]/platforms/woocommerce/
├── index.tsx         # Store URL + credentials entry
└── callback.tsx      # Not used (no OAuth redirect)

Key Utility Files:

// utils/woocommerce/validation.ts
// Store URL validation (any valid URL)
// Credential validation via test API call

// utils/woocommerce/auth.ts
// Basic Auth header construction

Note: There is no callback.tsx page needed for WooCommerce since there's no OAuth redirect.


Credential Structure

interface WooCommerceCredentials {
  storeUrl: string;        // e.g., "https://mystore.com"
  consumerKey: string;     // e.g., "ck_abc123def456..."
  consumerSecret: string;  // e.g., "cs_xyz789ghi012..."
}

Consumer Key Format: Starts with ck_ Consumer Secret Format: Starts with cs_


Validation: Test API Call

Validate credentials by making a test call to the WooCommerce REST API:

// Validate credentials by calling WC REST API
async function validateCredentials(creds: WooCommerceCredentials): Promise<{
  valid: boolean;
  wcVersion?: string;
  error?: string;
}> {
  try {
    // Construct Basic Auth header
    const auth = Buffer.from(
      `${creds.consumerKey}:${creds.consumerSecret}`
    ).toString('base64');

    // Test API call to system_status endpoint
    const response = await axios.get(
      `${creds.storeUrl}/wp-json/wc/v3/system_status`,
      {
        headers: {
          Authorization: `Basic ${auth}`,
          'Content-Type': 'application/json'
        },
        timeout: 10000  // 10 second timeout
      }
    );

    // Success - credentials are valid
    return {
      valid: true,
      wcVersion: response.data.environment?.version || 'Unknown'
    };
  } catch (error: any) {
    // Failed - credentials invalid or other error
    return {
      valid: false,
      error: error.response?.data?.message || error.message || 'Validation failed'
    };
  }
}

Why /wp-json/wc/v3/system_status:

  • Requires valid credentials (will return 401 if invalid)
  • Returns WooCommerce version (useful for debugging)
  • Doesn't modify any data (read-only endpoint)

Credential Entry UX

Key Generation Instructions

Merchants must generate REST API keys in their WordPress Admin panel. VioletConnect should guide them through this process.

Step-by-Step Instructions to Show Merchant:

1. Log in to your WordPress Admin Dashboard
2. Navigate to: WooCommerce → Settings
3. Click the "Advanced" tab
4. Click "REST API"
5. Click "Add Key" button
6. Configure the key:
   - Description: "Violet Integration"
   - User: Select an admin user
   - Permissions: Read/Write
7. Click "Generate API Key"
8. Copy the Consumer Key and Consumer Secret
   (You'll only see these once!)

Visual Aid: Consider adding screenshots or a link to WooCommerce docs: https://woocommerce.com/document/woocommerce-rest-api/


Credential Form Component

<WooCommerceCredentialForm
  onSubmit={async (data: WooCommerceCredentials) => {
    // Show loading state
    setValidating(true);

    // Validate credentials
    const validation = await validateCredentials(data);

    setValidating(false);

    if (validation.valid) {
      // Success - create merchant
      await createMerchant({
        platform: 'woocommerce',
        storeUrl: data.storeUrl,
        credentials: {
          consumerKey: data.consumerKey,
          consumerSecret: data.consumerSecret
        }
      });

      // Redirect to commission setup
      router.push(`/${appAlias}/commission`);
    } else {
      // Show error
      setError(validation.error || 'Invalid credentials');
    }
  }}
>
  <input
    name="consumerKey"
    placeholder="Consumer Key (ck_...)"
    required
  />

  <input
    name="consumerSecret"
    type="password"
    placeholder="Consumer Secret (cs_...)"
    required
  />

  <HelpText>
    <a
      href="https://woocommerce.com/document/woocommerce-rest-api/"
      target="_blank"
      rel="noopener noreferrer"
    >
      How to generate API keys
    </a>
  </HelpText>

  <Checkbox required>
    I understand these credentials will be used to:
    - Read products, orders, and customers
    - Create orders on my behalf
    - Update order statuses
  </Checkbox>

  <button type="submit" disabled={validating}>
    {validating ? 'Validating...' : 'Validate & Connect'}
  </button>
</WooCommerceCredentialForm>

Security Best Practice

CRITICAL: Always show merchants what the credentials will be used for:

  • Read products, orders, customers
  • Create orders on their behalf
  • Update order statuses

Require explicit consent: Merchant must check "I understand and approve" before submitting credentials.

Why: Builds trust and ensures merchants understand what permissions they're granting.


Pre-Registration Integration

WooCommerce supports Flow B (Store URL Lookup) and Flow C (MerchantId Link) only.

No Flow A: WooCommerce has no OAuth, so there's no "direct install link" pattern.


Flow B: Store URL Lookup

  1. Merchant enters WooCommerce store URL on VioletConnect
  2. VioletConnect calls /api/pre-register/lookup?storeUrl={url}&appId={appId}
  3. If found:
    • Show PreRegFound component
    • Display merchant name + store URL
    • "Connect to WooCommerce" button → Goes to credential entry form
  4. If not found: Continue normal email-first flow

API Endpoint:

// pages/api/pre-register/lookup.ts
GET /api/pre-register/lookup?storeUrl=https://mystore.com&appId=1

Response (if found): {
  merchantId: 123,
  merchantName: "My Store",
  storeUrl: "https://mystore.com",
  platform: "woocommerce",
  installLink: null,  // WC has no install link
  credentials: {
    consumerKey: "ck_...",     // Pre-stored
    consumerSecret: "cs_..."   // Pre-stored
  },
  status: "pending"
}

Response (if not found): 404

Note: For WooCommerce, pre-registration can store credentials (consumerKey + consumerSecret) upfront, but merchant must still review and approve before submission (security).


Flow C: MerchantId Link

  1. Channel sends link: connect.violet.io/{appAlias}?merchantId={id}
  2. AppContext detects merchantId query param
  3. Dispatches lookupByMerchantId(merchantId)
  4. If found: Redirect to /pre-registration/confirm
  5. Merchant reviews pre-stored credentials
  6. Merchant clicks "Approve and Connect"
  7. VioletConnect validates credentials via test API call
  8. If valid: Create merchant record

Confirmation Page:

// pages/[appAlias]/pre-registration/confirm.tsx
<PreRegConfirmation
  preRegistration={current}
  onConfirm={async () => {
    // Validate credentials before creating merchant
    const validation = await validateCredentials({
      storeUrl: current.storeUrl,
      consumerKey: current.credentials.consumerKey,
      consumerSecret: current.credentials.consumerSecret
    });

    if (validation.valid) {
      // Create merchant
      await createMerchant({
        merchantId: current.merchantId,
        platform: 'woocommerce',
        storeUrl: current.storeUrl,
        credentials: current.credentials
      });

      router.push(`/${appAlias}/success`);
    } else {
      setError('Credentials are no longer valid. Please contact support.');
    }
  }}
/>

WooCommerce Constraint: Even with pre-registered credentials, merchant should review before submitting (security best practice).


WooCommerce Components

StoreUrlInput (WooCommerce)

// Validates any valid URL (WC can be on any domain)
const wcUrlPattern = /^https?:\/\/.+\.[a-z]{2,}$/i;

<StoreUrlForm
  platform="woocommerce"
  placeholder="https://mystore.com"
  validation={wcUrlPattern}
  helpText="Enter your WordPress store URL"
  onSubmit={handleStoreUrlSubmit}
  errorMessage="Invalid URL format"
/>

Key Difference: Unlike Shopify (*.myshopify.com) or BigCommerce (store-*.mybigcommerce.com), WooCommerce URLs can be any domain.


CredentialForm

<WooCommerceCredentialForm>
  {/* Consumer Key Input */}
  <input
    name="consumerKey"
    placeholder="Consumer Key (ck_...)"
    pattern="^ck_[a-zA-Z0-9]+"
  />

  {/* Consumer Secret Input */}
  <input
    name="consumerSecret"
    type="password"
    placeholder="Consumer Secret (cs_...)"
    pattern="^cs_[a-zA-Z0-9]+"
  />

  {/* Help Text */}
  <HelpText>
    <a href="https://woocommerce.com/document/woocommerce-rest-api/" target="_blank">
      How to generate API keys
    </a>
  </HelpText>

  {/* Consent Checkbox */}
  <Checkbox required>
    I understand these credentials will be used to read products, orders, and customers
  </Checkbox>

  {/* Submit Button */}
  <button type="submit">Validate & Connect</button>
</WooCommerceCredentialForm>

CredentialValidator

// Real-time credential validation
const [validating, setValidating] = useState(false);
const [validationMessage, setValidationMessage] = useState<string>('');

const onValidate = async () => {
  setValidating(true);
  setValidationMessage('');

  const result = await validateCredentials(formData);

  setValidating(false);

  if (result.valid) {
    setValidationMessage(`✓ Connected to WooCommerce ${result.wcVersion}`);
  } else {
    setValidationMessage(`✗ ${result.error}`);
  }
};

return (
  <div>
    <button onClick={onValidate} disabled={validating}>
      {validating ? 'Validating...' : 'Test Credentials'}
    </button>
    {validationMessage && <p className={result.valid ? 'success' : 'error'}>{validationMessage}</p>}
  </div>
);

Error Handling

WooCommerce-Specific Errors

Error Trigger User Message Recovery
Invalid Store URL URL doesn't respond or times out "Could not connect to store. Please check the URL." Re-enter URL
Invalid Credentials REST API returns 401 Unauthorized "Invalid credentials. Please check your Consumer Key and Secret." Re-enter credentials
WC Not Installed /wp-json/wc/v3 returns 404 "WooCommerce is not installed on this store." Install WooCommerce plugin
Insufficient Permissions API key has read-only access "API key must have Read/Write permissions." Generate new key with correct permissions
Plugin Conflict REST API error 500 "Store configuration error. Please contact support." Disable conflicting plugins
SSL Required HTTP URL provided (WC requires HTTPS) "HTTPS is required for WooCommerce API. Please use https://" Use HTTPS URL
Firewall Blocking Connection timeout "Could not reach your store. Check firewall settings." Whitelist VioletConnect IPs

Error Component

<WCError
  error={error}
  onRetry={() => {
    setCredentials(null);
    setError(null);
  }}
  supportUrl={channelConfig.supportUrl}
  channelName={channelName}
/>

Error Recovery Patterns:

  • Invalid credentials: Allow merchant to re-enter
  • WC not installed: Show installation instructions
  • Permissions issue: Show key generation instructions with emphasis on "Read/Write"

Testing

Local Setup (Docker Compose)

Set up a local WordPress + WooCommerce environment:

# docker-compose.yml
version: '3'

services:
  wordpress:
    image: wordpress:latest
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: root
      WORDPRESS_DB_PASSWORD: password
    volumes:
      - ./wordpress:/var/www/html

  woocommerce:
    image: woocommerce/woocommerce:latest
    depends_on:
      - wordpress

  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: wordpress
    volumes:
      - ./db:/var/lib/mysql

Setup Steps:

# Start containers
docker-compose up -d

# Access WordPress
# URL: http://localhost:8080

# Complete WordPress setup
# Install WooCommerce plugin (should auto-install with woocommerce image)
# Navigate to WooCommerce → Settings → Advanced → REST API
# Generate API keys

E2E Testing

// tests/e2e/woocommerce-credentials.spec.ts
import { test, expect } from '@playwright/test';

test('WooCommerce credential flow with pre-registration', async ({ page }) => {
  // Navigate to WooCommerce platform page
  await page.goto('http://localhost:3001/testchannel/platforms/woocommerce');

  // Enter store URL
  await page.fill('[name="storeUrl"]', 'https://mystore.test');
  await page.click('button[type="submit"]');

  // Verify pre-registration found
  await expect(page.locator('text=Your store is already set up!')).toBeVisible();
  await expect(page.locator('text=My Store')).toBeVisible();

  // Click "Review Credentials"
  await page.click('text=Review Credentials');

  // Should show pre-filled credentials (masked)
  await expect(page.locator('input[name="consumerKey"]')).toHaveValue(/^ck_/);
  await expect(page.locator('input[name="consumerSecret"]')).toHaveAttribute('type', 'password');

  // Check consent checkbox
  await page.check('input[type="checkbox"][required]');

  // Click "Approve and Connect"
  await page.click('text=Approve and Connect');

  // Should validate and create merchant
  await expect(page.locator('text=Successfully connected')).toBeVisible();
});

Unit Testing

// tests/unit/woocommerce-validation.test.ts
import { validateCredentials } from '@/utils/woocommerce/validation';
import axios from 'axios';

jest.mock('axios');

describe('WooCommerce Credential Validation', () => {
  const validCreds = {
    storeUrl: 'https://test.com',
    consumerKey: 'ck_test123',
    consumerSecret: 'cs_test456'
  };

  test('validates correct credentials', async () => {
    (axios.get as jest.Mock).mockResolvedValue({
      data: {
        environment: {
          version: '6.5.0'
        }
      }
    });

    const result = await validateCredentials(validCreds);

    expect(result.valid).toBe(true);
    expect(result.wcVersion).toBe('6.5.0');
  });

  test('handles invalid credentials (401)', async () => {
    (axios.get as jest.Mock).mockRejectedValue({
      response: {
        status: 401,
        data: { message: 'Invalid signature' }
      }
    });

    const result = await validateCredentials(validCreds);

    expect(result.valid).toBe(false);
    expect(result.error).toContain('Invalid signature');
  });

  test('handles WooCommerce not installed (404)', async () => {
    (axios.get as jest.Mock).mockRejectedValue({
      response: {
        status: 404,
        data: { message: 'No route was found' }
      }
    });

    const result = await validateCredentials(validCreds);

    expect(result.valid).toBe(false);
    expect(result.error).toContain('No route was found');
  });

  test('handles connection timeout', async () => {
    (axios.get as jest.Mock).mockRejectedValue({
      message: 'timeout of 10000ms exceeded'
    });

    const result = await validateCredentials(validCreds);

    expect(result.valid).toBe(false);
    expect(result.error).toContain('timeout');
  });
});

Configuration

Environment Variables

# WooCommerce does NOT require central credentials
# Each merchant provides their own Consumer Key + Secret

# Optional: WC version requirements
MIN_WOOCOMMERCE_VERSION=5.0.0

# Optional: Test store for development
WC_TEST_STORE_URL=http://localhost:8080
WC_TEST_CONSUMER_KEY=ck_test123abc...
WC_TEST_CONSUMER_SECRET=cs_test456def...

Note: Unlike Shopify/BigCommerce, there are no central CLIENT_ID or CLIENT_SECRET environment variables. Each merchant has their own API keys.


Channel-Specific Config

interface ChannelConfig {
  requiresWCVersion?: string;           // e.g., ">=5.0.0"
  wcScopesRequired: string[];           // Permissions needed (for display only)
  showCredentialInstructions: boolean;  // Show key generation instructions?
  wcTestStoreUrl?: string;              // Test store for development
}

Example:

const channelConfig: ChannelConfig = {
  requiresWCVersion: '>=5.0.0',
  wcScopesRequired: ['read_products', 'read_orders', 'write_orders'],
  showCredentialInstructions: true,  // Show merchants how to generate keys
  wcTestStoreUrl: process.env.WC_TEST_STORE_URL
};

WooCommerce REST API Authentication

HTTP Basic Auth

All WooCommerce API calls use HTTP Basic Auth:

// Server-side API call pattern
const auth = Buffer.from(`${consumerKey}:${consumerSecret}`).toString('base64');

const response = await axios.get(
  `${storeUrl}/wp-json/wc/v3/products`,
  {
    headers: {
      Authorization: `Basic ${auth}`,
      'Content-Type': 'application/json'
    }
  }
);

Why Basic Auth:

  • Simple and widely supported
  • No token expiration (keys are long-lived)
  • No refresh token flow needed

API Endpoint Format

WooCommerce REST API endpoints follow this pattern:

{storeUrl}/wp-json/wc/v3/{resource}

Examples:

  • Products: https://mystore.com/wp-json/wc/v3/products
  • Orders: https://mystore.com/wp-json/wc/v3/orders
  • Customers: https://mystore.com/wp-json/wc/v3/customers
  • System Status: https://mystore.com/wp-json/wc/v3/system_status

API Version: Always use /wc/v3 (latest stable version)


Related Documentation

System Docs

  • WooCommerce Integration: prism-brain/systems/violet-connect/woocommerce-integration.md
  • REST API Patterns: prism-brain/systems/violet-connect/wc-rest-api.md
  • Credential Security: prism-brain/systems/violet-connect/credential-management.md

Code Patterns

  • violetconnect: Core features (subdomain routing, session management, 13-step wizard)
  • violetconnect-patterns: Redux, axiosWrapper, AppContext, API proxy patterns

Platform Integration

  • v-woocommerce: WooCommerce API patterns (products, orders, webhooks, WordPress integration)

Implementation Guides

  • Pre-Registration Implementation: prism-brain/product/specs/merchant-pre-registration/guides/violet-connect/
  • WooCommerce PR Guides: prism-brain/product/specs/merchant-pre-registration/guides/violet-connect/pr-*-woocommerce.md

External Resources