# How to Build Integration hub with V0

- Tool: v0
- Difficulty: Advanced
- Compatibility: V0 Premium
- Last updated: April 2026

## TL;DR

Build a Zapier-style integration hub with V0 using Next.js, Supabase for connection and flow data, and AES-256-GCM encryption for OAuth tokens. You'll create a connector marketplace, visual flow builder, webhook endpoints, and execution logging — all in about 2-4 hours without touching a terminal.

## Before you start

- A V0 account (Premium recommended for the complex multi-route app)
- A Supabase project for storing connections, flows, and execution logs
- OAuth credentials for at least one service (e.g., GitHub or Slack) for testing
- Understanding of API integrations (OAuth, webhooks, API keys)

## Step-by-step guide

### 1. Set up the project and integration schema

Open V0 and create a new project. Connect Supabase via the Connect panel. Create the schema for connectors, connections, flows, steps, executions, and webhooks.

```
// Paste this prompt into V0's AI chat:
// Build an integration hub. Create a Supabase schema with:
// 1. connectors: id (uuid PK), name (text), slug (text unique), description (text), icon_url (text), auth_type (text check in 'oauth2','api_key','webhook'), oauth_config (jsonb), base_url (text), is_active (boolean default true)
// 2. user_connections: id (uuid PK), user_id (uuid FK to auth.users), connector_id (uuid FK to connectors), credentials_encrypted (text), status (text default 'active' check in 'active','expired','revoked'), metadata (jsonb), connected_at (timestamptz), expires_at (timestamptz)
// 3. flows: id (uuid PK), user_id (uuid FK to auth.users), name (text), description (text), is_active (boolean default false), trigger_connection_id (uuid FK to user_connections), trigger_config (jsonb), created_at (timestamptz), updated_at (timestamptz)
// 4. flow_steps: id (uuid PK), flow_id (uuid FK to flows), position (int), connection_id (uuid FK to user_connections), action_type (text), action_config (jsonb), transform_code (text)
// 5. flow_executions: id (uuid PK), flow_id (uuid FK to flows), status (text check in 'running','completed','failed'), started_at (timestamptz), completed_at (timestamptz), steps_log (jsonb), error_message (text)
// 6. webhook_endpoints: id (uuid PK), flow_id (uuid FK to flows), token (text unique), is_active (boolean default true), last_triggered_at (timestamptz)
// Seed connectors table with 5 entries: GitHub, Slack, Stripe, Gmail, Notion with their base_urls and auth_types
// Add RLS: users see only their own connections, flows, and executions.
```

> Pro tip: Connect to GitHub via the Git panel immediately — this system has 10+ API routes and benefits from version-controlled incremental development with automatic branching.

**Expected result:** Database schema created with 6 tables, seeded connectors, and RLS policies. The schema supports OAuth2, API key, and webhook authentication types.

### 2. Build the connector marketplace and OAuth flow

Create the connector marketplace page and the OAuth2 callback handler that securely exchanges codes for tokens and encrypts them before storage.

```
// Paste this prompt into V0's AI chat:
// Build connector marketplace and OAuth:
// 1. app/connectors/page.tsx — marketplace:
//    - Grid of Card components showing each connector with icon, name, description, auth_type Badge
//    - Search Input filtering by name
//    - "Connect" Button per connector that either:
//      - Opens OAuth2 authorization URL (for oauth2 type)
//      - Opens Dialog with API key Input (for api_key type)
//    - Already-connected services show a green "Connected" Badge and "Disconnect" Button
//
// 2. app/api/oauth/[connector]/callback/route.ts:
//    - Receives code and state from OAuth provider
//    - Exchanges authorization code for access_token and refresh_token
//    - Encrypts tokens using AES-256-GCM with ENCRYPTION_KEY from env vars
//    - Stores encrypted tokens in user_connections.credentials_encrypted
//    - Sets expires_at based on token expiry
//    - Redirects to /connections with success message
//
// 3. app/connections/page.tsx — my connections:
//    - Card per connected service showing connector icon, name, status Badge, connected_at
//    - "Refresh" Button for expired OAuth tokens
//    - AlertDialog for disconnection confirmation
//    - Server Action to revoke connection (set status='revoked')
```

**Expected result:** Users browse available connectors, initiate OAuth flows, and manage their connections. Tokens are encrypted with AES-256-GCM before storage.

### 3. Build the visual flow builder

