자산 이전 허가 요청

자산의 이전 허가 요청을 검토하고, 결과를 반환합니다.

POST /v1/beneficiary/transfer

가상자산을 전송하려는 VASP 는 자산을 보내기 전에 수취 VASP 에 '자산 이전 허가' 를 요청합니다. 이 '자산 이전 허가 요청' 을 처리하기 위한 API 를 구현해야 합니다.

API 동작 명세

  1. 암호화된 payload 를 자신의 Private Key 로 복호화합니다.

  2. 이전할 자산 정보와 Originator 정보, OriginatingVASP 정보를 확인하고 이 자산 이전을 허용할지 판단할 수 있습니다. VerifyVASP 에서 온 요청은 originatingVASP 객체가 payload 밖에 있습니다. payload -> ivms101 안으로 덮어써 주세요.

  3. Beneficiary 에 담겨있는 수취인의 주소 정보가 실제로 수취 가능한 주소인지 확인합니다.

  4. Beneficiary 에 수취인의 이름이 있을 경우에는 해당 주소의 소유자와 일치하는지도 확인합니다. 이름 정보는 PrimaryIdentifier 만 정의돼 있다면 성과 이름을 모두 포함하는 경우입니다.

  5. 필요하다면 수취 주소에 대해서 Sanction screening 도 수행합니다.

  6. 이 내용을 토대로 자산 이전 정보를 DB 에 저장하고, status 값을 부여합니다. verified 또는 denied 로 지정할 수 있습니다.

  7. 요청 메시지의 내용을 확인한 결과를 토대로 응답( response) 메시지를 생성합니다. 이 때, Originator, OriginatingVASP 정보는 요청의 값을 그대로 복사하여 사용하고, Beneficiary 정보는 수취 VASP 의 정보를 기준으로 작성합니다.

  8. 응답 메시지 서명을 첨부해서 응답을 보냅니다.

REQUEST Body Schema: application/jsonRequest

중요: Originator 의 개인정보는 2022.3.25 현재 개인인 경우 개인의 이름, 법인인 경우 법인과 대표자의 이름에 대한 정보만 보내기로 합니다.

  • transferId(Required):

    • 자산을 전송하려는 VASP 가 생성하는 자산 이전 내역의 고유 식별번호입니다.

    • 요청을 보내는 클라이언트에서 UUID v4 값을 생성해서 보냅니다.

  • currency(Required): 이전하려는 가상 자산의 심볼입니다.(대소문자를 구분하지 않습니다)

  • amount(Required): 이전하려는 가상 자산의 총 볼륨입니다.

  • historicalCost(Optional): 이전하려는 가상자산의 취득 원가입니다. (국세청 요구 사항이지만, 아직은 사용하지 않습니다.)

  • tradePrice(Required):

    • 법정 화폐 환산한 가상 자산 전송 금액입니다. 자체 시세 정보가 없는 경우에는 타 VASP의 시세 API 를 사용하여 환산합니다.

  • tradeCurrency(Required): 법정 화폐로 환산할 때 사용한 ISO 4217 표준을 따르는 법정 화폐 코드입니다.

tradePrice에는 해당 자산의 수량과 가격을 곱하여 법정 화폐로 계산한 값을, tradeCurrency에는 법정 화폐의 종류를 입력합니다. 예를 들어 2 BTC를 이전하는 경우, 그 시점의 가격이 $42,708라고 한다면 총 가격은 42,708*2 = 85,416 달러 입니다. 이 경우 다음과 같이 입력 합니다.

