POST
/
api
/
webhooks
/
user-created
Webhook - User Created
curl --request POST \
  --url https://onlyautomator.com/api/webhooks/user-created \
  --header 'Content-Type: application/json' \
  --data '{
  "type": "INSERT",
  "table": "users",
  "schema": "auth",
  "record": {
    "id": "user-123-abc",
    "email": "user@example.com",
    "created_at": "2023-08-23T12:00:00Z"
  },
  "old_record": null
}'
{
  "success": true,
  "message": "New user processed successfully"
}

User Creation Webhook

This endpoint is a webhook that processes user creation events from Supabase. It is automatically triggered when a new user is created in the database.

Security

Authentication

This endpoint uses Supabase’s webhook signature verification for security. Each request must include a valid signature in the headers.
// Webhook signature verification
import { createHmac } from 'crypto'

const WEBHOOK_SECRET = process.env.SUPABASE_WEBHOOK_SECRET

export function verifyWebhookSignature(
  payload: string,
  signature: string
): boolean {
  const hmac = createHmac('sha256', WEBHOOK_SECRET)
  const computedSignature = hmac.update(payload).digest('hex')
  return computedSignature === signature
}

Required Headers

x-supabase-signature: SHA256 hash of the payload
content-type: application/json

Request Body

type
string
required
Operation type. Must be “INSERT” for user creation.
table
string
required
Table name. Must be “users”.
schema
string
required
Database schema. Must be “auth”.
record
object
required
New user data
old_record
object
Previous data (null for an insert)

Implementation

Webhook Handler

import { NextApiRequest, NextApiResponse } from 'next'
import { createClient } from '@supabase/supabase-js'
import { verifyWebhookSignature } from '../../../lib/webhooks'

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.SUPABASE_SERVICE_ROLE_KEY!
)

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  // Verify request method
  if (req.method !== 'POST') {
    return res.status(405).json({ message: 'Method not allowed' })
  }

  // Verify signature
  const signature = req.headers['x-supabase-signature']
  if (!signature || !verifyWebhookSignature(JSON.stringify(req.body), signature as string)) {
    return res.status(401).json({ message: 'Invalid signature' })
  }

  try {
    const { type, record } = req.body

    // Verify event type
    if (type !== 'INSERT') {
      return res.status(400).json({ 
        success: false,
        message: 'Invalid data: unsupported operation type' 
      })
    }

    // Process the new user
    await processNewUser(record)

    return res.status(200).json({
      success: true,
      message: 'New user processed successfully'
    })
  } catch (error) {
    console.error('Webhook error:', error)
    return res.status(500).json({
      success: false,
      message: 'Internal server error'
    })
  }
}

async function processNewUser(userData: any) {
  // 1. Create user profile
  await supabase
    .from('profiles')
    .insert({
      id: userData.id,
      email: userData.email,
      full_name: userData.raw_user_meta_data?.full_name
    })

  // 2. Send welcome email
  await sendWelcomeEmail(userData.email)

  // 3. Initialize settings
  await initializeUserSettings(userData.id)

  // 4. Record analytics event
  await recordAnalyticsEvent('user_created', {
    user_id: userData.id,
    timestamp: new Date().toISOString()
  })
}

## Triggered Actions

When a new user is created, this webhook automatically performs the following actions:

1. **User Profile Creation**
   - Creates an associated profile in the `profiles` table
   - Initializes default user preferences

2. **Welcome Email**
   - Sends a personalized welcome email via Resend
   - Includes getting started guide and next steps

3. **Marketing Platform Sync**
   - Adds user to Resend audience for marketing communications
   - Tags user based on signup source and preferences

4. **Account Setup**
   - Initializes default account settings
   - Creates necessary database records for the user

5. **Analytics**
   - Records the signup event in our analytics system
   - Tracks user attribution data if available

## Error Handling

The webhook implements comprehensive error handling:

```typescript
try {
  // Process webhook
} catch (error) {
  // Log error details
  console.error('Webhook error:', {
    error,
    timestamp: new Date().toISOString(),
    payload: req.body
  })

  // Determine error type and return appropriate response
  if (error.code === 'P2002') {
    return res.status(409).json({
      success: false,
      message: 'User already exists'
    })
  }

  // Default error response
  return res.status(500).json({
    success: false,
    message: 'Internal server error'
  })
}

Testing

Local Testing

# Start local development server
npm run dev

# Test webhook with curl
curl -X POST http://localhost:3000/api/webhooks/user-created \
  -H "Content-Type: application/json" \
  -H "x-supabase-signature: YOUR_TEST_SIGNATURE" \
  -d '{
    "type": "INSERT",
    "table": "users",
    "schema": "auth",
    "record": {
      "id": "test-user-id",
      "email": "test@example.com",
      "created_at": "2024-04-02T12:00:00Z"
    }
  }'

Production URLs

  • Development: http://localhost:3000/api/webhooks/user-created
  • Production: https://onlyautomator.com/api/webhooks/user-created

Notes

  • This webhook is designed to be called automatically by Supabase
  • Manual calls should only be made for testing purposes
  • All webhook calls are logged for monitoring and debugging
  • Failed webhook calls are automatically retried by Supabase

Body

application/json
type
string
required

Operation type. Must be "INSERT" for user creation.

Example:

"INSERT"

table
string
required

Table name. Must be "users".

Example:

"users"

schema
string
required

Database schema. Must be "auth".

Example:

"auth"

record
object
required

New user data

old_record
object | null

Previous data (null for an insert)

Example:

null

Response

Operation successful

success
boolean
Example:

true

message
string
Example:

"New user processed successfully"