Create the flow builder page where users select a trigger, add action steps with connected services, configure data transforms, and activate the flow.

```
// Paste this prompt into V0's AI chat:
// Build a flow builder at app/flows/new/page.tsx as a 'use client' component.
// Requirements:
// - Flow name Input at the top
// - Trigger selection: Select a connected service as trigger, configure trigger event (e.g., GitHub: push, Slack: message, Stripe: payment_intent.succeeded) via Select
// - Steps list below trigger, each step as a Card showing:
//   - Step number and connection icon
//   - Select for connected service
//   - Select for action type (e.g., Slack: send_message, GitHub: create_issue)
//   - Action config: Textarea for JSON template with {{trigger.data.field}} placeholders
//   - Optional transform_code: Textarea for JavaScript transform
//   - Remove step Button (trash icon)
// - "+ Add Step" Button to append a new step
// - Sheet sidebar for step configuration details
// - "Save & Activate" Button that creates the flow, flow_steps, and if trigger is webhook, creates a webhook_endpoint with a unique token
// - Switch for flow active/inactive toggle
// - Use Card for steps, Sheet for config sidebar, Select for dropdowns, Accordion for advanced settings
```

> Pro tip: Use the {{trigger.data.field}} placeholder syntax to pass data between steps — the execution engine replaces these with actual values at runtime.

**Expected result:** Users can build multi-step flows by selecting triggers and actions from their connected services, with data transform configuration per step.

### 4. Build the execution engine and webhook handler

Create the flow execution API that runs steps sequentially with logging, and the webhook endpoint that triggers flows from external events.

```
// Paste this prompt into V0's AI chat:
// Build the execution engine and webhooks:
// 1. app/api/flows/[id]/execute/route.ts:
//    - POST handler that creates a flow_execution with status='running'
//    - Iterates through flow_steps ordered by position
//    - For each step: decrypt the connection credentials, call the external API with the action_config (replacing {{}} placeholders with trigger data), log the step result (success/failure, response data, timing) in steps_log jsonb array
//    - If a step fails: set execution status='failed', store error_message, stop execution
//    - On completion: set status='completed', completed_at=now()
//    - Return the execution result
//
// 2. app/api/webhooks/[token]/route.ts:
//    - POST handler that receives incoming webhook payloads
//    - Looks up the flow by webhook_endpoint.token
//    - Checks flow.is_active and webhook_endpoint.is_active
//    - Updates webhook_endpoint.last_triggered_at
//    - Calls the execute API with the webhook payload as trigger data
//    - Returns 200 immediately, execution runs in background
//
// 3. Create a helper lib/encryption.ts:
//    - encrypt(plaintext: string): string — AES-256-GCM with ENCRYPTION_KEY
//    - decrypt(ciphertext: string): string — decrypts back to plaintext
//    - ENCRYPTION_KEY from process.env (never NEXT_PUBLIC_)
```

**Expected result:** The execution engine runs flow steps sequentially with per-step logging. Webhook endpoints receive external events and trigger flow executions automatically.

### 5. Build the dashboard and execution logs

Create the main dashboard showing active flows and recent executions, and the execution log viewer with step-by-step results.

```
// Paste this prompt into V0's AI chat:
// Build dashboard and logs:
// 1. app/page.tsx — dashboard:
//    - Stats Cards: active flows count, connected services count, executions today, failure rate
//    - Recent executions Table: flow name, trigger source, status Badge, duration, timestamp
//    - Active flows list with quick toggle Switch per flow
//    - "Create Flow" Button linking to /flows/new
//
// 2. app/flows/[id]/page.tsx — flow detail:
//    - Flow name, description, active Switch, trigger info Card
//    - Steps list showing the flow configuration
//    - Execution history Table for this flow with status, timing, started_at
//    - "Run Now" Button that manually triggers execution
//    - Webhook URL display (if trigger type is webhook) with copy Button
//
// 3. app/flows/[id]/logs/page.tsx — execution detail:
//    - Execution header: status Badge, duration, started_at → completed_at
//    - Accordion showing each step's result: step name, connection icon, status, response data preview, timing
//    - If failed: error_message highlighted in red Card
//    - JSON viewer for step input/output data
//    - "Re-run" Button to retry the execution
```

**Expected result:** The dashboard shows active flows and recent execution status. Flow detail pages show configuration and execution history. Log pages provide step-by-step debugging.

## Complete code example

File: `lib/encryption.ts`