"tradePrice": "85416", 
"tradeCurrency": "USD",
  • isExceedingThreshold(Required):

    • tradePrice 가 법령에서 지정한 트래블룰 적용 기준을 초과하는지 여부입니다.

    • 해당 필드는 true 또는false로 입력하며, 필드값이 true 일 경우, 요청(request)의Beneficiary 이름을 실제 가상 자산 주소를 소유한 Beneficiary 이름과 비교하게 됩니다.

    • 필드값이 true일 경우, 요청(request)에 Beneficiary이름이 없거나 다를 경우 '거절(deny)' 응답을 보냅니다.

  • originatingVasp(Optional, 대소문자 주의): VerifyVASP 로부터 들어오는 요청에 한하여 암호화 영역인 payload 외부에 originatingVASP 객체가 포함돼 있습니다. payload 밖에 originatingVASP 객체가 있으면 payload 영역의 ivms101 에 덮어 써주세요.

    • countryOfRegistration(Optional) : VerifyVASP는 해당 필드값이 포함되지 않습니다.

  • payload(Required): IVMS101 메시지를 담기 위한 객체입니다.

    • ivms101(Required): IVMS101 메시지 표준을 따르는 송금인(Originator), 수취인(Beneficiary), 송신 VASP(OriginatorVASP), 수취VASP(BeneficiaryVASP) 등 가상자산 이전에 관여하는 각 주체를 IVMS101 국제 표준에 맞춰서 정의한 객체입니다. '자산 이전 허가 요청' 에서는 Originator 의 이름과 자산 주소, Beneficiary 의 자산 주소, OriginatingVASP 정보가 반드시 포함되어야 하고, Beneficiary 이름은 선택 사항입니다.

      • Originator(Required): 자산을 이전하고자 하는 송금인(개인) 또는 법인 및 대표자에 대한 정보입니다.

        • originatorPersons(Required): naturalPerson(개인), legalPerson(법인) 두 종류의 객체가 있으며, 법인의 경우에는 legalPerson(법인)과 naturalPerson(대표) 정보를 모두 설정해야 합니다. 배열 객체이며, 배열의 각 요소는(element) naturalPerson 또는 legalPerson 중 하나 만을 정의해야 합니다. 자세한 내용은 본 매뉴얼 위쪽의 IVMS101 표준 항목을 참고해주세요.

          • naturalPerson(Required): 개인에 대한 정보를 설정하기 위한 객체로 name(이름) 정보를 필수로 설정해야 합니다.

            • name(Required):

              • nameIdentifier: 법적 성명을 기입합니다. 국내 VASP 간 거래인 경우는 한글로 기입하고, 해외 VASP 와 거래하는 경우 영문으로 기입합니다. IVMS101 표준 항목을 참고해주세요.

                • primaryIdentifier: 성명 중 성을 기입합니다. 분리할 수 없는 경우는 성과 이름을 순서대로 함께 입력합니다.

                • secondaryIdentifier: 성명 중 이름을 기입합니다. 성과 이름을 분리할 수 없는 경우는 생략합니다.

                • nameIdentifierType: 'LEGL'(legal) 로 고정합니다.

              • localNameIdentifier: 해외 VASP 와 거래하는 경우 한글 이름을 추가로 전달하기 위해 정의합니다.

                • primaryIdentifier: 한글 표기 성명 중 성을 기입합니다. 분리할 수 없는 경우 성과 이름을 순서대로 함께 입력합니다.

                • secondaryIdentifier: 한글 표기 성명 중 이름을 기입합니다. 분리할 수 없는 경우는 생략합니다.

                • nameIdentifierType: 'LEGL'(legal) 로 고정합니다.

            • customerIdentification(Optional): 자산을 전송하는 송금인을 VASP에서 식별 가능한 식별자 (UID 또는 IDX)

          • legalPerson(Optional): 법인에 대한 정보를 설정하기 위한 객체로 name 객체를 필수로 설정해야 합니다.

            • name(Required):

              • nameIdentifier: 법인의 등록 상 명칭을 기입합니다. 국내 VASP 간 거래인 경우는 한글 또는 영문으로 기입하고, 해외 VASP 와 거래하는 경우 영문으로 기입합니다.

                • legalPersonName: 법인명을 기입합니다.

                • legalPersonNameIdentifierType: 'LEGL'(legal) 로 고정됩니다.

            • customerIdentification(Optional): 자산을 전송하는 송금인을 VASP에서 식별 가능한 식별자 (UID 또는 IDX)

        • accountNumber(Required): 자산을 전송하는 지갑 주소입니다. tag 나 memo 값이 필요한 경우는 ':' 로 구분하여 하나의 문자열로 만듭니다. 검증 방법은 지갑 주소 검증하기 페이지를 참조해 주세요.

      • Beneficiary(Required): 자산을 수신 받는 수취인(개인) 또는 법인 및 대표자에 대한 정보를 기입합니다. 요청(request)을 보낼 때, Beneficiary 정보를 함께 기입하여 보내야 하며, ①이름과 ②지갑 주소로 구성되어 있습니다. 지갑 주소 정보는 필수입니다. 이름 정보는 tradePrice가 트래블룰 적용 기준을 초과할 경우, 필수로 설정해야하고, 초과하지 않을 경우 옵션입니다. ※ 이름 정보는 'isExceedingThreshold'가 true일 때 Required, 'isExceedingThreshold'가 false일 때 Optional입니다.

        • beneficiaryPersons(Required): Beneficiary 상위 객체에는 반드시 beneficiaryPersons라는 하위 객체가 포함되어야 합니다. beneficiaryPersons는 originatorPersons와 구조가 동일합니다. beneficiaryPersons 하위에는 naturalPerson 또는 legalPerson로 나눌 수 있습니다. 수취 VASP는 입력한 이름과 실제 수취인의 이름을 비교했을 때, 이름이 다를 경우 거절(denied) 응답을 보냅니다.

          • naturalPerson(Required or Optional): 개인에 대한 정보를 설정하기 위한 객체이며, 'isExceedingThreshold'가 true일 경우 Required, 'isExceedingThreshold'가 false일 경우 Optional입니다.

          • legalPerson(Required or Optional): 법인에 대한 정보를 설정하기 위한 객체이며, 'isExceedingThreshold'가 true일 경우 Required, 'isExceedingThreshold'가 false일 경우 Optional입니다.

        • accountNumber(Required): 자산을 수신하는 지갑 주소입니다. tag 나 memo 값이 필요한 경우는 ':' 로 구분해서 하나의 문자열로 만듭니다. 검증 방법은 지갑 주소 검증하기 페이지를 참조해 주세요.

      • OriginatingVASP(Required): 자산을 전송하려는 송신 VASP 정보입니다.

        • originatingVASP(Required):

          • legalPerson(Required): 자산을 전송하려는 VASP의 법인 정보입니다.

            • name(Required):

              • nameIdentifier: 국제 표기법을 따르는 영문 이름 정보입니다.

                • legalPersonName: 영문 법인명입니다.

                • legalPersonNameIdentifierType: 'LEGL'(legal) 로 고정됩니다.

          'geographicAddress'와 'nationalIdentification' 둘 중 하나는 반드시 입력해야 하며, 빈 값으로 입력할 수 없습니다.

          • geographicAddress(Optional): 법인의 등록 서류상 소재지입니다.

            • addressType: 'GEOG' 로 입력합니다.

            • townName: 시/도 이름을 입력합니다.

            • addressLine: townName 하위 주소를 문자열의 배열 형식으로 입력합니다.

            • country: ISO-3166-1 alpha-2 에서 정하는 2글자 국가 코드입니다. 예) KR, JP, US 등

          • nationalIdentification(Optional): 국가의 인증을 받은 법인 식별 번호, 즉 사업자등록번호입니다.

            • nationalIdentifier: 사업자등록번호

            • nationalIdentifierType: RAID(Registration authority identifier)

            • registrationAuthority: RA000657 (대한민국 국세청 RA 식별번호)

          • countryOfRegistration(Required): 등록 국가. ISO-3166-1 alpha-2 에서 정하는 2글자 국가 코드입니다. 예) KR, JP, US 등

