ERPNext Integration
Configure ERPNext CRM integration for lead management and customer portal data.
Last updated: 31 January 2026
ERPNext Integration
EthosPower AI integrates with ERPNext for CRM functionality, customer data, and business operations. This guide covers setup and configuration.
Overview
The ERPNext integration provides:
- Lead Creation - Contact form submissions create CRM leads
- Customer Portal - Dashboard shows projects, tasks, and invoices
- MCP Access - Claude Code can query ERPNext directly
Prerequisites
- ERPNext instance (v14+) with REST API enabled
- API user with appropriate permissions
- Network access from Cloudflare Workers to ERPNext
API Configuration
Generate API Credentials
- Log into ERPNext as Administrator
- Navigate to Settings > User
- Select or create an API user
- Go to API Access section
- Generate API Key and Secret
Configure Wrangler Secrets
# Set ERPNext credentials
wrangler secret put ERPNEXT_URL <<< "https://erp.yourdomain.org"
wrangler secret put ERPNEXT_API_KEY <<< "your-api-key"
wrangler secret put ERPNEXT_API_SECRET <<< "your-api-secret"
Use heredoc syntax (<<<) to avoid empty values from pipe issues.
Authentication Pattern
The ERPNext client uses token authentication:
import { ERPNextClient } from "@/lib/erpnext";
const client = new ERPNextClient({
baseUrl: env.ERPNEXT_URL,
apiKey: env.ERPNEXT_API_KEY,
apiSecret: env.ERPNEXT_API_SECRET,
});
// Token format: "token {api_key}:{api_secret}"
Graceful Degradation
The integration uses graceful degradation - if ERPNext is unavailable, core functionality continues:
// Contact form example
const leadResult = await createLead(formData, env);
// If ERPNext not configured or unavailable, skip silently
if (!leadResult.success) {
console.log("ERPNext unavailable, continuing without lead creation");
}
// Email notification still sent
await sendEmail(formData);
Available Operations
Lead Creation
await client.createDocument("Lead", {
lead_name: "Company Name",
email_id: "contact@example.com",
source: "Website",
notes: "Inquiry about AI consulting",
});
Query Documents
const leads = await client.getDocuments("Lead", {
filters: [["status", "=", "Open"]],
fields: ["name", "lead_name", "email_id"],
limit: 10,
});
Customer Portal Queries
// Get customer's projects
const projects = await client.getDocuments("Project", {
filters: [["customer", "=", customerId]],
fields: ["name", "project_name", "status", "percent_complete"],
});
// Get customer's invoices
const invoices = await client.getDocuments("Sales Invoice", {
filters: [["customer", "=", customerId]],
fields: ["name", "posting_date", "grand_total", "status"],
});
MCP Server Access
Claude Code has direct ERPNext access via the erpnext MCP server:
# List DocTypes
mcp-cli call erpnext/get_doctypes '{}'
# Get Lead fields
mcp-cli call erpnext/get_doctype_fields '{"doctype": "Lead"}'
# Query documents
mcp-cli call erpnext/get_documents '{"doctype": "Lead", "limit": 5}'
Caching Strategy
Dashboard data is cached in Cloudflare KV to reduce ERPNext load:
| Data Type | TTL | Cache Key Pattern |
|---|---|---|
| Projects | 5 min | erpnext:projects:{custId} |
| Tasks | 5 min | erpnext:tasks:{projId} |
| Invoices | 15 min | erpnext:invoices:{custId} |
Troubleshooting
Authentication Errors
Verify credentials:
curl -X GET "https://erp.yourdomain.org/api/resource/User" -H "Authorization: token api_key:api_secret"
Empty API Secret
If ERPNEXT_API_SECRET is empty after setting:
# Wrong - can result in empty value
echo "secret" | wrangler secret put ERPNEXT_API_SECRET
# Correct - use heredoc
wrangler secret put ERPNEXT_API_SECRET <<< "secret"
Permission Denied
Ensure API user has roles with read/write access to required DocTypes:
- Lead (read, write, create)
- Project (read)
- Task (read)
- Sales Invoice (read)
- Customer (read)