> ## 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.

# IP 위험 API: 위치, VPN 및 데이터센터 신호

> Didit의 IP 위험 API는 위치, ISP, VPN/Tor, 데이터센터, 위협, 주장 국가 불일치 신호로 IP의 위험 점수를 산정합니다.

`POST /v3/ip/risk/`는 백엔드가 이미 IP 주소를 보유하고 있으며 서버 간 위험 판정이 필요할 때 사용합니다.

응답에는 지리적 위치, 네트워크 소유자, VPN/Tor 및 데이터 센터 플래그, 위협 데이터가 포함됩니다. 제시한 국가를 보내면 `country_mismatch`도 포함됩니다.

## 응답 해석

* `status`는 확인된 국가가 `claimed_country`와 충돌하거나, 해당 주소가 VPN, Tor 또는 데이터 센터 인프라와 연관된 경우 `In Review`입니다. 그 외에는 `Approved`입니다.
* `ip.ip_country_code`에는 확인된 국가 코드가 담깁니다. 국가 문자열을 직접 비교하지 말고 `ip.country_mismatch`로 비교하십시오.
* `ip.latitude`와 `ip.longitude`는 대략적인 네트워크 지리 위치이며, 정확한 기기 위치가 아닙니다.
* `ip.is_vpn_or_tor`, `ip.is_data_center`, `ip.proxy_type`, `ip.threat`는 네트워크 위험 근거를 나타냅니다.
* `ip.asn_number`, `ip.asn_organization`, `ip.connection_type`, `ip.carrier`는 해당 주소가 속한 네트워크를 설명합니다.
* `request_id`는 API 세션 ID입니다. 결과를 나중의 webhook이나 콘솔 활동과 연관지어야 하면 `vendor_data`와 함께 저장하십시오.

> [!NOTE]
>
> IP 정보 보강은 최선의 노력 방식으로 제공됩니다. 어떤 보강 소스도 사용 가능한 데이터를 반환하지 않으면, endpoint는 `ip.ip_address: null`, `ip.country_mismatch: null`, 빈 `ip.threat` 객체를 포함한 승인 응답을 반환합니다. 개별 보강 필드도 사용할 수 없는 경우 `null`일 수 있습니다.

## 기기 인텔리전스

IP Risk API는 순수한 서버 간 endpoint입니다. 기기 핑거프린팅은 서버 간 방식만으로는 수행할 수 없습니다. 백엔드만으로는 브라우저나 기기 신호를 관찰할 수 없기 때문입니다. 호스팅 플로우와 SDK 세션의 경우, Didit은 세션 응답에 이미 수집된 기기 필드를 노출합니다. 여기에는 `device_fingerprint`, 기기 및 브라우저 세부 정보, `user_agent`, 원시 기기 데이터, 세션 간 일치 항목이 포함됩니다.

## 샌드박스 동작

샌드박스 키는 요청을 검증하고 항상 동일한 승인 데이터를 반환합니다. 외부 인텔리전스 서비스에 연결하지 않으며, 크레딧을 소비하지 않고, 세션을 생성하지 않으며, Networks에 기여하지 않습니다.

## 결제

IP Risk API 호출은 정가 기준 \$0.02입니다. 프로덕션 환경 요청은 조회가 시작되는 순간부터 과금됩니다.


## OpenAPI