{
  "transferId": "string",
  "currency": "string",
  "amount": "string",
  "historicalCost": "",
  "tradePrice": "1000001",
  "tradeCurrency": "KRW",
  "isExceedingThreshold": "true",
  "originatingVasp": {
  },
  "payload": {
    "ivms101": {
      "Originator": {
        "originatorPersons": [
          // 개인일 경우 배열의 첫번째 요소에 naturalPerson 하나만 입력
          {
            "naturalPerson": {
              "name": {
                "nameIdentifier": [
                  {
                    "primaryIdentifier": "Barnes",
                    "secondaryIdentifier": "Robert",
                    "nameIdentifierType": "LEGL"
                  }
                ],
                "localNameIdentifier": [
                  {
                    "primaryIdentifier": "로버트 반스",
                    "secondaryIdentifier": "",
                    "nameIdentifierType": "LEGL"
                  }
                ]
              },
              "customerIdentification": "customernumber in Max 50 Text"
            }
          },
          // 또는 법인일 경우 배열의 첫번째 요소에 legalPerson 을 입력하고,
          // 두번째 요소부터 naturalPerson(대표자) 정보를 입력
          {  // 법인 정보
            "legalPerson": {
              "name": {
                "nameIdentifier": [
                  {
                    "legalPersonName": "(주)코인원",
                    "legalPersonNameIdentifierType": "LEGL"
                  }
                ]
              },
              "customerIdentification": "customernumber in Max 50 Text"
            }
          },
          {  // 법인의 대표자
            "naturalPerson": {
              "name": {
                "nameIdentifier": [
                  {
                    "primaryIdentifier": "Barnes",
                    "secondaryIdentifier": "Robert",
                    "nameIdentifierType": "LEGL"
                  }
                ],
                "localNameIdentifier": [
                  {
                    "primaryIdentifier": "로버트 반스",
                    "secondaryIdentifier": "",
                    "nameIdentifierType": "LEGL"
                  }
                ]
              }
            }
          }
        ],
        "accountNumber": ["rJChk8e71gxVhyJSr1srzZxWhVisWMMYKZ:tag or memo"]  // 전송 고객의 지갑 주소:Tag or memo
      },
      "Beneficiary" : {
        "beneficiaryPersons": [
          {
            "naturalPerson": {
              "name": {
                "nameIdentifier": [
                  {
                    "primaryIdentifier": "Smith",
                    "secondaryIdentifier": "Alice",
                    "nameIdentifierType": "LEGL"
                  }
                ],
                "localNameIdentifier": [
                  {
                    "primaryIdentifier": "앨리스 스미스",
                    "secondaryIdentifier": "",
                    "nameIdentifierType": "LEGL"
                  }
                ]
              }
            }
          }
        ],
        "accountNumber": ["rHcFoo6a9qT5NHiVn1THQRhsEGcxtYCV4d:tag or memo"] // 수신 고객의 지갑 주소:Tag or memo
      },
      "OriginatingVASP": {
        "originatingVASP": {
          "legalPerson": {
            "name": {
              "nameIdentifier": [
                {
                  "legalPersonName": "Korbit Inc.",
                  "legalPersonNameIdentifierType": "LEGL"
                }
              ]
            },
            "geographicAddress": [
              {
                "addressType":"GEOG",
                "townName":"Seoul",
                "addressLine": ["100 Teheran-ro 1-gil, Gangnam-gu", "10th floor"],
                "country":"KR"
              }
            ],
            "nationalIdentification": {
              "nationalIdentifier": "사업자번호",
              "nationalIdentifierType": "RAID",
              "registrationAuthority": "RA000657"
            },
            "countryOfRegistration": "KR"
          }
        }
      }
    }
  }
}           