```typescript
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto'

const ALGORITHM = 'aes-256-gcm'
const KEY = Buffer.from(process.env.ENCRYPTION_KEY!, 'hex')

export function encrypt(plaintext: string): string {
  const iv = randomBytes(16)
  const cipher = createCipheriv(ALGORITHM, KEY, iv)
  let encrypted = cipher.update(plaintext, 'utf8', 'hex')
  encrypted += cipher.final('hex')
  const authTag = cipher.getAuthTag().toString('hex')
  return `${iv.toString('hex')}:${authTag}:${encrypted}`
}

export function decrypt(ciphertext: string): string {
  const [ivHex, authTagHex, encrypted] = ciphertext.split(':')
  const iv = Buffer.from(ivHex, 'hex')
  const authTag = Buffer.from(authTagHex, 'hex')
  const decipher = createDecipheriv(ALGORITHM, KEY, iv)
  decipher.setAuthTag(authTag)
  let decrypted = decipher.update(encrypted, 'hex', 'utf8')
  decrypted += decipher.final('utf8')
  return decrypted
}

export function generateWebhookToken(): string {
  return randomBytes(32).toString('hex')
}
```

## Common mistakes

- **Storing OAuth tokens in plain text** — Plain text tokens in the database are exposed if the database is compromised, giving attackers access to all connected third-party accounts. Fix: Encrypt all credentials with AES-256-GCM using an ENCRYPTION_KEY stored in the Vars tab, never in the database or NEXT_PUBLIC_ variables.
- **Not handling token expiration** — OAuth2 access tokens typically expire in 1-2 hours. Flows fail silently when trying to use expired tokens. Fix: Check expires_at before each API call in the execution engine. If expired, use the stored refresh_token to get a new access token automatically.
- **Running webhook handlers synchronously** — Webhook providers expect a quick 200 response. Long-running flow executions cause timeouts and retry floods. Fix: Return 200 immediately from the webhook endpoint and trigger the flow execution asynchronously in the background.
- **Not logging per-step execution results** — Without step-level logging, debugging failed flows requires guessing which step failed and why. Fix: Store a steps_log jsonb array in flow_executions with per-step status, response data, timing, and error details.

## Best practices

- Encrypt all third-party credentials with AES-256-GCM before storing in Supabase — use ENCRYPTION_KEY from env vars, never NEXT_PUBLIC_.
- Implement automatic OAuth token refresh by checking expires_at before each API call in the execution engine.
- Return 200 immediately from webhook endpoints and process flow executions asynchronously to prevent timeout issues.
- Log per-step execution results with timing, input/output data, and error details for debugging failed flows.
- Connect to GitHub via V0's Git panel immediately — the 10+ API routes benefit from version-controlled incremental development.
- Set Vercel Function timeout to 60s in vercel.json for long-running flow executions that call multiple external APIs.
- Use RLS policies to ensure users can only see their own connections, flows, and execution logs.

## Frequently asked questions

### Can I build this with the free V0 plan?

The core connector marketplace and flow builder fit within the free tier. V0 Premium is strongly recommended for the complete system with OAuth callbacks, execution engine, and logging.

### How are credentials secured?

All OAuth tokens and API keys are encrypted with AES-256-GCM before storage in Supabase. The encryption key lives in the Vars tab (never NEXT_PUBLIC_) and decryption happens only in server-side API routes.

### How do webhooks trigger flows?

Each flow with a webhook trigger gets a unique URL with a random token. External services POST to this URL. The handler validates the token, returns 200 immediately, and queues the flow execution.

### What happens when a step fails?

The execution engine stops at the failed step, records the error in the steps_log, sets the execution status to failed, and stores the error_message. Users can see exactly which step failed and why in the execution logs.

### Can I add more connectors?

Yes. Seed new rows into the connectors table with the service name, OAuth config (if applicable), and base URL. For OAuth2 services, register the callback URL and add the credentials to the Vars tab.

### How do I handle token refresh?

The execution engine checks expires_at before each API call. If the token has expired, it uses the stored refresh_token to request a new access_token, re-encrypts, and updates user_connections.

### Can RapidDev help build a custom integration platform?

Yes. RapidDev has built 600+ apps including iPaaS platforms with advanced orchestration, error handling, and enterprise-grade security. Book a free consultation to discuss your requirements.

---

Source: https://www.rapidevelopers.com/how-to-build-v0/integration-hub
© RapidDev — https://www.rapidevelopers.com/how-to-build-v0/integration-hub
