Form submission URL: https://lzxtmoeysjiohyc.form.io/treeplenishtest
A Next.js webhook service that receives form submissions from Form.io and stores them in a Supabase database. Optimized for deployment on Vercel.
- Next.js API routes for serverless deployment
- Receives POST requests from Form.io form submissions
- Automatically creates or updates school records in Supabase
- Creates event records linked to schools
- Error handling and validation
- Built-in CORS support
- Health check endpoint
- Node.js (v18 or higher recommended)
- A Supabase account and project
- A Form.io account with a form set up
- A Vercel account (for deployment)
- Clone the repository:
git clone https://github.com/tree-plenish/fillout_mock_1.git
cd fillout_mock_1- Install dependencies:
npm install- Create a
.env.localfile based on.env.local.example:
cp .env.local.example .env.local- Update the
.env.localfile with your Supabase credentials:
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_KEY=your-service-key-here
- Go to your Supabase Dashboard
- Select your project
- Go to Settings > API
- Copy the Project URL (this is your
SUPABASE_URL) - Copy the service_role key (this is your
SUPABASE_SERVICE_KEY)- Important: Use the service role key, not the anon key, as the service role has full permissions
npm run devThe app will start on http://localhost:3000
npm run build
npm start- Push your code to GitHub
- Go to Vercel and sign in
- Click "Add New Project"
- Import your GitHub repository
- Add environment variables:
SUPABASE_URL: Your Supabase project URLSUPABASE_SERVICE_KEY: Your Supabase service role key
- Click "Deploy"
- Install Vercel CLI:
npm install -g vercel- Login to Vercel:
vercel login- Deploy:
vercel- Add environment variables:
vercel env add SUPABASE_URL
vercel env add SUPABASE_SERVICE_KEY- Redeploy with environment variables:
vercel --prod- Log in to your Form.io account
- Open your form at https://lzxtmoeysjiohyc.form.io/treeplenishtest
- Go to Actions or Webhooks settings
- Add a new webhook with the URL:
- For Vercel:
https://your-app.vercel.app/api/webhook/formio - For local testing with ngrok:
https://your-ngrok-url.ngrok.io/api/webhook/formio
- For Vercel:
For local testing, use ngrok to create a public URL:
ngrok http 3000Then use the ngrok URL in Form.io: https://your-ngrok-url.ngrok.io/api/webhook/formio
Receives form submission data from Form.io and stores it in Supabase.
Expected Form.io Fields:
schoolName- Name of the schoolcity- Citystate- StateschoolContactEmail- Contact emailtypeOfSchool- Type of school (not stored, for reference only)address- Address (not stored, for reference only)zipPostalCode- ZIP/Postal code (not stored, for reference only)schoolContactName- Contact name (not stored, for reference only)role- Role (not stored, for reference only)preferredEventDatesOrTimeline- Event start dateendDate- Event end datetypeOfEvent- Type of eventestimatedNumberOfTreesToPlant- Estimated number of trees
Mapped to Supabase:
- Schools:
name,city,state,contact_email - Events:
title,goal_trees,event_date,description
Response:
{
"success": true,
"data": {
"school": { ... },
"event": { ... }
}
}Health check endpoint to verify the service is running.
Response:
{
"status": "ok",
"timestamp": "2025-10-21T12:00:00.000Z",
"service": "Form.io to Supabase Webhook"
}fillout_mock_1/
├── app/
│ ├── api/
│ │ ├── health/
│ │ │ └── route.js # Health check endpoint
│ │ └── webhook/
│ │ └── formio/
│ │ └── route.js # Form.io webhook endpoint
│ ├── layout.js # Root layout
│ └── page.js # Home page
├── lib/
│ └── supabase.js # Supabase client & utilities
├── .env.local.example # Environment variables template
├── .gitignore
├── next.config.js # Next.js configuration
├── package.json
├── README.md
└── vercel.json # Vercel deployment config
The service interacts with two main tables in Supabase:
id(int8) - Primary keyname(varchar) - School namecity(varchar) - Citystate(varchar) - Statecountry(varchar) - Countrycontact_email(varchar) - Contact emaillongitude(float8) - Longitude coordinate (optional)latitude(float8) - Latitude coordinate (optional)total_trees_planted(int4) - Total trees planted across all eventstrees_planted_this_year(int4) - Trees planted this yearparticipated_years(int2) - Number of years participatedowner_id(int8) - User ID of school owner (optional)created_at(timestamptz) - Creation timestamp
Note: The webhook populates name, city, state, country, and contact_email. Other fields like total_trees_planted are calculated/updated by other processes.
id(int8) - Primary keytitle(varchar) - Event titleschool_id(int8) - Foreign key to schoolsgoal_trees(int4) - Target number of treestrees_planted(int4) - Actual number of trees planted (defaults to 0)event_date(date) - Event datedescription(text) - Event descriptionpickup(bool) - Whether pickup is available (defaults to false)created_at(timestamptz) - Creation timestamp
- Form.io sends a POST request to
/api/webhook/formiowhen a form is submitted - The service extracts the form data from the
submission.dataobject - Maps Form.io fields to the expected Supabase schema
- It checks if a school with the same name and city exists:
- If yes: Updates the existing school record
- If no: Creates a new school record
- Creates a new event record linked to the school
- Returns a success response with the created/updated records
The service includes comprehensive error handling:
- Invalid form data structure returns a 400 error
- Database errors are logged and return a 500 error
- All errors include descriptive messages in the response
You can test the webhook using curl with Form.io's payload structure:
curl -X POST https://your-app.vercel.app/api/webhook/formio \
-H "Content-Type: application/json" \
-d '{
"request": {},
"submission": {
"data": {
"schoolName": "Green Valley High",
"city": "Springfield",
"state": "CA",
"schoolContactEmail": "[email protected]",
"typeOfEvent": "Tree Planting Day",
"estimatedNumberOfTreesToPlant": "100",
"preferredEventDatesOrTimeline": "2025-11-15",
"endDate": "2025-11-15"
}
},
"params": {}
}'For local testing:
curl -X POST http://localhost:3000/api/webhook/formio \
-H "Content-Type: application/json" \
-d '{ ... }'- All webhook requests are logged to the console
- Successful submissions log school and event IDs
- Errors are logged with detailed messages
- On Vercel, logs can be viewed in the Vercel Dashboard under the "Logs" tab
| Variable | Description | Required |
|---|---|---|
SUPABASE_URL |
Your Supabase project URL | Yes |
SUPABASE_SERVICE_KEY |
Your Supabase service role key | Yes |
.env.localis gitignored to prevent exposing credentials- Use the Supabase service role key for full database access
- Vercel automatically provides HTTPS
- Consider adding webhook signature verification for additional security
- Environment variables are securely stored in Vercel
- Serverless: Automatically scales with traffic
- Global CDN: Fast response times worldwide
- Zero configuration: No server setup required
- Automatic HTTPS: SSL certificates included
- Environment variables: Secure credential storage
- Instant deployments: Deploy with git push
- Check that all dependencies are installed:
npm install - Verify your
.env.localfile has the correct Supabase credentials - Ensure you're using Node.js v18 or higher
- Verify the webhook URL in Form.io settings
- Check the Vercel logs for incoming requests
- Ensure the form field names match the expected Form.io field keys
- Verify your Supabase credentials are correct
- Check that the tables exist in your Supabase project
- Ensure the service role key has the necessary permissions
- Check Vercel logs for detailed error messages
- Ensure environment variables are set in Vercel
- Check the build logs in Vercel dashboard
- Verify your
next.config.jsis properly configured
For issues or questions:
- Check the Next.js documentation
- Check the Vercel documentation
- Check the Supabase documentation
- Open an issue on GitHub
ISC