Response

200 OK

RESPONSE SCHEMA: application/json

  • result(Required): 가상 자산의 이전 허가 결과입니다.

    • verified: 허가된 경우 반환합니다.

    • denied: 자산 이전을 거부한 경우 반환합니다. reasonType값으로 상세 내용을 구분합니다.

  • reasonType(Optional): denied 인 경우, 이유에 해당하는 필드를 추가합니다.

    • NOT_FOUND_ADDRESS: 가상 자산 주소를 찾을 수 없는 경우입니다.

    • NOT_SUPPORTED_SYMBOL: 거래할 수 없는 화폐 심볼입니다.

    • NOT_KYC_USER: 수신 주소의 소유자가 KYC 인증을 진행하지 않은 경우입니다.

    • INPUT_NAME_MISMATCHED: 요청 메시지로 전송한 수취인 이름이 실제 소유자의 이름과 일치하지 않는 경우입니다.

    • SANCTION_LIST: 가상 자산 주소 또는 소유자가 수취 VASP 의 제재 대상입니다.

    • LACK_OF_INFORMATION: 자산 이전을 결정하는데 필요한 정보가 없을 경우입니다.

    • UNKNOWN: 그 밖에 다른 이유입니다.

  • reasonMsg(Optional): reasonType 을 추가 설명하는 메시지.

  • transferId(Required): '자산 이전 허가 요청' 부터는 이후 프로세스가 실행되는 중에 트랜잭션 상태를 추적할 고유 아이디가 필요합니다. 요청을 보내는 클라이언트에서 UUID 를 생성해서 보냅니다.

  • beneficiaryVasp(Optional, 대소문자 주의): VerifyVASP 로부터 들어오는 응답에 한하여 암호화 영역인 payload 외부에 beneficiaryVASP 객체가 포함되어 있습니다. 만약, payload 밖에 beneficiaryVASP 객체가 있으면 payload 영역의 ivms101 에 덮어 써주세요.

  • payload(Required): IVMS101 메시지를 담기 위한 객체입니다.

    • ivms101(Required): IVMS101 메시지 표준을 따르는 송금인(Originator), 수취인(Beneficiary), 송신 VASP(OriginatorVASP), 수취VASP(BeneficiaryVASP) 등 가상자산 이전에 관여하는 각 주체를 IVMS101 국제 표준에 맞춰서 정의한 객체입니다. 응답(response) 객체에서는 Originator, OriginatingVASP 정보는 요청(request)의 데이터를 복사하고, Beneficiary, BeneficiaryVASP 데이터는 수신 VASP 의 정보를 기준으로 작성합니다.

      • Originator(Required): 자산을 전송하고자 하는 송금인(개인) 또는 법인 및 대표자에 대한 정보로 요청의 값을 그대로 복사해서 사용합니다.

      • Beneficiary(Required): 자산을 수신하는 수취인(개인) 또는 법인 및 대표자에 대한 정보입니다. 응답(response) 에서는 이름과 자산 주소를 기입해서 보내야 합니다.

        • beneficiaryPersons(Required): 상위 객체인 Beneficiary 객체에 반드시 포함되어야 하며 구조는 originatorPersons 와 같으므로 요청의 originatorPersons 설명을 참고해 주세요.

          • naturalPerson(Required): 개인에 대한 정보를 설정하기 위한 객체로 name(이름) 정보를 필수로 설정해야 한다.

          • legalPerson(Optional): 법인에 대한 정보를 설정하기 위한 객체로 name(이름) 정보를 필수로 설정해야 한다.

        • accountNumber(Required): 자산을 수신하는 지갑 주소입니다. tag 나 memo 값이 필요한 경우는 ':' 로 구분해서 하나의 문자열로 만듭니다.

      • OriginatingVASP(Required): 자산을 전송하려는 송신 VASP 정보입니다. 요청의 값을 그대로 복사해서 사용합니다.

      • BeneficiaryVASP(Required): 자산을 수신하는 수취 VASP 정보입니다. 구조는 OriginatingVASP 와 같으므로 요청의 OriginatingVASP 설명을 참고해 주세요.

