Complete guide to setting up, configuring, and using your Secure Backend API.
Get the project files on your server or local machine.
git clone your-repository-url
cd project-directory
npm install
cp .env.example .env
nano .env # or your preferred editor
# Development
npm run dev
# Production
npm start
| Variable | Description | Example |
|---|---|---|
PORT |
Server port | 3000 |
NODE_ENV |
Environment | production |
ALLOWED_ORIGINS |
CORS origins (comma-separated) | https://yoursite.com |
ALLOWED_DOMAINS |
Domain patterns (comma-separated) | yoursite.com,*.yoursite.com |
| Variable | Description |
|---|---|
N8N_WEBHOOK_URL |
Your n8n webhook endpoint |
OAUTH_CLIENT_ID |
OAuth2 client ID (if using auth) |
OAUTH_CLIENT_SECRET |
OAuth2 client secret |
OAUTH_TOKEN_URL |
OAuth2 token endpoint |
| Variable | Description |
|---|---|
ENABLE_IP_WHITELIST |
Enable IP filtering (true/false) |
ALLOWED_IPS |
Comma-separated IP addresses |
project/
├── config/ # Configuration management
│ └── index.js # Centralized config from env vars
├── controllers/ # Request handlers
│ ├── contactController.js
│ └── businessContactController.js
├── middleware/ # Express middleware
│ ├── domainCors.js # CORS by domain
│ ├── errorHandler.js # Global error handling
│ ├── ipWhitelist.js # IP filtering
│ ├── requestLogger.js # Request/response logging
│ └── validateRequest.js # Input validation
├── routes/ # API route definitions
│ ├── index.js # Main router
│ └── forms.js # Form endpoints
├── services/ # Business logic
│ ├── formService.js
│ └── n8nService.js
├── utils/ # Helper functions
│ ├── logger.js
│ ├── oauth.js
│ └── RestClient.js
├── validation/ # Schema validation
│ ├── schemas.js
│ └── middleware.js
├── views/ # HTML pages
│ ├── components/
│ └── pages/
└── index.js # Application entry point
Add your schema to validation/schemas.js:
const myNewSchema = Joi.object({
field1: Joi.string().required().min(2).max(100),
field2: Joi.string().email().required(),
field3: Joi.number().optional().min(0)
});
Create services/myService.js for business logic:
const processMyData = async (data) => {
// Your business logic here
const processedData = {
...data,
timestamp: new Date().toISOString()
};
return processedData;
};
module.exports = { processMyData };
Create controllers/myController.js:
const { processMyData } = require('../services/myService');
const { sendToN8n } = require('../services/n8nService');
const handleMyRequest = async (req, res, next) => {
try {
const processedData = await processMyData(req.body);
// Optional: Send to n8n
if (process.env.N8N_WEBHOOK_URL) {
await sendToN8n('my_data_type', processedData, req);
}
res.json({
success: true,
data: processedData,
debugId: req.debugId
});
} catch (error) {
next(error);
}
};
module.exports = { handleMyRequest };
Add to routes/index.js or create new route file:
const express = require('express');
const router = express.Router();
const { validateRequest } = require('../validation/middleware');
const { myNewSchema } = require('../validation/schemas');
const { handleMyRequest } = require('../controllers/myController');
router.post('/my-endpoint',
validateRequest(myNewSchema),
handleMyRequest
);
module.exports = router;
In routes/index.js, mount your router:
const myRoutes = require('./myRoutes');
router.use('/my', myRoutes);
/api/my/my-endpoint
Scenario: Receive contact form submissions from your website and forward to email/CRM.
Endpoints Used: POST /api/forms/contact
Scenario: Capture qualified business leads with detailed information.
Endpoints Used: POST /api/forms/business-contact
Scenario: Collect email addresses for marketing campaigns.
Implementation: Create custom endpoint following "Adding New APIs" guide
Scenario: Secure access to third-party APIs without exposing credentials.
Benefits: Hide API keys, add caching, implement rate limits
Scenario: Receive webhooks from external services (Stripe, GitHub, etc.)
Implementation: Disable CORS for webhook endpoint, add signature validation
Add this code to your Framer site to submit forms to the backend:
async function handleSubmit(event) {
event.preventDefault();
const formData = {
name: event.target.name.value,
email: event.target.email.value,
subject: event.target.subject.value,
message: event.target.message.value,
consent: true
};
try {
const response = await fetch('https://your-backend.com/api/forms/contact', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData)
});
const result = await response.json();
if (result.success) {
// Show success message
console.log('Form submitted:', result.data.referenceId);
} else {
// Show error message
console.error('Error:', result.error.message);
}
} catch (error) {
console.error('Network error:', error);
}
}
const businessData = {
name: "John Smith",
email: "john@company.com",
phone: "+1-555-0123",
businessName: "Acme Corp",
businessType: "corporation",
websiteUrl: "https://acme.com",
message: "Interested in partnership",
urgency: "medium",
consent: true
};
const response = await fetch('https://your-backend.com/api/forms/business-contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(businessData)
});
.env file as N8N_WEBHOOK_URL
The backend sends this structure to n8n:
{
"type": "contact_form",
"referenceId": "CONTACT-1698765432000",
"debugId": "1698765432000-a1b2c3d4",
"timestamp": "2025-10-26T10:30:32.000Z",
"data": {
"name": "John Doe",
"email": "john@example.com",
"subject": "Question",
"message": "Hello..."
},
"metadata": {
"ip": "192.168.1.1",
"origin": "https://yoursite.com",
"userAgent": "Mozilla/5.0..."
}
}
Solution: Add your Framer site URL to ALLOWED_ORIGINS in .env
ALLOWED_ORIGINS=https://your-framer-site.framer.app
Solution: Ensure all required fields are included in your request. Check the API documentation for each endpoint's required fields.
Solution:
N8N_WEBHOOK_URL is correct in .envSolution: Wait for the rate limit window to expire (typically 15 minutes to 1 hour) or contact the administrator to adjust rate limits.
Enable debug logging for detailed information:
ENABLE_DEBUG_LOGGING=true
Every response includes a debugId. Use it to search server logs:
grep "1698765432000-a1b2c3d4" logs/*.log
Check the full documentation or review server logs for detailed error information.