> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# 거래 모니터링 연동: KYT API

> Didit의 KYT 아키텍처와 모범 사례: 실시간 vs 배치, 거래 당사자, 멱등성, 과거 데이터 수집, webhook. 월 1,000건 포함, 이후 건당 $0.001.

이 가이드는 거래 모니터링의 전체 연동 범위를 다룹니다. [빠른 시작](https://docs.didit.me/ko/transaction-monitoring/quickstart.md)으로 바로 실행해 볼 수 있으며, 이 페이지에서는 프로덕션 환경까지 안내합니다.

## 아키텍처

```mermaid theme={null}
sequenceDiagram
    participant You as Your platform
    participant Didit as Didit API
    participant Rules as Rule engine
    participant AML as AML providers
    participant Webhook as Your webhook

    You->>Didit: POST /v3/transactions/ (txn_id, parties, amount)
    Didit->>Didit: IP enrichment (inline)
    Didit->>AML: Screen wallet or transaction hash + address
    AML-->>Didit: Hits / clean
    Didit->>Rules: Evaluate all active rules
    Rules-->>Didit: Score + matched rules + actions
    Didit-->>You: Transaction record with status
    Didit->>Webhook: transaction.created
    Didit->>Webhook: transaction.status.updated (if async rules)
```

## 인증

표준 `x-api-key` 헤더를 사용합니다. 세션과 엔티티에도 같은 키를 사용합니다. [API 인증](https://docs.didit.me/ko/getting-started/api-authentication.md)을 참조하세요.

## 거래 제출

엔드포인트는 `POST /v3/transactions/` 하나입니다. 전체 스키마는 [거래 제출](https://docs.didit.me/ko/transaction-monitoring/transactions.md)을 참조하세요.

**최소 페이로드:**

```json theme={null}
{
  "transaction_id": "tx-0001",
  "transaction_category": "finance",
  "transaction_details": {
    "direction": "outbound",
    "amount": "500.00",
    "currency": "EUR"
  },
  "subject": { "entity_type": "person", "vendor_data": "user-42", "full_name": "John Doe" },
  "counterparty": { "entity_type": "company", "full_name": "Acme Corp" }
}
```

**결제 수단, 기기 컨텍스트, 사용자 정의 속성이 포함된 상세 페이로드:**

```json theme={null}
{
  "transaction_id": "tx-0002",
  "transaction_at": "2026-04-16T10:00:00Z",
  "transaction_category": "finance",
  "transaction_details": {
    "direction": "outbound",
    "amount": "12500.00",
    "currency": "USD",
    "action_type": "withdrawal"
  },
  "subject": {
    "entity_type": "person",
    "vendor_data": "user-42",
    "full_name": "John Doe",
    "country_code": "US",
    "device_context": {
      "fingerprint": "fp-9f2c...",
      "user_agent": "Mozilla/5.0 ...",
      "browser_family": "Chrome",
      "platform": "web",
      "network_context": { "ip_address": "203.0.113.5" }
    },
    "payment_method": {
      "method_type": "bank_account",
      "account_id": "US12345678901234567890",
      "issuing_country": "US"
    }
  },
  "counterparty": {
    "entity_type": "company",
    "vendor_data": "biz-acme",
    "full_name": "Acme Corp",
    "country_code": "US",
    "payment_method": {
      "method_type": "bank_account",
      "account_id": "US09876543210987654321",
      "issuing_country": "US"
    }
  },
  "custom_properties": {
    "invoice_id": "INV-2026-00042",
    "category": "b2b_goods"
  }
}
```

모든 최상위 필드에는 camelCase 별칭을 사용할 수 있습니다(`txnId`, `txnDate`, `type`, `info`, `applicant`, `props`, `travelRule`, `includeCryptoScreening`). SDK 와이어 형식과 snake\_case 형식은 동일한 곳에 저장됩니다.

## 당사자 모델링

모든 거래에는 필수 `subject`(모니터링 대상인 귀사의 고객)와 선택 사항인 `counterparty`(거래 상대방)가 있습니다. 각 당사자에는 고유한 `payment_method`와 선택적인 `device` 컨텍스트가 포함됩니다.

응답에서는 두 당사자가 역할 `APPLICANT`와 `COUNTERPARTY`를 가진 `parties` 배열로 반환됩니다. `vendor_data`가 없는 당사자는 연결된 엔티티 없이 외부 스냅샷(`kind: EXTERNAL`)으로 저장됩니다.

당사자 필드는 [거래 페이로드](https://docs.didit.me/ko/transaction-monitoring/transactions.md)를 참조하세요.

## 멱등성

`txn_id`(보내는 `transaction_id`)는 애플리케이션마다 고유합니다.
이미 존재하는 `transaction_id`를 다시 제출하면 `transaction_id` 필드에 `A transaction with this transaction_id already exists.` 메시지와 함께 `400`이 반환됩니다. 동일한 요청 두 개가 경합하는 경우, 두 번째 요청은 `409`를 받습니다.
두 응답 모두 기존 거래를 반환하지 않습니다.
중복 `transaction_id`에 대해 `400` 또는 `409`를 받으면 다시 제출하지 말고 기존 거래를 조회하세요. 첫 응답의 `uuid`를 사용해 [`GET /v3/transactions/{uuid}/`](https://docs.didit.me/ko/management-api/transactions/get)로 읽거나, `transaction.created` webhook이 `txn_id`와 함께 전달하는 `transaction_id`(Didit uuid)를 사용하세요.

**제출 전에 항상 `txn_id`를 직접 생성하세요.** 멱등성을 위해 Didit이 생성한 ID에 의존하지 마세요. 자체 데이터베이스 ID, UUID 또는 거래 필드의 해시를 사용하세요.

## 실시간 및 배치

* **실시간**: 대부분의 사용 사례에 권장됩니다. 시스템에서 거래가 발생하는 즉시 제출하세요. 규칙은 동기식으로 평가되고 결정을 반환합니다.
* **배치 / 백필**: 과거 데이터를 가져올 때는 과거 날짜의 `txn_date`를 전달하세요. 규칙은 계속 실행되며 webhook을 트리거할 수 있습니다. 백필 시 규칙 트리거를 피하려면 콘솔의 CSV 가져오기에서 "dry ingest" 플래그를 사용하세요.

## 과거 데이터 수집

다른 거래 모니터링 시스템에서 마이그레이션하는 경우:

1. 과거 거래를 CSV로 내보냅니다.
2. 콘솔의 *Transactions → Import history*를 사용하거나(또는 반복문에서 API로 제출), 과거 날짜의 `txn_date`를 지정합니다.
3. 가져오기가 끝난 후에만 규칙을 활성화하거나, dry ingest를 사용해 규칙 평가를 건너뜁니다.

> [!WARNING]
>
> 과거 데이터에 대한 규칙 평가는 신중하게 진행하세요. "30일 동안 20건의 송금" 규칙에 6개월치 과거 데이터를 입력하면 한꺼번에 수천 건의 알림이 생성됩니다.

## webhook

다음 이벤트를 구독하세요.

* `transaction.created`: 제출된 모든 거래에 대해 발생합니다.
* `transaction.status.updated`: 상태 변경 시 발생합니다(예: 분석가가 `IN_REVIEW`에서 `APPROVED`로 변경하거나, 비동기 AML 검사가 점수를 업데이트하는 경우).

자세한 내용은 [TM webhook](https://docs.didit.me/ko/transaction-monitoring/webhooks.md)을 참조하세요.

```typescript theme={null}
app.post('/webhooks/didit-tm', (req, res) => {
  if (!verifySignature(req)) return res.status(401).end();

  const { webhook_type, status, txn_id } = req.body;
  if (webhook_type === 'transaction.status.updated' && status === 'DECLINED') {
    suspendTransaction(txn_id);
  }
  res.status(200).end();
});
```

## 상태 처리

| 상태 | 처리 방법 |
| - | - |
| `APPROVED` | 거래를 일반적으로 처리합니다. |
| `IN_REVIEW` | 분석가 검토가 완료되거나 자동 재확인으로 문제가 해결될 때까지 거래를 보류합니다. |
| `DECLINED` | 거래를 거부합니다. 사용자에게는 일반적인 오류를 표시합니다. |
| `AWAITING_USER` | 거래가 정산되려면 사용자가 조치해야 합니다. `action_required` 블록을 읽고 그 `url`을 사용자에게 전달하세요(SDK는 [이를 자동으로 처리](https://docs.didit.me/ko/transaction-monitoring/sdk-transaction-submission.md#필수-사용자-작업)할 수 있습니다). |

[TM 상태](https://docs.didit.me/ko/transaction-monitoring/statuses.md)를 참조하세요.

## 거래를 엔티티에 연결하기

모든 당사자에 `vendor_data`를 전달하세요. 이렇게 하면 다음과 같은 이점이 있습니다.

* 모든 거래가 사용자 또는 기업 프로필에 집계됩니다.
* 속도 및 행동 규칙이 평가에 사용할 전체 이력을 확보합니다.
* 엔티티를 차단하면 향후 거래에도 자동으로 적용됩니다.

`vendor_data`가 없어도 치명적인 오류는 아닙니다. 거래는 외부 스냅샷으로 저장되지만, 엔티티 단위 집계는 할 수 없게 됩니다.

## 보완 세션

규칙 작업이 거래를 `AWAITING_USER`로 전환하면 Didit은 같은 `vendor_data`에 대한 표준 호스팅 인증 세션인 **보완 세션**을 자동으로 생성합니다.
커스텀 규칙은 항상 작업 자체에 워크플로를 지정합니다. 기본 제공 라이브러리 규칙의 경우 워크플로는 [거래 설정의 보완 워크플로](https://docs.didit.me/ko/transaction-monitoring/settings.md#보완-워크플로)로 대체되고, 그다음 대상자에게 저장된 기준 얼굴이 있으면 애플리케이션의 생체 인증 워크플로, 마지막으로 애플리케이션의 기본 워크플로가 사용됩니다.
Travel Rule 거래는 이 자동 대체 방식에서 제외됩니다. 이 거래의 대기 작업은 지갑 소유권 증명입니다.
거래(응답, 이후의 모든 조회, 모든 webhook)에는 표준 `action_required` 블록에 이 정보가 포함됩니다.

```json theme={null}
{
  "status": "AWAITING_USER",
  "action_required": {
    "type": "verification_session",
    "url": "https://verify.didit.me/session/...",
    "session_id": "11111111-2222-3333-4444-555555555555",
    "session_token": "SESSION_TOKEN",
    "status": "Not Started"
  },
  "remediation": {
    "session_id": "11111111-2222-3333-4444-555555555555",
    "session_token": "SESSION_TOKEN",
    "url": "https://verify.didit.me/session/...",
    "status": "Not Started"
  }
}
```

`remediation`은 하위 호환성을 위해 유지되며, `action_required`가 표준 블록입니다. 이 블록에는 [Travel Rule](https://docs.didit.me/ko/transaction-monitoring/travel-rule.md) 송금의 `wallet_ownership` 작업도 포함됩니다.
`wallet_ownership` 작업은 그 자체로 거래 상태를 바꾸지 않습니다. 거래는 규칙이 부여한 상태를 그대로 유지하며, 흔히 `APPROVED`입니다. 따라서 `AWAITING_USER`일 때만이 아니라 모든 응답에서 `action_required`를 확인하십시오.

사용자는 인증을 완료합니다. **생체 인증** 워크플로의 경우, 사용자는 라이브니스 검사를 거친 셀피를 제출하고, 이 셀피는 최초 KYC 온보딩 때 캡처된 얼굴과 대조됩니다. 이는 [고액 거래](https://docs.didit.me/ko/transaction-monitoring/sdk-transaction-submission.md#예시-고액-출금-시-추가-생체-인증)에 적용되는 가장 강력한 추가 인증 단계입니다.
세션에서 결정이 내려지면 거래는 그 결정을 자동으로 따릅니다. `APPROVED`(`decision_reason_code: user_action_approved`), `DECLINED`(`user_action_declined`), `IN_REVIEW`(`user_action_in_review`) 중 하나로 전환되며, `transaction.status.updated` webhook이 발생합니다.

> [!NOTE]
>
> KYB를 제외한 모든 워크플로 유형을 선택할 수 있습니다.
> 생체 인증 워크플로(및 얼굴 대조가 신분증 인증보다 먼저 실행되는 워크플로)에는 대상자에게 승인된 인증에서 저장된 기준 얼굴이 이미 있어야 합니다. 저장된 기준 얼굴이 없는 사용자는 대신 애플리케이션의 기본 워크플로로 보내지며, 이때 거래에 이 대체 적용 내용이 기록됩니다.

## 권장 사항

| 권장 사항 | 이유 |
| - | - |
| 항상 `vendor_data`를 전달하십시오 | 집계를 가능하게 합니다. |
| 자체 `txn_id`를 사용하십시오 | 멱등성. |
| `transaction.created`와 `transaction.status.updated`를 모두 구독하십시오 | 비동기 상태 변경(예: 분석가 검토 결과)을 포착합니다. |
| 규칙 임계값을 신중하게 설정하십시오 | 임계값이 낮으면 알림이 많아지고, 높으면 위험을 놓치기 쉽습니다. [위험 점수](https://docs.didit.me/ko/transaction-monitoring/risk-scoring.md)를 참조하십시오. |
| 콘솔에서 규칙 실행 횟수를 모니터링하십시오 | 한 번도 실행되지 않는 규칙(잘못 구성됨)이나 모든 거래에 실행되는 규칙(지나치게 느슨함)을 찾아내십시오. |
| 프로덕션 환경으로 전환하기 전에 TEST 모드에서 규칙을 테스트하십시오 | [규칙](https://docs.didit.me/ko/transaction-monitoring/rules.md)을 참조하십시오. |

## 속도 제한

[속도 제한](https://docs.didit.me/ko/integration/rate-limiting.md)을 참조하십시오. 거래 생성은 처리량이 가장 많은 endpoint 중 하나이며, 일반적인 제한은 초당 수백 건의 요청 수준입니다. 요청을 급격히 몰아서 보내지 않도록 주의하십시오.

## 다음 단계

> [card] [거래](https://docs.didit.me/ko/transaction-monitoring/transactions.md)
>
> 전체 페이로드 참조.

> [card] [규칙](https://docs.didit.me/ko/transaction-monitoring/rules.md)
>
> 규칙이 평가되는 방식.

> [card] [webhook](https://docs.didit.me/ko/transaction-monitoring/webhooks.md)
>
> 이벤트 목록.

> [card] [문제 해결](https://docs.didit.me/ko/transaction-monitoring/troubleshooting.md)
>
> 자주 발생하는 연동 문제.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.