ReactiveCRM 통합 가이드
ReactiveCRM과 자체 통합을 구축하려는 기업(테넌트)을 위한 기술 문서: 리드 및 클라이언트 수집, 거래 생성, 마케팅 이벤트 전송, 데이터 내보내기.
이 문서는 외부 통합에 가장 일반적으로 사용되는 API만 다룹니다. 내부 참조 데이터 및 관리 서비스 엔드포인트는 의도적으로 범위에서 제외됩니다.
1. 통합 개요
일반적인 통합 흐름은 다음과 같습니다:
사용자 시스템 (백엔드 / 서버 측 프록시)
|
| 1. POST /api/auth/login (액세스 + 리프레시 토큰 획득)
v
ReactiveCRM
| 2. 참조: GET /api/users/paged, GET /api/statuses, GET /api/stages, GET /api/lead-sources
| (ownerId, authorId, statusId 등에 대한 UUID 획득)
v
| 3. 핵심 작업:
| POST /api/leads/create — 리드 생성
| POST /api/clients/create — 클라이언트 생성
| POST /api/contacts/create — 연락처 생성
| POST /api/deals/create — 거래 생성
| POST /api/dashboard/marketing/events — 마케팅 이벤트 전송
| POST /api/leads/import/batch — 리드 대량 가져오기
v
| 4. 읽기 / 내보내기:
| GET /api/leads/paged — 필터가 있는 페이지 읽기
| GET /api/export/leads — 모든 리드의 NDJSON 내보내기
핵심 보안 규칙: 최종 사용자의 브라우저에서 CRM API를 직접 호출하지 마십시오. CRM 토큰과 내부 식별자는 백엔드(또는 서버리스 함수)에 보관하세요.
2. 인증
2.1. 토큰 획득
인증 엔드포인트는 토큰이 필요하지 않습니다:
| 메서드 | URL | 설명 |
|---|---|---|
POST | /api/auth/login | 사용자명 + 비밀번호로 로그인, 액세스 + 리프레시 토큰 반환 |
POST | /api/auth/refresh | 리프레시 토큰을 새 토큰 쌍으로 교환 |
POST | /api/auth/logout | 리프레시 토큰 취소 |
curl -X POST "$CRM_BASE_URL/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username": "integration", "password": "secret123"}'
{
"token": "eyJhbGciOiJIUzI1NiJ9...",
"refreshToken": "a8f3k2m9Qx7Tt1Vv...",
"tokenType": "Bearer",
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"firstName": "통합",
"lastName": "봇",
"tenantId": "660e8400-e29b-41d4-a716-446655440001"
},
"tenant": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Zunga Corp"
}
}
2.2. 토큰 처리 규칙
- 액세스 토큰 (
token) — 1시간 동안 유효한 JWT입니다. 모든 요청과 함께 전송:Authorization: Bearer <token>. - 리프레시 토큰 (
refreshToken) — 7일 동안 유효한 임의 문자열입니다. 새 토큰 쌍을 얻는 데 사용합니다. - 매
/api/auth/refresh호출마다 서버는 리프레시 토큰을 회전시킵니다: 이전 토큰은 삭제되고 새 토큰이 발급됩니다. 두 새 값을 모두 유지하세요. - 만료된 액세스 토큰이 있는 요청은
401을 반환합니다. 이 경우 리프레시하여 원래 요청을 재시도하세요 — 다시 로그인하지 마세요.
2.3. 기본 설정
CRM_BASE_URL=https://crm.example.com
아래 모든 예제는 다음 헤더를 가정합니다:
Authorization: Bearer <CRM_ACCESS_TOKEN>
Content-Type: application/json
3. 페이지네이션 API 규칙
GET /api/*/paged 형식의 모든 목록 엔드포인트는 동일한 규칙을 공유합니다:
| 파라미터 | 유형 | 기본값 | 설명 |
|---|---|---|---|
page | 정수 | 0 | 페이지 번호, 0부터 시작 |
size | 정수 | 엔드포인트별 | 페이지 크기 |
sort | 문자열 | createdAt,desc | 필드,방향 형식의 정렬. 방향: asc 또는 desc |
페이지 응답 구조
{
"content": [ { "..." } ],
"page": 0,
"size": 20,
"totalElements": 137,
"totalPages": 7
}
날짜 필터링
범위에 대해 필드From / 필드To 파라미터 사용 (ISO 8601):
createdAtFrom=2026-01-01T00:00:00Z
createdAtTo=2026-01-31T23:59:59Z
정렬
항상 ?sort=필드,방향:
?sort=createdAt,desc
?sort=name,asc
일부 필터 필드에는 전용 범위 파라미터가 있습니다 (예:
dealAmountFrom/dealAmountTo).
필터링 의미론
- 모든 필터링 및 정렬은 서버 측에서 수행됩니다 (모든 것을 다운로드하여 클라이언트 측에서 필터링할 필요가 없음).
- 여러 필터는 AND로 결합됩니다.
- 텍스트(부분 문자열) 필터는 대소문자 구분 없는 검색을 사용합니다 (ILIKE).
- 범용
search필터는 여러 필드를 OR로 검색합니다.
4. 참조 (UUID 획득)
엔티티를 생성하기 전에 관련 참조 데이터의 UUID를 획득하세요. 주요 항목은 다음과 같습니다:
4.1. 사용자 (GET /api/users/paged)
ownerId, authorId, developingManagerIds에 사용됩니다.
curl "$CRM_BASE_URL/api/users/paged?page=0&size=50&sort=createdAt,asc" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
응답 예시 (content 조각):
[
{
"id": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"firstName": "Roman",
"lastName": "Posledovskiy",
"username": "roman",
"email": "roman@example.com",
"tenantId": "660e8400-e29b-41d4-a716-446655440001"
}
]
4.2. 상태 (GET /api/statuses)
리드, 거래 및 거래 당사자 클라이언트의 statusId에 사용됩니다. 배열을 반환합니다:
curl "$CRM_BASE_URL/api/statuses" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
[
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "New",
"entityType": "LEAD"
},
{
"id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"name": "In progress",
"entityType": "STAGE"
}
]
4.3. 단계 (GET /api/stages)
거래의 stageId에 사용됩니다:
curl "$CRM_BASE_URL/api/stages" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
4.4. 리드 소스 (GET /api/lead-sources)
리드 소스의 트리를 반환합니다. 리드의 leadSourceId에 사용됩니다:
curl "$CRM_BASE_URL/api/lead-sources" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
[
{
"id": "cccc0001-0000-0000-0000-000000000001",
"name": "Website",
"children": [
{
"id": "cccc0001-0000-0000-0000-000000000002",
"name": "Feedback form",
"children": []
}
]
}
]
5. 리드
5.1. 리드 생성 (POST /api/leads/create)
curl -X POST "$CRM_BASE_URL/api/leads/create" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "웹사이트 문의: 상담",
"ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"leadSourceId": "cccc0001-0000-0000-0000-000000000002",
"statusId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"quality": "WARM"
}'
요청 필드:
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
message | 문자열 | 아니오 | 메시지 / 문의 텍스트 |
ownerId | uuid | 예 | 담당 사용자 |
authorId | uuid | 예 | 리드를 생성한 사용자 |
clientId | uuid | 아니오 | 관련 클라이언트 |
contactId | uuid | 아니오 | 관련 연락처 |
leadSourceId | uuid | 아니오 | 리드 소스 트리 노드 |
statusId | uuid | 아니오 | 상태 |
quality | enum | 아니오 | HOT, WARM, COOL, COLD |
201 Created 응답 예시:
{
"id": "22222222-2222-2222-2222-222222222222",
"message": "웹사이트 문의: 상담",
"status": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "New"
},
"quality": "WARM",
"dealId": null,
"createdAt": "2026-09-05T20:00:00Z",
"updatedAt": "2026-09-05T20:00:00Z",
"version": 0,
"author": {
"id": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"firstName": "Roman",
"lastName": "Posledovskiy"
},
"owner": {
"id": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"firstName": "Roman",
"lastName": "Posledovskiy"
}
}
반환된
id를 보관하세요 — 마케팅 이벤트의leadId에 필요합니다 (8절 참조).
5.2. 페이지 읽기 (GET /api/leads/paged)
curl "$CRM_BASE_URL/api/leads/paged?page=0&size=20&createdAtFrom=2026-09-01T00:00:00Z&sort=createdAt,desc" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
주요 필터:
| 파라미터 | 유형 | 모드 | 설명 |
|---|---|---|---|
statusId | uuid | 정확히 일치 | 상태로 필터링 |
leadSourceId | uuid | 정확히 일치 | 리드 소스로 필터링 |
quality | enum | 정확히 일치 | HOT, WARM, COOL, COLD |
message | 문자열 | ILIKE | 메시지의 부분 문자열 |
search | 문자열 | ILIKE (OR) | 메시지, 연락처, 이메일, 전화번호 검색 |
contactEmail | 문자열 | ILIKE | 연락처 이메일로 검색 |
contactPhone | 문자열 | ILIKE | 연락처 전화번호로 검색 |
company | 문자열 | ILIKE | 회사명으로 검색 |
clientId | uuid | 정확히 일치 | 클라이언트 ID로 검색 |
createdAtFrom / createdAtTo | 날짜-시간 | 범위 | 생성일로 검색 |
updatedAtFrom / updatedAtTo | 날짜-시간 | 범위 | 업데이트일로 검색 |
createdBy | uuid | 정확히 일치 | 리드 작성자로 검색 |
관련 거래에 대한 필터도 있습니다: dealStatusId, dealStageId, dealAmountFrom/dealAmountTo, dealProbabilityFrom/dealProbabilityTo.
정렬: createdAt, updatedAt, message, quality, 상태/소스 등 (필드,방향 형식).
5.3. 단일 리드 가져오기 (GET /api/leads/{id})
curl "$CRM_BASE_URL/api/leads/$LEAD_ID" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
5.4. 리드 대량 가져오기 (POST /api/leads/import/batch)
대량의 리드를 대량 수집하려면 배치 엔드포인트를 사용하세요. 리드 배열을 받아들이고, 가져오기 기록을 생성하며, 전체 가져오기를 롤백할 수 있습니다.
curl -X POST "$CRM_BASE_URL/api/leads/import/batch" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"fileName": "leads-2026-09-05.csv",
"leads": [
{
"message": "문의 #1",
"ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"quality": "WARM"
},
{
"message": "문의 #2",
"ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"quality": "COOL"
}
]
}'
응답 예시:
{
"importId": "44444444-4444-4444-4444-444444444444",
"imported": 2,
"total": 2,
"skipped": []
}
imported— 생성된 개수.skipped—index(0부터 시작)와reason이 있는 건너뛴 행의 배열.
기록 및 롤백:
# 가져오기 기록
curl "$CRM_BASE_URL/api/leads/import/history" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
# 가져오기 롤백
curl -X POST "$CRM_BASE_URL/api/leads/import/rollback/$IMPORT_ID" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
5.5. 빠른 웹사이트 리드 (POST /api/site/leads)
웹사이트 양식을 위해 연락처, 기본 전화번호 및 이메일, 리드, 연락처-리드 링크, 마케팅 이벤트를 하나의 요청으로 원자적으로 생성하는 단일 결합 엔드포인트가 있습니다 — externalId를 통한 멱등성 포함.
전용 가이드 참조: site-lead-multi-contract.md.
6. 클라이언트 및 연락처
6.1. 클라이언트 생성 (POST /api/clients/create)
curl -X POST "$CRM_BASE_URL/api/clients/create" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "COMPANY",
"name": "Romashka LLC",
"taxId": "7700000001",
"regNumber": "1234567890",
"country": "RU",
"phone": "+7-495-000-00-01",
"email": "info@romashka.ru",
"website": "https://romashka.ru",
"ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35"
}'
주요 필드:
| 필드 | 유형 | 해당 대상 | 설명 |
|---|---|---|---|
type | enum | 모두 | INDIVIDUAL 또는 COMPANY (필수) |
name | 문자열 | 모두 | 표시 이름 (필수) |
firstName / lastName | 문자열 | INDIVIDUAL | 이름/성 |
taxId | 문자열 | COMPANY | 세금 ID (INN) |
regNumber | 문자열 | COMPANY | 등록 번호 |
legalAddress | 문자열 | COMPANY | 법적 주소 |
phone / email / website | 문자열 | 모두 | 연락처 |
country | 문자열 | 모두 | ISO 국가 코드 |
ownerId | uuid | 모두 | 담당 사용자 |
authorId | uuid | 모두 | 작성자 |
developingManagerIds | uuid[] | 모두 | 개발 관리자 |
6.2. 클라이언트 페이지 읽기 (GET /api/clients/paged)
curl "$CRM_BASE_URL/api/clients/paged?page=0&size=20&type=COMPANY&search=Romashka&sort=name,asc" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
주요 필터: name, type (INDIVIDUAL/COMPANY), country, taxId, email, phone, lastName (개인), search (이름/세금 ID/전화번호로), createdAtFrom/createdAtTo, createdBy, developingManagerId.
6.3. 중복 확인 (GET /api/clients/duplicates)
클라이언트를 생성하기 전에 유사한 항목이 이미 존재하는지 확인하세요:
# 세금 ID 및 이름으로 확인
curl "$CRM_BASE_URL/api/clients/duplicates?type=COMPANY&taxId=7700000001&name=Romashka" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
6.4. 연락처 생성 (POST /api/contacts/create)
curl -X POST "$CRM_BASE_URL/api/contacts/create" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Ivan",
"lastName": "Petrov",
"dateOfBirth": "1990-05-15",
"gender": "MALE",
"countryCode": "RU",
"ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35"
}'
필드: firstName (필수), lastName, patronymicName, dateOfBirth (date), gender (MALE/FEMALE), countryCode, ownerId, authorId.
6.5. 연락처 페이지 읽기 (GET /api/contacts/paged)
curl "$CRM_BASE_URL/api/contacts/paged?page=0&size=20&search=Petrov&sort=createdAt,desc" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
7. 거래
7.1. 거래 생성 (POST /api/deals/create)
curl -X POST "$CRM_BASE_URL/api/deals/create" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "서버 하드웨어 납품",
"clientId": "9f128931-69fd-493a-9a08-be5be0e6603d",
"statusId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"stageId": "dddd0001-0000-0000-0000-000000000001",
"probability": 60,
"amount": 150000.00,
"ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
"authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35"
}'
주요 필드:
| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
name | 문자열 | 예 | 거래명 |
clientId | uuid | 예 | 클라이언트 ID |
statusId | uuid | 아니오 | 상태 (단계 상태) |
stageId | uuid | 아니오 | 판매 단계 |
probability | 정수 | 아니오 | 확률 0-100 |
amount | 숫자 | 아니오 | 금액 |
plannedAmount | 숫자 | 아니오 | 계획 금액 |
discountPercent | 정수 | 아니오 | 할인 0-100 |
startDate / expectedCloseDate | 날짜-시간 | 아니오 | 날짜 |
ownerId | uuid | 아니오 | 소유자 |
leadId | uuid | 아니오 | 관련 리드 |
contactId | uuid | 아니오 | 관련 연락처 |
productIds | uuid[] | 아니오 | 제품 (간소화 형식) |
dealProducts | 배열 | 아니오 | 거래 라인 항목 (전체 형식) |
dealParties | 배열 | 아니오 | 거래 당사자 |
7.2. 거래 페이지 읽기 (GET /api/deals/paged)
curl "$CRM_BASE_URL/api/deals/paged?page=0&size=20&stageKind=OPEN&sort=createdAt,desc" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
주요 필터: name (ILIKE), clientId, clientName, statusId, stageId, stageKind (OPEN/WON/LOST), ownerId, search, startDateFrom/startDateTo, expectedCloseDateFrom/expectedCloseDateTo, actualCloseDateFrom/actualCloseDateTo, createdAtFrom/createdAtTo.
8. 마케팅 이벤트 (속성)
UTM 태그, 광고 식별자 및 트래픽 소스를 전송하려면 다음을 사용하세요:
POST /api/dashboard/marketing/events
curl -X POST "$CRM_BASE_URL/api/dashboard/marketing/events" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"eventType": "lead_submitted",
"occurredAt": "2026-09-05T20:00:00Z",
"visitorId": "visitor-8b7f",
"sessionId": "session-31ac",
"leadId": "22222222-2222-2222-2222-222222222222",
"externalId": "site-form-submit-20260905-000123",
"source": "website",
"channel": "paid",
"utmSource": "google",
"utmMedium": "cpc",
"utmCampaign": "summer-consulting",
"utmContent": "banner-a",
"utmTerm": "crm consultation",
"gclid": "EAIaIQobChMI-example",
"landingUrl": "https://www.example.com/consultation",
"referrer": "https://www.google.com/",
"metadata": {
"formName": "consultation",
"pageType": "landing"
}
}'
응답 예시:
{
"accepted": true,
"duplicate": false,
"eventId": "33333333-3333-3333-3333-333333333333"
}
규칙:
- 안정적인
externalId(UUID 또는 고유 requestId)를 구성하세요. 동일한source/테넌트에 대해 동일한externalId로 재전송하면duplicate: true가 반환됩니다 — 이는 오류가 아닙니다. - 재시도 시 새
externalId를 생성하지 마세요. metadata에 개인 식별 정보(이메일, 전화번호, 이름, 메시지 텍스트)를 넣지 마세요. 양식 이름이나 페이지 유형과 같은 기술적 속성만 허용됩니다.
자세한 내용은 site-leads-integration-guide.md를 참조하세요.
9. 데이터 내보내기 (NDJSON)
내보내기 엔드포인트는 테넌트의 모든 레코드를 NDJSON 형식(한 줄에 하나의 JSON 객체, \n으로 구분)으로 반환합니다.
| 엔드포인트 | 설명 |
|---|---|
GET /api/export/leads | 모든 테넌트 리드 |
GET /api/export/clients | 모든 테넌트 클라이언트 |
GET /api/export/contacts | 모든 테넌트 연락처 |
curl "$CRM_BASE_URL/api/export/leads" \
-H "Authorization: Bearer $CRM_ACCESS_TOKEN"
응답 예시 (라인 스트림):
{"id":"550e8400-e29b-41d4-a716-446655440001","message":"웹사이트 문의","quality":"WARM","statusName":"New","createdAt":"2026-08-20T10:00:00+03:00","ownerName":"Ivan Ivanov","clientName":"Romashka LLC","contactFirstName":"Petr","contactLastName":"Petrov","leadSourceName":"Paid search"}
{"id":"550e8400-e29b-41d4-a716-446655440002","message":"전화 통화","quality":"COOL","statusName":"In progress","createdAt":"2026-08-19T09:00:00+03:00","ownerName":"Maria Smirnova","clientName":null}
중요: NDJSON은 유효한 JSON 배열이 아닙니다. ReadableStream을 통해 응답을 한 줄씩 읽으세요 (전체 응답에 대해 JSON.parse()를 호출하지 마세요).
10. 종단 간 통합 예제
다음 시나리오는 웹사이트 리드를 생성하고, 연락처와 클라이언트를 연결하고, 거래를 생성하고, 마케팅 이벤트를 전송합니다.
CRM_BASE_URL=https://crm.example.com
CRM_TOKEN="<access-token>"
# 1. 로그인
curl -s -X POST "$CRM_BASE_URL/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username": "integration", "password": "secret123"}' | tee /tmp/login.json
CRM_TOKEN=$(jq -r '.token' /tmp/login.json)
OWNER_ID=$(curl -s "$CRM_BASE_URL/api/users/paged?page=0&size=50" \
-H "Authorization: Bearer $CRM_TOKEN" | jq -r '.content[0].id')
# 2. 클라이언트 생성
curl -s -X POST "$CRM_BASE_URL/api/clients/create" \
-H "Authorization: Bearer $CRM_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"type\": \"COMPANY\",
\"name\": \"Romashka LLC\",
\"taxId\": \"7700000001\",
\"country\": \"RU\",
\"ownerId\": \"$OWNER_ID\",
\"authorId\": \"$OWNER_ID\"
}" | tee /tmp/client.json
CLIENT_ID=$(jq -r '.id' /tmp/client.json)
# 3. 연락처 생성
curl -s -X POST "$CRM_BASE_URL/api/contacts/create" \
-H "Authorization: Bearer $CRM_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"firstName\": \"Ivan\",
\"lastName\": \"Petrov\",
\"countryCode\": \"RU\",
\"ownerId\": \"$OWNER_ID\",
\"authorId\": \"$OWNER_ID\"
}" | tee /tmp/contact.json
CONTACT_ID=$(jq -r '.id' /tmp/contact.json)
# 4. 리드 생성
curl -s -X POST "$CRM_BASE_URL/api/leads/create" \
-H "Authorization: Bearer $CRM_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"message\": \"웹사이트 문의\",
\"clientId\": \"$CLIENT_ID\",
\"contactId\": \"$CONTACT_ID\",
\"ownerId\": \"$OWNER_ID\",
\"authorId\": \"$OWNER_ID\",
\"quality\": \"WARM\"
}" | tee /tmp/lead.json
LEAD_ID=$(jq -r '.id' /tmp/lead.json)
# 5. 리드에 연결된 거래 생성
curl -s -X POST "$CRM_BASE_URL/api/deals/create" \
-H "Authorization: Bearer $CRM_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"Ivan Petrov 상담\",
\"clientId\": \"$CLIENT_ID\",
\"leadId\": \"$LEAD_ID\",
\"contactId\": \"$CONTACT_ID\",
\"amount\": 50000.00,
\"ownerId\": \"$OWNER_ID\",
\"authorId\": \"$OWNER_ID\"
}"
# 6. 마케팅 이벤트 전송
curl -s -X POST "$CRM_BASE_URL/api/dashboard/marketing/events" \
-H "Authorization: Bearer $CRM_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"eventType\": \"lead_submitted\",
\"occurredAt\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",
\"leadId\": \"$LEAD_ID\",
\"externalId\": \"request-$(uuidgen)\",
\"source\": \"website\",
\"channel\": \"direct\",
\"landingUrl\": \"https://www.example.com/form\",
\"metadata\": {\"formName\": \"consultation\"}
}"
11. 멱등성 및 오류 처리
- 안정적인 식별자: 각 제출에 대해 자체
externalId(UUID 또는 requestId)를 생성하세요. 동일한externalId를 재전송해도 중복이 생성되지 않아야 합니다 (마케팅 이벤트의 경우 서버에서 처리 —duplicate: true). - 동일한 식별자로 재시도: 네트워크 오류 시 동일한
externalId로 재시도하세요; 새로 생성하지 마세요. - 맹목적으로 중복 생성하지 마세요: 생성 요청이 타임아웃된 경우, 새로 생성하는 대신 먼저 결과를 확인하세요 (자체 requestId 사용 또는 생성된 엔티티 찾기).
400: 잘못된 페이로드 — 변경 없이 재시도해도 도움이 되지 않습니다; 데이터를 수정하세요.401: 액세스 토큰 만료 —/api/auth/refresh를 호출하고 요청을 재시도하세요.403: 권한 없음 — 역할과 테넌트를 확인하세요.5xx/타임아웃: 일시적 오류 — 동일한externalId로 재시도하세요 (리드의 경우 대기열 사용).
12. 빠른 시작
- 인증:
POST /api/auth/login으로 인증하고token과refreshToken을 저장하세요. - 추가: 모든 요청에
Authorization: Bearer <token>을 추가하세요.401발생 시/api/auth/refresh로 갱신하세요. - 참조 가져오기: 참조(사용자/상태/단계/리드 소스)를 한 번 가져오고 UUID를 캐시하세요.
- 엔티티 생성: 논리적 순서로 생성: 클라이언트 → 연락처 → 리드 → 거래.
- 페이지 엔드포인트 사용: 서버 측 필터링 및 정렬로 읽기를 수행하세요.
- 내보내기: NDJSON 엔드포인트를 사용하고 스트림을 한 줄씩 읽으세요.
- 대량 수집: 배치 엔드포인트(
/api/leads/import/batch,/api/clients/import/batch)를 롤백 지원과 함께 사용하세요. - 마케팅 속성 전송:
POST /api/dashboard/marketing/events를 안정적인externalId와 함께 사용하세요. - 저장 금지: 마케팅 이벤트
metadata에 PII를 저장하거나 전달하지 마세요. - 상세 API 문서:
site-leads-integration-guide.md를 참조하세요.
Reactive CRM