````yaml ko/openapi-25.json POST /v3/ip/risk/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: 신분증 인증 API입니다. x-api-key 헤더로 인증합니다.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/ip/risk/:
    post:
      tags:
        - Standalone APIs
      summary: IP 주소 위험 점수 산정
      description: >-
        제공된 IP 주소에 대한 지리적 위치, 네트워크 소유권, VPN/Tor 및 데이터 센터 플래그, 위협 데이터,
        `country_mismatch`를 반환합니다. 이 endpoint는 API 세션을 생성하고 해당 ID를 `request_id`로
        반환합니다.


        **결정.** 확인된 국가가 `claimed_country`와 충돌하거나, 해당 주소가 VPN, Tor 또는 데이터 센터 인프라와
        연결되어 있는 경우 `status`는 `In Review`가 됩니다. 그렇지 않은 경우 `Approved`입니다.


        **최선의 노력.** IP 보강은 최선의 노력으로 제공됩니다. 사용할 수 있는 데이터를 반환하는 보강 소스가 없는 경우,
        endpoint는 `ip.ip_address: null`, `ip.country_mismatch: null` 및 빈
        `ip.threat` 객체가 포함된 승인된 응답을 반환합니다.


        **결제.** 프로덕션 호출에는 IP Risk API 요금이 적용됩니다. 조회가 시작되면 요청에 대한 요금이 청구됩니다.


        **샌드박스.** 샌드박스 키는 크레딧을 소비하거나 세션을 생성하거나 Networks에 기여하지 않고, 요청을 검증한 후
        결정론적인 승인 데이터를 반환합니다.


        **인증.** 애플리케이션의 API 키를 `x-api-key`에 넣어 전송하십시오. 인증 정보가 누락되었거나 유효하지 않은 경우
        `403`을 반환하며, 이 API는 `401`을 절대 반환하지 않습니다.


        **속도 제한.** POST/PATCH/DELETE endpoint 전반에 걸쳐 API 키당 분당 300개의 쓰기 요청 예산이
        공유됩니다(거래 생성 및 이벤트 수집은 별도로 600개의 예산이 배정됨).
      operationId: post_v3ip_risk
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IPRiskRequest'
            examples:
              Minimal:
                summary: 기본값으로 주소 점수 산정
                value:
                  ip_address: 8.8.8.8
              With claimed country:
                summary: 불일치 감지를 위한 신고 국가를 포함한 점수 산정
                value:
                  ip_address: 8.8.8.8
                  claimed_country: ESP
                  user_agent: >-
                    Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
                    AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4
                    Safari/605.1.15
                  vendor_data: lead-123
      responses:
        '200':
          description: >-
            위험 평가가 완료되었습니다. 결정 사항은 `status`를 확인하십시오. 완료된 조회의 경우 HTTP는 항상
            `200`입니다.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IPRiskResponse'
              examples:
                Clean residential IP:
                  summary: 거주지 주소, 명시된 국가가 일치함
                  value:
                    request_id: 9a96ed2a-721e-4b86-8cbf-d61eda529279
                    status: Approved
                    ip:
                      status: Approved
                      ip_address: 192.0.2.10
                      ip_country: Spain
                      ip_country_code: ES
                      ip_state: Madrid
                      ip_city: Madrid
                      latitude: 40.4168
                      longitude: -3.7038
                      isp: Example Telecom
                      organization: Example Telecom SA
                      is_vpn_or_tor: false
                      is_data_center: false
                      time_zone: Europe/Madrid
                      time_zone_offset: '+0200'
                      asn_number: 3352
                      asn_organization: EXAMPLE-TELECOM
                      connection_type: broadband
                      carrier: Example Telecom
                      proxy_type: null
                      claimed_country: ESP
                      country_mismatch: false
                      threat: {}
                    vendor_data: lead-123
                    metadata: null
                    created_at: '2026-09-01T10:30:00.123456+00:00'
                Datacenter mismatch:
                  summary: 신고된 국가와 충돌하는 데이터 센터 주소
                  value:
                    request_id: 5b1d4e9a-3c7b-4f8e-9a2d-1b0c9d8e7f6a
                    status: In Review
                    ip:
                      status: In Review
                      ip_address: 8.8.8.8
                      ip_country: United States
                      ip_country_code: US
                      ip_state: California
                      ip_city: Mountain View
                      latitude: 37.386
                      longitude: -122.0838
                      isp: Google
                      organization: Google LLC
                      is_vpn_or_tor: true
                      is_data_center: true
                      time_zone: America/Los_Angeles
                      time_zone_offset: '-0700'
                      asn_number: 15169
                      asn_organization: GOOGLE, US
                      connection_type: hosting
                      carrier: null
                      proxy_type: VPN
                      claimed_country: ESP
                      country_mismatch: true
                      threat:
                        is_proxy: true
                        is_data_center: true
                        is_tor: false
                    vendor_data: lead-126
                    metadata: null
                    created_at: '2026-09-01T10:30:00.123456+00:00'
        '400':
          $ref: '#/components/responses/IPRiskValidationError'
        '403':
          $ref: '#/components/responses/RiskPermissionDenied'
        '429':
          $ref: '#/components/responses/RateLimitedWrite'
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: curl
          source: |-
            curl -X POST https://verification.didit.me/v3/ip/risk/ \
              -H 'x-api-key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{
                "ip_address": "8.8.8.8",
                "claimed_country": "ESP",
                "user_agent": "Mozilla/5.0",
                "vendor_data": "lead-123"
              }'
        - lang: python
          label: Python
          source: |-
            from didit import Didit

            # Reads DIDIT_API_KEY.
            client = Didit()

            result = client.ip.assess_risk(
                ip_address="8.8.8.8",
            )
            print(result)
        - lang: javascript
          label: Node.js
          source: |-
            import Didit from "@didit-protocol/sdk-node";

            // Reads DIDIT_API_KEY.
            const didit = new Didit();

            const result = await didit.ip.assessRisk({
              ip_address: "8.8.8.8",
            });
            console.log(result);
        - lang: go
          label: Go
          source: "ctx := context.Background()\n// Reads DIDIT_API_KEY.\nclient := didit.NewClient()\n\nresult, err := client.IP.AssessRisk(ctx, didit.IPRiskRequest{\n\tIPAddress: \"8.8.8.8\",\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nfmt.Printf(\"%+v\\n\", result)"
        - lang: java
          label: Java
          source: |-
            import me.didit.Didit;
            import me.didit.types.IPRiskRequest;

            // Reads DIDIT_API_KEY.
            Didit client = new Didit();

            var result = client.ip().assessRisk(IPRiskRequest.builder()
                    .ipAddress("8.8.8.8")
                    .build());
            System.out.println(result);
        - lang: php
          label: PHP
          source: |-
            <?php

            require 'vendor/autoload.php';

            use Didit\DiditClient;

            // Reads DIDIT_API_KEY.
            $didit = new DiditClient();

            $result = $didit->ip->assessRisk([
                'ip_address' => '8.8.8.8',
            ]);
            print_r($result->toArray());
        - lang: ruby
          label: Ruby
          source: |-
            require "didit"

            # Reads DIDIT_API_KEY.
            didit = Didit::Client.new

            result = didit.ip.assess_risk(ip_address: "8.8.8.8")
            puts result.to_h
        - lang: csharp
          label: .NET
          source: |-
            using System;
            using System.Text.Json;
            using Didit;

            // Reads DIDIT_API_KEY.
            using var client = new DiditClient();

            var result = await client.Ip.AssessRiskAsync(new IPRiskRequest
            {
                IpAddress = "8.8.8.8",
            });
            Console.WriteLine(JsonSerializer.Serialize(result));
