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.
What you're building
An integration hub lets users connect third-party services and create automated data flows between them. Users connect services like Slack, GitHub, and Stripe, then build flows that trigger on events and execute actions across connected services.
V0 generates the connector marketplace, flow builder UI, and execution dashboard from prompts. Supabase stores connector configurations, encrypted credentials, flow definitions, and execution logs.
The architecture uses Next.js App Router with API routes for OAuth callbacks and webhook endpoints, a client component for the interactive flow builder, Server Actions for flow management, AES-256-GCM encryption for third-party tokens stored in Supabase, and a sequential execution engine with per-step logging.
Final result
An integration hub with connector marketplace, OAuth connection management, visual flow builder, webhook triggers, sequential execution engine, and detailed execution logging.
Tech stack
Prerequisites
- 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)
Build steps
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.
1// Paste this prompt into V0's AI chat:2// Build an integration hub. Create a Supabase schema with:3// 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)4// 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)5// 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)6// 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)7// 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)8// 6. webhook_endpoints: id (uuid PK), flow_id (uuid FK to flows), token (text unique), is_active (boolean default true), last_triggered_at (timestamptz)9// Seed connectors table with 5 entries: GitHub, Slack, Stripe, Gmail, Notion with their base_urls and auth_types10// 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.
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.
1// Paste this prompt into V0's AI chat:2// Build connector marketplace and OAuth:3// 1. app/connectors/page.tsx — marketplace:4// - Grid of Card components showing each connector with icon, name, description, auth_type Badge5// - Search Input filtering by name6// - "Connect" Button per connector that either:7// - Opens OAuth2 authorization URL (for oauth2 type)8// - Opens Dialog with API key Input (for api_key type)9// - Already-connected services show a green "Connected" Badge and "Disconnect" Button10//11// 2. app/api/oauth/[connector]/callback/route.ts:12// - Receives code and state from OAuth provider13// - Exchanges authorization code for access_token and refresh_token14// - Encrypts tokens using AES-256-GCM with ENCRYPTION_KEY from env vars15// - Stores encrypted tokens in user_connections.credentials_encrypted16// - Sets expires_at based on token expiry17// - Redirects to /connections with success message18//19// 3. app/connections/page.tsx — my connections:20// - Card per connected service showing connector icon, name, status Badge, connected_at21// - "Refresh" Button for expired OAuth tokens22// - AlertDialog for disconnection confirmation23// - 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.
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.
1// Paste this prompt into V0's AI chat:2// Build a flow builder at app/flows/new/page.tsx as a 'use client' component.3// Requirements:4// - Flow name Input at the top5// - Trigger selection: Select a connected service as trigger, configure trigger event (e.g., GitHub: push, Slack: message, Stripe: payment_intent.succeeded) via Select6// - Steps list below trigger, each step as a Card showing:7// - Step number and connection icon8// - Select for connected service9// - Select for action type (e.g., Slack: send_message, GitHub: create_issue)10// - Action config: Textarea for JSON template with {{trigger.data.field}} placeholders11// - Optional transform_code: Textarea for JavaScript transform12// - Remove step Button (trash icon)13// - "+ Add Step" Button to append a new step14// - Sheet sidebar for step configuration details15// - "Save & Activate" Button that creates the flow, flow_steps, and if trigger is webhook, creates a webhook_endpoint with a unique token16// - Switch for flow active/inactive toggle17// - Use Card for steps, Sheet for config sidebar, Select for dropdowns, Accordion for advanced settingsPro 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.
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.
1// Paste this prompt into V0's AI chat:2// Build the execution engine and webhooks:3// 1. app/api/flows/[id]/execute/route.ts:4// - POST handler that creates a flow_execution with status='running'5// - Iterates through flow_steps ordered by position6// - 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 array7// - If a step fails: set execution status='failed', store error_message, stop execution8// - On completion: set status='completed', completed_at=now()9// - Return the execution result10//11// 2. app/api/webhooks/[token]/route.ts:12// - POST handler that receives incoming webhook payloads13// - Looks up the flow by webhook_endpoint.token14// - Checks flow.is_active and webhook_endpoint.is_active15// - Updates webhook_endpoint.last_triggered_at16// - Calls the execute API with the webhook payload as trigger data17// - Returns 200 immediately, execution runs in background18//19// 3. Create a helper lib/encryption.ts:20// - encrypt(plaintext: string): string — AES-256-GCM with ENCRYPTION_KEY21// - decrypt(ciphertext: string): string — decrypts back to plaintext22// - 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.
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.
1// Paste this prompt into V0's AI chat:2// Build dashboard and logs:3// 1. app/page.tsx — dashboard:4// - Stats Cards: active flows count, connected services count, executions today, failure rate5// - Recent executions Table: flow name, trigger source, status Badge, duration, timestamp6// - Active flows list with quick toggle Switch per flow7// - "Create Flow" Button linking to /flows/new8//9// 2. app/flows/[id]/page.tsx — flow detail:10// - Flow name, description, active Switch, trigger info Card11// - Steps list showing the flow configuration12// - Execution history Table for this flow with status, timing, started_at13// - "Run Now" Button that manually triggers execution14// - Webhook URL display (if trigger type is webhook) with copy Button15//16// 3. app/flows/[id]/logs/page.tsx — execution detail:17// - Execution header: status Badge, duration, started_at → completed_at18// - Accordion showing each step's result: step name, connection icon, status, response data preview, timing19// - If failed: error_message highlighted in red Card20// - JSON viewer for step input/output data21// - "Re-run" Button to retry the executionExpected 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
1import { createCipheriv, createDecipheriv, randomBytes } from 'crypto'23const ALGORITHM = 'aes-256-gcm'4const KEY = Buffer.from(process.env.ENCRYPTION_KEY!, 'hex')56export function encrypt(plaintext: string): string {7 const iv = randomBytes(16)8 const cipher = createCipheriv(ALGORITHM, KEY, iv)9 let encrypted = cipher.update(plaintext, 'utf8', 'hex')10 encrypted += cipher.final('hex')11 const authTag = cipher.getAuthTag().toString('hex')12 return `${iv.toString('hex')}:${authTag}:${encrypted}`13}1415export function decrypt(ciphertext: string): string {16 const [ivHex, authTagHex, encrypted] = ciphertext.split(':')17 const iv = Buffer.from(ivHex, 'hex')18 const authTag = Buffer.from(authTagHex, 'hex')19 const decipher = createDecipheriv(ALGORITHM, KEY, iv)20 decipher.setAuthTag(authTag)21 let decrypted = decipher.update(encrypted, 'hex', 'utf8')22 decrypted += decipher.final('utf8')23 return decrypted24}2526export function generateWebhookToken(): string {27 return randomBytes(32).toString('hex')28}Customization ideas
Add conditional branching
Let users add IF/ELSE conditions between steps that route execution based on previous step output values.
Add retry logic
Configure per-step retry policies with exponential backoff for failed API calls, with a maximum retry count.
Add flow templates
Offer pre-built flow templates (GitHub PR to Slack notification, Stripe payment to email) that users can import and customize.
Add rate limiting
Track API calls per connection and enforce rate limits to prevent exceeding third-party API quotas.
Add scheduled triggers
Let users configure flows to run on a schedule (every hour, daily) using Vercel Cron jobs instead of webhook triggers.
Common pitfalls
Pitfall: Storing OAuth tokens in plain text
How to avoid: Encrypt all credentials with AES-256-GCM using an ENCRYPTION_KEY stored in the Vars tab, never in the database or NEXT_PUBLIC_ variables.
Pitfall: Not handling token expiration
How to avoid: 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.
Pitfall: Running webhook handlers synchronously
How to avoid: Return 200 immediately from the webhook endpoint and trigger the flow execution asynchronously in the background.
Pitfall: Not logging per-step execution results
How to avoid: 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.
AI prompts to try
Copy these prompts to build this project faster.
I'm building an integration hub with Next.js and Supabase. I need to securely store OAuth2 tokens: encrypt with AES-256-GCM before insertion, decrypt only in server-side API routes, and implement automatic token refresh when access tokens expire. Show me the encryption utility, the OAuth callback handler, and the token refresh middleware.
Build the flow builder interface for an integration hub. Create a 'use client' component where users: 1) Name the flow with an Input. 2) Select a trigger connection and event from Select dropdowns. 3) Add action steps as Card components, each with a connection Select, action_type Select, and Textarea for JSON configuration with {{trigger.data.field}} placeholders. 4) Reorder steps by position. 5) Save with a Server Action that creates flow + flow_steps + webhook_endpoint rows. Include a Switch for active toggle.
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.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation