API

조건 매칭 기반 관계 일괄 연결

작성일 2026.04.23 | 수정일 2026.04.29

POST/crm-core/v1/relationships/bulk-match

지정한 매칭 기준(이름 또는 속성값)으로 소스 레코드와 상대 레코드를 자동 매칭하여 일괄 연결합니다. 동일한 이메일·전화번호 등을 키로 두 개체를 동기화할 때 사용합니다. MEMBER 이상 권한 + relationships.max 한도 적용.

Body Params

NameTypeRequiredDescription
sourceEntityIdstring*소스 개체 ID
relationshipTypeIdstring*관계 유형 ID
criteriaarray<object>*매칭 기준 목록 (최소 1개)
myFieldobject*내 레코드 매칭 필드
typestring*매칭 유형 — name | property
propertyIdstringtype=property 인 경우 사용할 속성 ID
counterFieldobject*상대 레코드 매칭 필드
typestring*매칭 유형 — name | property
propertyIdstringtype=property 인 경우 사용할 속성 ID
matchModestring*매칭 모드 — FIRST | ALL
sourceRecordIdsarray<string>소스 레코드 ID 목록 (최대 500개)
sourceFilterobject조건으로 소스 레코드 선택
keywordstring레코드 이름 검색 키워드
filtersstringJSON 문자열 속성 필터
segmentIdstring세그먼트 ID 필터

Response

NameTypeRequiredDescription
matchednumber*조건에 매칭된 후보 수
creatednumber*실제 생성된 관계 수
skippednumber*중복으로 건너뛴 관계 수

Structure

코드 예제

const crypto = require('crypto');

const apiKey = 'NCSXXXXXXXXXXXXX';
const apiSecret = 'YOUR_API_SECRET';
const dateTime = new Date().toISOString();
const salt = crypto.randomBytes(16).toString('hex');
const signature = crypto.createHmac('sha256', apiSecret).update(dateTime + salt).digest('hex');
const authHeader = HMAC-SHA256 apiKey=${apiKey}, date=${dateTime}, salt=${salt}, signature=${signature};

const response = await fetch('https://api.solapi.com/crm-core/v1/relationships/bulk-match', {
method: 'POST',
headers: { 'Authorization': authHeader, 'Content-Type': 'application/json' },
body: JSON.stringify({
"sourceEntityId": "CRMET1260423081530123CUS11122233",
"relationshipTypeId": "CRMRT1260423091530123RTP11122233",
"criteria": [
{
"myField": {
"type": "property",
"propertyId": "CRMPP1260423081530123MAIL1234567"
},
"counterField": {
"type": "property",
"propertyId": "CRMPP1260423081530124MAIL1234567"
}
}
],
"matchMode": "FIRST",
"sourceFilter": {
"segmentId": "CRMSG1260423081530123SGM11122233"
}
})
});
const data = await response.json();

import hmac, hashlib, secrets, requests
from datetime import datetime, timezone

api_key = 'NCSXXXXXXXXXXXXX'
api_secret = 'YOUR_API_SECRET'
date_time = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
salt = secrets.token_hex(16)
signature = hmac.new(api_secret.encode(), (date_time + salt).encode(), hashlib.sha256).hexdigest()
auth_header = f'HMAC-SHA256 apiKey={api_key}, date={date_time}, salt={salt}, signature={signature}'

response = requests.post('https://api.solapi.com/crm-core/v1/relationships/bulk-match', headers={
'Authorization': auth_header,
'Content-Type': 'application/json'
}, json={
"sourceEntityId": "CRMET1260423081530123CUS11122233",
"relationshipTypeId": "CRMRT1260423091530123RTP11122233",
"criteria": [
{
"myField": {
"type": "property",
"propertyId": "CRMPP1260423081530123MAIL1234567"
},
"counterField": {
"type": "property",
"propertyId": "CRMPP1260423081530124MAIL1234567"
}
}
],
"matchMode": "FIRST",
"sourceFilter": {
"segmentId": "CRMSG1260423081530123SGM11122233"
}
})
data = response.json()

API_KEY="NCSXXXXXXXXXXXXX"
API_SECRET="YOUR_API_SECRET"
DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
SALT=$(openssl rand -hex 16)
SIGNATURE=$(echo -n "${DATE}${SALT}" | openssl dgst -sha256 -hmac "${API_SECRET}" | awk '{print $NF}')
AUTH="HMAC-SHA256 apiKey=${API_KEY}, date=${DATE}, salt=${SALT}, signature=${SIGNATURE}"

curl -X POST 'https://api.solapi.com/crm-core/v1/relationships/bulk-match' \
-H "Authorization: ${AUTH}" \
-H "Content-Type: application/json" \
-d '{"sourceEntityId": "CRMET1260423081530123CUS11122233", "relationshipTypeId": "CRMRT1260423091530123RTP11122233", "criteria": [{"myField": {"type": "property", "propertyId": "CRMPP1260423081530123MAIL1234567"}, "counterField": {"type": "property", "propertyId": "CRMPP1260423081530124MAIL1234567"}}], "matchMode": "FIRST", "sourceFilter": {"segmentId": "CRMSG1260423081530123SGM11122233"}}'

lightbulb

`matchMode`가 `FIRST`이면 첫 매칭 1건만 연결, `ALL`이면 매칭된 모든 상대 레코드를 연결합니다. 응답 필드는 `bulk` 엔드포인트와 다릅니다(`matched`/`created`/`skipped`).

lightbulb

**401 응답**: `{ "errorCode": "Unauthorized", "errorMessage": "권한이 없습니다." }`