Tham chiếu API quản lý khách hàng / CRM API Reference
Complete API reference for the VietERP Customer Relationship Management module.
Development: http://localhost:8000/api/v1/crm
Production: https://api.vierp.vn/api/v1/crm
Direct module:
Development: http://localhost:3002/api/v1
All endpoints require authentication:
Authorization: Bearer <token>
X-Tenant-ID: <tenant-id>Required permissions:
read:crm- View customer datawrite:crm- Create/edit recordsdelete:crm- Delete recordsadmin:crm- System configuration
POST /crm/leadsRequest Body:
{
"firstName": "Nguyễn",
"lastName": "Văn A",
"email": "nguyenv@example.com",
"phone": "+84912345678",
"company": "Công ty ABC",
"designation": "Sales Manager",
"source": "website",
"leadScore": 75,
"status": "new",
"notes": "Interested in enterprise plan",
"tags": ["hot", "decision-maker"],
"customFields": {
"industry": "Technology",
"budget": "5000000000"
}
}Response (201 Created):
{
"data": {
"id": "lead-123",
"firstName": "Nguyễn",
"lastName": "Văn A",
"email": "nguyenv@example.com",
"fullName": "Nguyễn Văn A",
"leadScore": 75,
"status": "new",
"source": "website",
"createdAt": "2026-03-29T10:00:00Z",
"owner": {
"id": "user-123",
"name": "Sales Agent"
}
}
}GET /crm/leadsParameters:
status- new, contacted, qualified, proposal, won, lostsource- website, referral, cold_call, email, etc.scoreMin,scoreMax- Filter by lead scoreowner- Filter by assigned sales personsearch- Search by name or emailtags- Filter by tagssortBy- leadScore (default), createdAt, namepage,limit- Pagination
Example:
curl "http://localhost:8000/api/v1/crm/leads?status=qualified&scoreMin=60&sortBy=-leadScore"GET /crm/leads/{leadId}Response:
{
"data": {
"id": "lead-123",
"firstName": "Nguyễn",
"lastName": "Văn A",
"email": "nguyenv@example.com",
"phone": "+84912345678",
"company": "Công ty ABC",
"leadScore": 75,
"status": "qualified",
"source": "website",
"owner": {
"id": "user-123",
"name": "John Sales"
},
"interactions": [
{
"type": "email_opened",
"timestamp": "2026-03-28T15:30:00Z"
},
{
"type": "page_visited",
"timestamp": "2026-03-28T14:00:00Z"
}
],
"activities": [
{
"id": "act-1",
"type": "call",
"subject": "Discovery call",
"scheduledFor": "2026-03-30T10:00:00Z"
}
],
"notes": "Interested in enterprise plan",
"createdAt": "2026-03-20T08:00:00Z"
}
}PUT /crm/leads/{leadId}POST /crm/leads/{leadId}/convertRequest:
{
"accountId": "acc-123",
"contactEmail": "nguyenv@example.com"
}Creates Contact and Account records from Lead.
POST /crm/contactsRequest:
{
"firstName": "Nguyễn",
"lastName": "Văn B",
"email": "nguyenb@company.vn",
"phone": "+84923456789",
"jobTitle": "Procurement Manager",
"department": "Operations",
"accountId": "acc-123",
"mailingAddress": {
"street": "123 Nguyễn Huệ",
"city": "Hồ Chí Minh",
"state": "HCMC",
"postalCode": "700000",
"country": "Vietnam"
},
"notes": "Primary contact for all PO approvals"
}Response (201):
{
"data": {
"id": "contact-456",
"firstName": "Nguyễn",
"lastName": "Văn B",
"fullName": "Nguyễn Văn B",
"email": "nguyenb@company.vn",
"phone": "+84923456789",
"jobTitle": "Procurement Manager",
"accountId": "acc-123",
"isPrimary": true
}
}GET /crm/contactsParameters:
accountId- Filter by accountjobTitle- Filter by job titledepartment- Filter by departmentsearch- Search by name or emailpage,limit- Pagination
GET /crm/contacts/{contactId}PUT /crm/contacts/{contactId}POST /crm/accountsRequest:
{
"name": "Công ty ABC Limited",
"taxCode": "0123456789",
"industry": "Technology",
"annualRevenue": 500000000000,
"numberOfEmployees": 500,
"website": "https://abc.vn",
"email": "contact@abc.vn",
"phone": "+84289999999",
"billingAddress": {
"street": "456 Lê Lợi",
"city": "Hà Nội",
"state": "Hà Nội",
"postalCode": "100000",
"country": "Vietnam"
},
"shippingAddress": {
"street": "789 Nguyễn Hữu Cảnh",
"city": "Hồ Chí Minh",
"state": "HCMC",
"postalCode": "700000",
"country": "Vietnam"
},
"owner": "user-123",
"notes": "Key account - enterprise customer"
}Response (201):
{
"data": {
"id": "acc-123",
"name": "Công ty ABC Limited",
"taxCode": "0123456789",
"industry": "Technology",
"annualRevenue": 500000000000,
"numberOfEmployees": 500,
"rating": "cold",
"stage": "prospecting",
"owner": {
"id": "user-123",
"name": "Account Manager"
},
"createdAt": "2026-03-29T10:00:00Z"
}
}GET /crm/accountsParameters:
industry- Filter by industryrating- hot, warm, coldstage- prospecting, negotiation, closed-won, closed-lostowner- Filter by account ownersearch- Search by name or tax codesortBy- name, annualRevenue, createdAtpage,limit- Pagination
GET /crm/accounts/{accountId}Response:
{
"data": {
"id": "acc-123",
"name": "Công ty ABC Limited",
"taxCode": "0123456789",
"industry": "Technology",
"annualRevenue": 500000000000,
"numberOfEmployees": 500,
"rating": "hot",
"stage": "negotiation",
"owner": { "id": "user-123", "name": "Account Manager" },
"contacts": [
{
"id": "contact-1",
"fullName": "Nguyễn Văn A",
"jobTitle": "Director",
"isPrimary": true
}
],
"opportunities": [
{
"id": "opp-1",
"name": "Enterprise License - 50 seats",
"value": 5000000000,
"stage": "proposal",
"probability": 60
}
],
"interactions": [
{
"type": "call",
"date": "2026-03-28T14:00:00Z",
"notes": "Discussed features and pricing"
}
]
}
}POST /crm/opportunitiesRequest:
{
"name": "Enterprise License - 50 seats",
"accountId": "acc-123",
"contactId": "contact-456",
"value": 5000000000,
"probability": 30,
"stage": "proposal",
"closeDate": "2026-06-30",
"description": "Enterprise license sale to ABC Corp",
"nextStep": "Send proposal",
"owner": "user-123",
"customFields": {
"contract_value": 5000000000,
"number_of_seats": 50,
"implementation_cost": 500000000
}
}Response (201):
{
"data": {
"id": "opp-123",
"name": "Enterprise License - 50 seats",
"accountId": "acc-123",
"value": 5000000000,
"probability": 30,
"expectedRevenue": 1500000000,
"stage": "proposal",
"closeDate": "2026-06-30",
"daysInStage": 2,
"owner": {
"id": "user-123",
"name": "Sales Rep"
},
"createdAt": "2026-03-27T10:00:00Z"
}
}GET /crm/opportunitiesParameters:
stage- prospecting, qualification, proposal, negotiation, closed-won, closed-lostowner- Filter by owneraccountId- Filter by accountprobabilityMin,probabilityMax- Filter by probabilitysortBy- expectedRevenue (default), closeDate, createdAtsearch- Search by name
GET /crm/opportunities/{opportunityId}PUT /crm/opportunities/{opportunityId}POST /crm/opportunities/{opportunityId}/move-stageRequest:
{
"stage": "negotiation",
"notes": "Customer agreed to demo"
}POST /crm/activitiesRequest:
{
"type": "call",
"subject": "Follow-up on proposal",
"description": "Discussed pricing details and timeline",
"scheduledFor": "2026-03-30T10:00:00Z",
"dueDate": "2026-03-30T10:00:00Z",
"status": "scheduled",
"priority": "high",
"relatedTo": {
"type": "opportunity",
"id": "opp-123"
},
"attendees": ["contact-456", "user-789"],
"reminders": [
{
"type": "email",
"minutesBefore": 15
}
]
}Activity Types:
call- Phone callemail- Email messagemeeting- Face-to-face meetingtask- To-do itemnote- Note or memo
Response (201):
{
"data": {
"id": "act-789",
"type": "call",
"subject": "Follow-up on proposal",
"status": "scheduled",
"scheduledFor": "2026-03-30T10:00:00Z",
"assignedTo": {
"id": "user-789",
"name": "Sales Rep"
},
"relatedTo": {
"type": "opportunity",
"id": "opp-123"
}
}
}GET /crm/activitiesParameters:
type- Filter by activity typestatus- scheduled, completed, overduepriority- low, medium, highassignedTo- Filter by assigneerelatedId- Filter by related opportunity/contactdueDateFrom,dueDateTo- Date range
POST /crm/activities/{activityId}/completeRequest:
{
"notes": "Customer confirmed interest in proposal"
}POST /crm/communications/emailsRequest:
{
"to": "contact@abc.vn",
"subject": "Enterprise proposal for ABC Corp",
"body": "Hi, Please find attached our proposal...",
"attachments": [
{
"url": "s3://bucket/proposal.pdf",
"name": "proposal.pdf"
}
],
"relatedTo": {
"type": "opportunity",
"id": "opp-123"
},
"trackOpens": true,
"trackClicks": true
}GET /crm/communications/emailsReturns sent and received emails for contacts/opportunities.
GET /crm/pipelineParameters:
owner- Filter by ownertimeframe- current_month (default), current_quarter, current_yeargroupBy- stage (default), owner, source
Response:
{
"data": {
"stages": [
{
"name": "proposal",
"count": 5,
"totalValue": 10000000000,
"expectedRevenue": 3000000000,
"opportunities": [
{
"id": "opp-1",
"name": "Enterprise License",
"value": 5000000000,
"probability": 60
}
]
},
{
"name": "negotiation",
"count": 3,
"totalValue": 8000000000
}
],
"totalPipeline": 50000000000,
"totalExpectedRevenue": 15000000000
}
}GET /crm/forecastParameters:
period- current_month, current_quarter, current_yeargroupBy- owner, region, industry
| Code | HTTP | Description |
|---|---|---|
LEAD_NOT_FOUND |
404 | Lead does not exist |
CONTACT_NOT_FOUND |
404 | Contact does not exist |
ACCOUNT_NOT_FOUND |
404 | Account does not exist |
OPPORTUNITY_NOT_FOUND |
404 | Opportunity does not exist |
INVALID_STAGE_TRANSITION |
422 | Cannot move to requested stage |
DUPLICATE_CONTACT |
409 | Contact email already exists |
DUPLICATE_TAX_CODE |
409 | Tax code already exists |
INVALID_PROBABILITY |
400 | Probability must be 0-100 |
import { ERPClient } from '@vierp/sdk';
const client = new ERPClient({
apiKey: process.env.ERP_API_KEY,
tenantId: 'tenant-123',
});
// 1. Create lead
const lead = await client.crm.leads.create({
firstName: 'John',
lastName: 'Doe',
email: 'john@company.vn',
source: 'website',
});
// 2. Track interactions
await client.crm.activities.create({
type: 'email',
subject: 'Welcome to VietERP',
relatedTo: { type: 'lead', id: lead.id },
});
// 3. Qualify lead
await client.crm.leads.update(lead.id, {
status: 'qualified',
leadScore: 80,
});
// 4. Convert to contact
const { contact, account } = await client.crm.leads.convert(lead.id, {
accountName: 'John\'s Company',
});
// 5. Create opportunity
const opportunity = await client.crm.opportunities.create({
name: 'Enterprise License Sale',
accountId: account.id,
contactId: contact.id,
value: 5000000000,
stage: 'proposal',
});// Send tracked email
const email = await client.crm.communications.sendEmail({
to: contact.email,
subject: 'Your personalized demo',
body: 'Hi, Check out your custom demo...',
trackOpens: true,
trackClicks: true,
relatedTo: { type: 'opportunity', id: opportunity.id },
});
// System tracks:
// - Email opens
// - Link clicks
// - Updates lead/opportunity score automatically- Explore CRM Development Guide
- Review Testing Guide for test scenarios
- Check API Overview for global patterns