{
  "result": "string",
  "reasonType": "",
  "reasonMsg": "",
  "transferId": "string",
  "beneficiaryVasp": {
  },
  "payload": {
    "ivms101": {
      "Originator": {
        "originatorPersons": [
          // 개인일 경우 배열의 첫번째 요소에 naturalPerson 하나만 입력
          {
            "naturalPerson": {
              "name": {
                "nameIdentifier": [
                  {
                    "primaryIdentifier": "로버트 반스",
                    "secondaryIdentifier": "",
                    "nameIdentifierType": "LEGL"
                  }
                ]
              },
              "customerIdentification": "customernumber in Max 50 Text"
            }
          },
          // 법인일 경우 배열의 첫번째 요소에 legalPerson 을 입력하고,
          // 두번째 요소부터 naturalPerson(대표자) 정보를 입력
          {  // 법인 정보
            "legalPerson": {
              "name": {
                "nameIdentifier": [
                  {
                    "legalPersonName": "(주)코인원",
                    "legalPersonNameIdentifierType": "LEGL"
                  }
                ]
              },
              "customerIdentification": "customernumber in Max 50 Text"
            }
          },
          {  // 법인의 대표자
            "naturalPerson": {
              "name": {
                "nameIdentifier": [
                  {
                    "primaryIdentifier": "로버트 반스",
                    "secondaryIdentifier": "",
                    "nameIdentifierType": "LEGL"
                  }
                ]
              }
            }
          }
        ],
        "accountNumber": ["rJChk8e71gxVhyJSr1srzZxWhVisWMMYKZ:tag or memo"]  // 송금 고객의 지갑 주소:Tag or memo
      },
      "Beneficiary": {
        "beneficiaryPersons": [
          // 개인일 경우 배열의 첫번째 요소에 naturalPerson 하나만 입력
          {
            "naturalPerson": {
              "name": {
                "nameIdentifier": [
                  {
                    "primaryIdentifier": "로버트 반스",
                    "secondaryIdentifier": "",
                    "nameIdentifierType": "LEGL"
                  }
                ]
              },
              "customerIdentification": "customernumber in Max 50 Text"
            }
          },
          // 법인일 경우 배열의 첫번째 요소에 legalPerson 을 입력하고,
          // 두번째 요소부터 naturalPerson(대표자) 정보를 입력
          {  // 법인 정보
            "legalPerson": {
              "name": {
                "nameIdentifier": [
                  {
                    "legalPersonName": "(주)코인원",
                    "legalPersonNameIdentifierType": "LEGL"
                  }
                ]
              },
              "customerIdentification": "customernumber in Max 50 Text"
            }
          },
          {  // 법인의 대표자
            "naturalPerson": {
              "name": {
                "nameIdentifier": [
                  {
                    "primaryIdentifier": "로버트 반스",
                    "secondaryIdentifier": "",
                    "nameIdentifierType": "LEGL"
                  }
                ]
              }
            }
          }
        ],
        "accountNumber": [ "rHcFoo6a9qT5NHiVn1THQRhsEGcxtYCV4d:tag or memo" ] // 수신 고객의 지갑 주소:Tag or memo
      },
      "OriginatingVASP": {
        "originatingVASP": {
          "legalPerson": {
            "name": {
              "nameIdentifier": [
                {
                  "legalPersonName": "Korbit Inc.",
                  "legalPersonNameIdentifierType": "LEGL"
                }
              ]
            },
            "geographicAddress": [
              {
                "addressType":"GEOG",
                "townName":"Seoul",
                "addressLine": ["100 Teheran-ro 1-gil, Gangnam-gu", "10th floor"],
                "country":"KR"
              }
            ],
            "nationalIdentification": {
              "nationalIdentifier": "사업자번호",
              "nationalIdentifierType": "RAID",
              "registrationAuthority": "RA000657"
            },
            "countryOfRegistration": "KR"
          }
        }
      },
      "BeneficiaryVASP": {
        "beneficiaryVASP": {
          "legalPerson": {
            "name": {
              "nameIdentifier": [
                {
                  "legalPersonName": "Coinone Inc.",
                  "legalPersonNameIdentifierType": "LEGL"
                }
              ]
            },
            "geographicAddress": [
              {
                "addressType":"GEOG",
                "townName":"Seoul",
                "addressLine": ["100 Teheran-ro 1-gil, Gangnam-gu", "10th floor"],
                "country":"KR"
              }
            ],
            "nationalIdentification": {
              "nationalIdentifier": "6948624434",
              "nationalIdentifierType": "RAID",
              "registrationAuthority": "RA000657"
            },
            "countryOfRegistration": "KR"
          }
        }
      }
    }
  }
}

Last updated