components:
  schemas:
    IPRiskRequest:
      type: object
      required:
        - ip_address
      properties:
        ip_address:
          type: string
          format: ip
          description: 점수를 산정할 IPv4 또는 IPv6 주소입니다.
          example: 8.8.8.8
        claimed_country:
          type: string
          maxLength: 3
          description: >-
            사용자 또는 세션에서 주장한 선택적 ISO 3166-1 alpha-2 또는 alpha-3 국가입니다.
            `country_mismatch`를 계산하는 데 사용됩니다.
          example: ESP
        user_agent:
          type: string
          maxLength: 512
          description: 백엔드에서 확인된 사용자 에이전트입니다. 요청 컨텍스트로 저장되며 기기 핑거프린팅 기능은 제공하지 않습니다.
        vendor_data:
          type: string
          description: 이 요청에 대한 안정적인 참조값입니다. API 세션에 저장되며 응답에 그대로 반영됩니다.
        metadata:
          type: object
          nullable: true
          additionalProperties: true
          description: 귀하의 비민감 JSON 메타데이터입니다. API 세션에 저장되며 응답에 그대로 반환됩니다.
    IPRiskResponse:
      type: object
      required:
        - request_id
        - status
        - created_at
      properties:
        request_id:
          type: string
          format: uuid
          description: >-
            이 요청에 대해 생성된 API 세션의 ID입니다. 결과를 향후의 webhook이나 콘솔 활동과 연결해야 하는 경우
            `vendor_data`와 함께 저장하세요.
        status:
          type: string
          enum:
            - Approved
            - In Review
          description: >-
            이 API 세션에 대한 결정: 네트워크 또는 국가 불일치 위험이 있는 경우 `In Review`, 그렇지 않으면
            `Approved`입니다.
        vendor_data:
          type: string
          nullable: true
          description: 전송한 `vendor_data`의 에코 값이며, 전송하지 않은 경우 `null`입니다.
        metadata:
          type: object
          nullable: true
          additionalProperties: true
          description: 전송한 `metadata`의 에코 값이며, 전송하지 않은 경우 `null`입니다.
        created_at:
          type: string
          format: date-time
          description: 이 응답의 타임스탬프입니다.
        ip:
          type: object
          description: >-
            IP 위험 결과입니다. 조회를 통해 사용할 수 있는 데이터가 반환되지 않은 경우 개별 보강 필드는 `null`일 수
            있습니다.
          required:
            - status
            - threat
          properties:
            status:
              type: string
              enum:
                - Approved
                - In Review
              description: >-
                확인된 국가가 `claimed_country`와 충돌하거나, 주소가 VPN, Tor 또는 데이터 센터 인프라와
                연결된 경우 `In Review`. 그렇지 않으면 `Approved`.
            ip_address:
              type: string
              nullable: true
              description: 점수가 산정된 주소입니다. 사용 가능한 데이터를 반환한 보강 소스가 없는 경우 `null`입니다.
            ip_country:
              type: string
              nullable: true
              description: 확인된 국가명입니다.
            ip_country_code:
              type: string
              nullable: true
              description: >-
                확인된 국가 코드입니다. 국가 문자열 원본을 직접 비교하는 대신 `country_mismatch`를 통해 국가를
                비교하십시오.
            ip_state:
              type: string
              nullable: true
              description: 확인된 주 또는 지역입니다.
            ip_city:
              type: string
              nullable: true
              description: 확인된 도시입니다.
            latitude:
              type: number
              nullable: true
              description: 대략적인 네트워크 지리적 위치이며, 정밀한 기기 위치가 아닙니다.
            longitude:
              type: number
              nullable: true
              description: 대략적인 네트워크 지리적 위치이며, 정밀한 기기 위치가 아닙니다.
            isp:
              type: string
              nullable: true
              description: 해당 주소에 서비스를 제공하는 인터넷 서비스 제공업체입니다.
            organization:
              type: string
              nullable: true
              description: 주소 블록을 소유한 조직입니다.
            is_vpn_or_tor:
              type: boolean
              nullable: true
              description: 주소가 VPN 또는 Tor 인프라와 연결되어 있는 경우 `true`입니다.
            is_data_center:
              type: boolean
              nullable: true
              description: 주소가 호스팅 또는 데이터 센터 네트워크에 속한 경우 `true`입니다.
            time_zone:
              type: string
              nullable: true
              description: 확인된 위치의 시간대입니다.
            time_zone_offset:
              type: string
              nullable: true
              description: 확인된 위치의 UTC 오프셋입니다.
            asn_number:
              type: number
              nullable: true
              description: 자율 시스템 번호(ASN)입니다.
            asn_organization:
              type: string
              nullable: true
              description: 자율 시스템을 운영하는 조직입니다.
            connection_type:
              type: string
              nullable: true
              description: '연결 분류(예: `cellular`, `hosting`)입니다.'
            carrier:
              type: string
              nullable: true
              description: 주소가 모바일 네트워크에 속하는 경우의 이동통신사입니다.
            proxy_type:
              type: string
              nullable: true
              description: 주소가 프록시 뒤에 있을 때의 프록시 분류입니다.
            claimed_country:
              type: string
              nullable: true
              description: 전송한 `claimed_country`의 에코 값입니다.
            country_mismatch:
              type: boolean
              nullable: true
              description: >-
                확인된 국가가 `claimed_country`와 다를 때 `true`입니다. 보강 데이터가 없거나 주장된 국가가
                없는 경우 `null`입니다.
            threat:
              type: object
              additionalProperties: true
              description: >-
                데이터 보강 소스에서 제공되는 자유 형식 네트워크 위협 증거(예: `is_proxy`, `is_tor`)입니다.
                보강 데이터를 사용할 수 없는 경우 빈 객체입니다. 안정적인 규약이 아닌 진단 세부 정보로 취급하십시오.
  responses:
    IPRiskValidationError:
      description: 요청 유효성 검사에 실패했습니다.
      content:
        application/json:
          examples:
            Missing IP address:
              summary: IP 주소가 누락되었습니다
              value:
                ip_address:
                  - This field is required.
            Invalid IP address:
              summary: 유효하지 않은 IP 주소
              value:
                ip_address:
                  - Enter a valid IPv4 or IPv6 address.
            Country hint too long:
              summary: 국가 힌트가 너무 김
              value:
                claimed_country:
                  - Ensure this field has no more than 3 characters.
    RiskPermissionDenied:
      description: >-
        API 키가 누락되었거나 유효하지 않거나, 조직이 실시간 조회 비용을 충당할 수 없습니다. 이 API는 절대 `401`을 반환하지
        않습니다.
      content:
        application/json:
          examples:
            Missing or invalid API key:
              summary: '`x-api-key` 헤더가 없거나, 키가 유효하지 않거나 해지되었습니다'
              value:
                detail: You do not have permission to perform this action.
            Not enough credits:
              summary: 조직 잔액이 조회 가격을 충당할 수 없습니다
              value:
                error: You don't have enough credits to perform this request.
    RateLimitedWrite:
      description: >-
        API 키당 분당 300개의 요청을 처리하는 공유 쓰기 속도 제한을 초과했습니다. 다시 시도하기 전에 `Retry-After`를
        준수하십시오.
      content:
        application/json:
          schema:
            type: object
            required:
              - detail
            properties:
              detail:
                type: string
          example:
            detail: >-
              Write request rate limit exceeded. You can make up to 300 requests
              per minute.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Business Console의 Developers -> API keys에서 발급받은 귀하 애플리케이션의 API 키입니다. 기본
        키는 전체 접근 권한을 갖습니다. 이름이 지정된 키는 리소스별 none, read, write 범위로 권한을 제한할 수 있으며
        특정 워크플로나 승인된 세션, IP 주소 목록, 만료일 등으로 제한할 수도 있습니다. 401은 키가 잘못되었거나 폐기되었거나
        만료되었음을 의미합니다. 403은 키가 전송되지 않았거나, 키에 해당 리소스나 작업에 대한 접근 권한이 없거나, 요청이 허용된
        IP 목록 외부 주소에서 발생했음을 의미합니다. 세션 경로에서의 404는 해당 세션이 키의 허용 워크플로 또는 상태 범위를
        벗어났음을 의미합니다. 미디어 접근 권한이 없는 키는 이미지, 비디오, PDF URL을 null로 수신하며, 세션 write
        권한이 없는 키는 세션 링크와 token을 null로 수신합니다.
        https://docs.didit.me/console/api-keys 를 참고하십시오.

````

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