A reference implementation of an enterprise-style Sales Management API, built entirely on n8n workflows.
Demonstrates production patterns: authentication, rate limiting, idempotency, atomic transactions, and observability β without writing a single line of backend server code.
About β’ Quick Start β’ Architecture β’ API Reference β’ Security Patterns β’ Deployment
This repository is a portfolio piece demonstrating how far n8n can be pushed as a backend platform. It is a fully functional reference implementation β every endpoint works, every validation runs, every workflow is wired end-to-end β but it has not been deployed to serve real users in production.
It exists to showcase a specific set of skills:
- Designing REST APIs with proper auth, rate limiting, and idempotency
- Modeling atomic database transactions for inventory + sales flows
- Composing observability and operational tooling (health checks, logging, backups)
- Architecting layered security (defense in depth)
- Documenting an API to a level where a third party could integrate against it
If you are evaluating this repo for hiring or collaboration purposes, the code, workflow, and documentation here represent how I approach backend design problems. Happy to walk through any design decision in detail.
Enterprise Sales transforms n8n from a simple automation tool into a structured REST API backend. It exposes webhook endpoints that handle the full lifecycle of a sales operation β from user authentication to invoice generation β while enforcing rate limiting, idempotency, input sanitization, and atomic database transactions.
| Conventional Approach | This Reference Implementation |
|---|---|
| Months building a custom Express/FastAPI backend | A single n8n workflow handles HTTP routing & orchestration |
| Writing auth middleware from scratch | Supabase Auth with JWT validation, wired through n8n nodes |
| Manual rate limiting implementation | Redis-backed rate limiting per IP + User-Agent |
| Custom idempotency layer | Redis SETNX with 24h TTL |
| Boilerplate transaction handling | PostgreSQL stored function for atomic sale + inventory update |
- Supabase Auth integration with JWT-based access & refresh tokens
- Role-based access control (
admin,seller, custom roles) - Multi-tenant support via
company_idscoping - CORS configuration with environment-driven allowed origins
- Redis-powered rate limiting β 5 requests/minute per IP + User-Agent fingerprint
- Idempotency keys β prevent duplicate sale creation with Redis
SETNX+ 24h TTL - Input sanitization β HTML/SQL injection protection on all user-supplied strings
- Parameterized SQL β zero raw string interpolation in database queries
- Request validation β strict type checking, range enforcement, format validation
- HTTP timeouts β 10s timeouts on all external service calls
- Atomic sale creation with PostgreSQL stored function (
create_sale_with_inventory_update) - Real-time inventory verification with row-level locking (
SELECT ... FOR UPDATE) - Race condition detection with HTTP 409 responses
- Automatic tax calculation with configurable tax rates
- Auto-generated invoice numbers (
F-YYYY-XXXXXX-XXX) - Validation for up to 100 line items per sale, quantities up to 10,000 units
- Paginated sales queries with date range filtering (up to 10,000 records)
- Excel/PDF export via CloudConvert API integration
- Async report generation with execution job tracking
- Health check endpoint β monitors PostgreSQL + Redis connectivity
- Scheduled backup workflow β
pg_dumpon cron, with audit logging tobackup_logstable - Centralized error logging β failures forwarded to Datadog for observability
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CLIENT APPLICATION β
β (Web App / Mobile / cURL) β
ββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β HTTPS
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β n8n WORKFLOW ENGINE β
β β
β βββββββββββββββ βββββββββββββββ ββββββββββββ ββββββββββββββββ β
β β /api/auth β β /api/sales β β /api/ β β /api/health β β
β β /login β β (POST) β β reports/ β β (GET) β β
β β (POST) β β β β sales β β β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββ¬ββββββ ββββββββ¬ββββββββ β
β β β β β β
β ββββββββΌββββββββ ββββββββΌββββββββ ββββββΌββββββ ββββββββΌβββββββββ
β β Validate β β Validate β β Validate β β Check ββ
β β Input β β Token β β Token β β Services ββ
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββ¬ββββββ βββββββββββββββββ
β β β β β
β ββββββββΌββββββββ ββββββββΌββββββββ β β
β β Rate Limit β β Idempotency β β β
β β (Redis) β β (Redis) β β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ β β
β β β β β
β ββββββββΌββββββββ ββββββββΌββββββββ ββββββΌββββββ β
β β Supabase β β Inventory β β Query β β
β β Auth β β Verification β β + Export β β
β ββββββββββββββββ ββββββββ¬ββββββββ ββββββββββββ β
β β β
β ββββββββΌββββββββ β
β β Atomic β β
β β Transaction β β
β β (PL/pgSQL) β β
β ββββββββββββββββ β
ββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββΌβββββββββββββββββββ
β β β
βββββββΌβββββββ ββββββββΌβββββββ βββββββββΌβββββββ
β PostgreSQL β β Redis β β Supabase β
β (Data) β β (Cache/ β β (Auth) β
β β β Rate Limit)β β β
βββββββββββββββ βββββββββββββββ ββββββββββββββββ
| Pipeline | Trigger | Key Nodes | Purpose |
|---|---|---|---|
| Auth Login | POST /api/auth/login |
Validate Input β Redis Rate Limit β Supabase Auth β Process Auth | Authenticate users, return JWT |
| Create Sale | POST /api/sales |
Validate Token β Supabase Verify β Redis Idempotency β Verify Inventory β Process Sale β Atomic Transaction | Create a new sale with inventory update |
| Sales Report | GET /api/reports/sales |
Validate Token β Supabase Verify β PostgreSQL Query β CloudConvert Export | Generate & export sales reports |
| Health Check | GET /api/health |
PostgreSQL Ping β Redis Ping β Aggregate Status | Monitor infrastructure health |
| Scheduled Backup | Cron 0 2 * * * |
Execute pg_dump β Log Backup | Database backup workflow |
| Service | Minimum Version | Purpose |
|---|---|---|
| n8n | v1.0+ | Workflow engine |
| PostgreSQL | 14+ | Primary data store |
| Redis | 6+ | Rate limiting & idempotency cache |
| Supabase | Free tier | Authentication provider |
git clone https://github.com/iarturo/enterprise-sales-api.git
cd enterprise-sales-api-- Create the database
CREATE DATABASE ventas_enterprise;
CREATE USER ventas_app WITH PASSWORD 'your_secure_password';
GRANT ALL PRIVILEGES ON DATABASE ventas_enterprise TO ventas_app;Then run the stored function required for atomic sale transactions:
-- File: Function.txt
-- Creates the `create_sale_with_inventory_update` PL/pgSQL function
-- Handles inventory locking, stock validation, and sale insertion atomically
\i Function.txtSet the following environment variables in your n8n instance:
# ββ Supabase ββββββββββββββββββββββββββββββββββββββ
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=your-anon-key
# ββ Database ββββββββββββββββββββββββββββββββββββββ
DB_HOST=localhost
DB_USER=postgres
DB_NAME=ventas_enterprise
DB_PASSWORD=your-db-password
# ββ Monitoring ββββββββββββββββββββββββββββββββββββ
DATADOG_API_KEY=your-datadog-api-key
# ββ Business Logic ββββββββββββββββββββββββββββββββ
TAX_RATE=0.16
PAYMENT_METHODS=cash,card,transfer,check
FRONTEND_URL=https://app.yourdomain.com
# ββ Reporting (Optional) βββββββββββββββββββββββββ
CLOUDCONVERT_API_KEY=your-cloudconvert-key- Open your n8n instance
- Click Import from file
- Select
enterprise-sales.json - Assign credentials to each node group:
- PostgreSQL nodes β your PostgreSQL credential
- Redis nodes β your Redis credential
- Supabase HTTP nodes β Header Auth credential
- CloudConvert nodes β Header Auth credential
- Datadog nodes β Header Auth credential
- Toggle the workflow to Active β
-- In the Supabase SQL Editor:
INSERT INTO auth.users (email, encrypted_password, email_confirmed_at, created_at, updated_at)
VALUES ('admin@yourcompany.com', crypt('strong_password_here', gen_salt('bf')), NOW(), NOW(), NOW());
UPDATE auth.users
SET raw_user_meta_data = '{"role": "admin", "company_id": 1, "profile": {"name": "Admin User"}}'
WHERE email = 'admin@yourcompany.com';Authenticate a user and receive JWT tokens.
Request:
curl -X POST https://your-n8n.com/webhook/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "admin@yourcompany.com",
"password": "strong_password_here"
}'Response 200 OK:
{
"success": true,
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "admin@yourcompany.com",
"role": "admin",
"company_id": 1,
"profile": { "name": "Admin User" }
},
"tokens": {
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "v1.MjQ1NjM4..."
},
"expiresIn": 3600
}Error Responses:
| Status | Code | Description |
|---|---|---|
400 |
Bad Request | Missing or invalid email/password format |
401 |
Unauthorized | Invalid credentials |
429 |
Too Many Requests | Rate limit exceeded (5 req/min) |
Create a new sale with automatic inventory management.
Headers:
| Header | Required | Description |
|---|---|---|
Authorization |
β | Bearer <access_token> |
Idempotency-Key |
β | Unique UUID to prevent duplicate submissions |
Content-Type |
β | application/json |
Request:
curl -X POST https://your-n8n.com/webhook/api/sales \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-d '{
"customer_info": {
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "+1-555-123-4567"
},
"items": [
{ "product_id": 1, "quantity": 2, "unit_price": 49.99 },
{ "product_id": 5, "quantity": 1, "unit_price": 129.00 }
],
"payment_method": "card"
}'Response 200 OK:
{
"success": true,
"invoiceNumber": "F-2026-847293-042",
"totalAmount": 228.98,
"message": "Sale registered successfully"
}Validation Constraints:
| Field | Rule |
|---|---|
items |
1β100 items per sale |
items[].quantity |
1β10,000 units |
items[].unit_price |
$0.01β$1,000,000 |
customer_info.name |
Required, max 255 chars, sanitized |
customer_info.email |
Optional, validated format |
payment_method |
One of: cash, card, transfer, check (configurable) |
Error Responses:
| Status | Code | Description |
|---|---|---|
400 |
Bad Request | Validation error or insufficient inventory |
401 |
Unauthorized | Missing or invalid token |
409 |
Conflict | Idempotency key already processed / Race condition detected |
Retrieve paginated sales data with optional date filtering.
Query Parameters:
| Parameter | Default | Description |
|---|---|---|
company_id |
1 |
Company scope |
start_date |
30 days ago | ISO date YYYY-MM-DD |
end_date |
Today | ISO date YYYY-MM-DD |
limit |
1000 |
Max 10000 |
offset |
0 |
Pagination offset |
Request:
curl "https://your-n8n.com/webhook/api/reports/sales?start_date=2026-01-01&end_date=2026-05-21&limit=50" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Check the status of all infrastructure dependencies.
Request:
curl https://your-n8n.com/webhook/api/healthResponse 200 OK:
{
"status": "healthy",
"timestamp": "2026-05-21T18:43:00.000Z",
"services": {
"database": { "status": "healthy" },
"redis": { "status": "healthy" }
}
}This implementation applies defense-in-depth across multiple layers:
Request βββΆ Rate Limiting βββΆ Input Validation βββΆ JWT Verification βββΆ Idempotency βββΆ Business Logic
(Redis) (Regex + Type) (Supabase) (Redis SETNX) (Parameterized SQL)
| Layer | Mechanism | Details |
|---|---|---|
| Rate Limiting | Redis INCR + EXPIRE | 5 req/min per IP + User-Agent fingerprint |
| Input Validation | Regex + type assertions | Email format, numeric ranges, string sanitization |
| Authentication | Supabase Auth | JWT token validation via Supabase /auth/v1/user |
| Idempotency | Redis SETNX | Atomic set-if-not-exists with 24h TTL |
| SQL Injection | Parameterized queries | All queries use $1, $2, ... placeholders |
| XSS Prevention | Input sanitization | Strip < > ' " \ from user-supplied strings |
| Race Conditions | SELECT ... FOR UPDATE |
Row-level locks during inventory checks |
| Timeouts | 10s on all HTTP calls | Prevents hanging connections |
| Error Logging | Datadog integration | All errors forwarded to centralized logging |
| CORS | Environment-driven | Access-Control-Allow-Origin set via FRONTEND_URL |
If you wanted to take this from reference implementation to actual production, here is how I'd approach scaling it.
| Component | Service | Cost |
|---|---|---|
| Compute | DigitalOcean Droplet | ~$6/mo |
| Database | Supabase (PostgreSQL + Auth) | Free |
| Cache | Redis (self-hosted) | Included |
| Workflow | n8n (self-hosted) | Free |
| Component | Service | Cost |
|---|---|---|
| Auth + Database | Supabase Pro | ~$25/mo |
| Cache | Redis Cloud | Freeβ$7/mo |
| Workflow | n8n Cloud | ~$20/mo |
For 1,000+ concurrent users. PostgreSQL, Redis, and n8n would deploy as separate services behind an ingress controller with horizontal pod autoscaling.
| Users | Auth | Cache | Workflow |
|---|---|---|---|
| 10β100 | Supabase Free | Redis single | n8n single |
| 100β1,000 | Supabase Pro | Redis cluster | n8n + load balancer |
| 1,000+ | Supabase Enterprise | Redis Enterprise | n8n on Kubernetes |
enterprise-sales-api/
βββ enterprise-sales.json # n8n workflow export
βββ Function.txt # PL/pgSQL stored function
βββ GUIA_CONFIGURACION_FUNCIONAL.md # Setup guide (Spanish)
βββ LICENSE # MIT License
βββ README.md # β You are here
If I were to take this further, the natural next steps would be:
- Two-factor authentication (TOTP via Supabase)
- Webhook notifications on sale creation (Slack / WhatsApp Business)
- PDF invoice generation with branded templates
- Multi-currency support
- Advanced analytics dashboard endpoint
- OpenAPI / Swagger specification
- Automated integration test suite
This is a personal portfolio project. If you're reviewing it for hiring, collaboration, or just curiosity, I'm happy to walk through any architectural decision, trade-off, or extension idea. Open an issue or reach out directly.
π§ arturo66@gmail.com π LinkedIn
Released under the MIT License. See LICENSE for details.
Built by Arturo Ortega Salinas β Mexico City.