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

# 이메일 OTP 전송 API: 이메일 인증 코드 발송

> POST /v3/email/send/로 일회용 인증 코드를 보내세요. 전송 불가 시 자동 재시도, 5분 유효, 사용량 기준 요금, 월 최소 약정 없음. Didit API.



## OpenAPI

````yaml ko/openapi-25.json POST /v3/email/send/
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/email/send/:
    post:
      tags:
        - Standalone APIs
      summary: 이메일 코드 전송
      description: >-
        이메일 주소로 일회용 코드(OTP)를 전송한 다음, [`POST
        /v3/email/check/`](/ko/standalone-apis/email-check)를 통해 확인합니다.


        **전송과 확인의 연계 방식.** 인증 상태는 애플리케이션 및 `email` 주소를 키로 관리되며, 확인 호출에는
        `request_id`가 전달되지 않습니다. 새로 전송할 때마다 **5분** 동안 유효한 대기 상태의 인증이 생성됩니다. 유효
        시간이 만료되기 전에 동일한 주소 및 사용자가 수신한 코드로 확인을 호출하십시오. 인증이 대기 중인 상태에서 동일한 주소로 전송을
        다시 호출하면 해당 인증에 대한 새 코드가 생성되며(`status: "Retry"`, 동일한 `request_id`), 이전
        코드는 더 이상 작동하지 않습니다. 이 방식으로 최대 1회의 재시도가 연결되며(총 2회 전송), 추가로 전송하면 새
        `request_id`를 가진 새로운 인증이 시작됩니다. 5분의 유효 시간은 첫 번째 전송 시점부터 측정되며 재시도로 연장되지
        않습니다.


        **전송 가능 여부 사전 확인.** 전송이 이루어지기 전에 해당 주소의 구문 및 DNS/MX 검증이 진행됩니다. 메일을 수신할 수
        없는 주소는 `status: "Undeliverable"` 및 `reason:
        "email_can_not_be_delivered"`와 함께 `200`을 반환합니다. 이메일은 전송되지 않고 결제도 청구되지
        않으며, 인증은 즉시 `Declined`로 완료 처리됩니다(이후 확인을 호출하면 `Expired or Not Found`가
        반환됨). 주소 외의 원인으로 전송에 실패한 경우(이메일을 전송을 위해 인계하지 못한 경우) 대신 `503`이 반환됩니다. 코드가
        전송되지 않고 요금도 청구되지 않으며, 인증은 열린 상태로 유지되므로 동일한 요청을 다시 시도할 수 있습니다.


        **코드 형식 및 브랜딩.** 코드는 4~8자(`options.code_size`, 기본값 6)이며 기본적으로 숫자입니다.
        대문자와 숫자를 사용하려면 `options.alphanumeric_code: true`로 설정하십시오(확인 시 대소문자를 구분하지
        않고 비교함). 이메일 템플릿은 `options.locale`(54개 지원 언어)을 통해 현지화되며,
        `options.use_white_label_customization`을 통해 애플리케이션의 화이트 라벨 브랜딩을 적용할 수
        있습니다.


        **결제.** 성공한 전송(`status: "Success"`) 건당 1개의 이메일 인증 API 크레딧이 전송 시점에 청구됩니다.
        `Retry` 및 `Undeliverable` 전송은 무료이며, 확인 또한 무료입니다.


        **세션 지속성.** 모든 새로운 인증은 API 유형 세션으로 유지됩니다. `request_id`는 `GET
        /v3/session/{sessionId}/decision/`에 전달할 수 있는 실제 세션 ID이며, 인증 내역은 Business
        Console에 표시되고 진행 상황에 따라 `status.updated` webhook이 발생합니다.


        **샌드박스.** 샌드박스 API 키는 전송 및 결제를 건너뜁니다. 요청 유효성 검사(형식이 잘못된 입력은 여전히 `400`
        반환) 후 endpoint는 임의의 `request_id`가 포함된 정적 `Success` payload를 반환합니다. 이메일은
        전송되지 않으며 아무것도 저장되지 않습니다. 샌드박스 확인에는 코드 `123456`을 사용하십시오.


        **인증.** `x-api-key` 헤더에 애플리케이션의 API 키를 전달하십시오. 자격 증명이 누락되었거나 유효하지 않은 경우
        `403`(`{"detail": "You do not have permission to perform this
        action."}`)이 반환됩니다. 이 API는 `401`을 반환하지 않습니다.


        **속도 제한.** 모든 POST/PATCH/DELETE endpoint에 걸쳐 API 키당 분당 300개의 쓰기 요청 한도가
        공유되며, 이를 초과하면 `429`가 반환됩니다.
      operationId: post_v3email_send
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                  description: >-
                    수취인 이메일 주소입니다. 형식이 잘못된 주소는 `400`을 반환합니다. 문법적으로는 유효하지만 메일을
                    수신할 수 없는 주소(DNS/MX 검증 실패)는 `status: "Undeliverable"`과 함께
                    `200`을 반환합니다.
                  example: alice@example.com
                options:
                  type: object
                  description: OTP 형식, 현지화 및 브랜딩 옵션입니다. 모든 필드는 선택 사항입니다.
                  properties:
                    code_size:
                      type: integer
                      minimum: 4
                      maximum: 8
                      default: 6
                      description: >-
                        OTP의 문자 수입니다(기본적으로 숫자이며, `alphanumeric_code`가 `true`인 경우
                        대문자 및 숫자입니다).
                    alphanumeric_code:
                      type: boolean
                      default: false
                      description: >-
                        `true`인 경우 OTP가 숫자만으로 구성되는 대신 대문자 `A–Z`와 숫자 `0–9`로
                        구성됩니다. `/v3/email/check/` 비교는 대소문자를 구분하지 않습니다.
                    locale:
                      type: string
                      maxLength: 5
                      enum:
                        - en
                        - ar
                        - bn
                        - bg
                        - bs
                        - ca
                        - cs
                        - da
                        - de
                        - el
                        - es
                        - et
                        - fa
                        - fi
                        - fr
                        - he
                        - hi
                        - hr
                        - hu
                        - hy
                        - id
                        - it
                        - ja
                        - ka
                        - kk
                        - ko
                        - ky
                        - lt
                        - lv
                        - cnr
                        - mk
                        - mn
                        - ms
                        - nl
                        - 'no'
                        - pl
                        - pt-BR
                        - pt
                        - ro
                        - ru
                        - sk
                        - sl
                        - so
                        - sq
                        - sr
                        - sv
                        - th
                        - tr
                        - uk
                        - uz
                        - vi
                        - zh-CN
                        - zh-TW
                        - zh
                      description: >-
                        OTP 이메일 템플릿의 언어입니다. 기본값은 `en`입니다. 지원되지 않는 값은 지원되는 모든 로캘을
                        나열하는 `400`을 반환합니다.
                      example: en
                    use_white_label_customization:
                      type: boolean
                      default: false
                      description: >-
                        `true`인 경우 OTP 이메일에 기본 Didit 템플릿 대신 애플리케이션의 화이트 라벨 맞춤
                        설정(로고, 색상, 발신자 브랜딩)이 사용됩니다.
                signals:
                  type: object
                  description: >-
                    최종 사용자에 대한 선택적 기기 및 네트워크 신호로, 어뷰징 또는 자동화된 트래픽 감지를 개선하기 위해 사기
                    방지 계층으로 전달됩니다. 모든 필드는 선택 사항입니다.
                  properties:
                    ip:
                      type: string
                      description: 최종 사용자 기기의 주소입니다. IPv4 또는 IPv6입니다.
                      example: 192.0.2.1
                    device_id:
                      type: string
                      maxLength: 255
                      description: >-
                        최종 사용자 기기의 고유 식별자입니다. Android: `ANDROID_ID`, iOS:
                        `identifierForVendor`.
                      example: 8F0B8FDD-C2CB-4387-B20A-56E9B2E5A0D2
                    device_platform:
                      type: string
                      enum:
                        - android
                        - ios
                        - ipados
                        - tvos
                        - web
                      description: 최종 사용자 기기의 플랫폼입니다.
                    device_model:
                      type: string
                      maxLength: 255
                      description: 최종 사용자 기기의 모델입니다.
                      example: iPhone17,2
                    os_version:
                      type: string
                      maxLength: 64
                      description: 최종 사용자 기기의 운영체제 버전입니다.
                      example: 18.0.1
                    app_version:
                      type: string
                      maxLength: 64
                      description: 애플리케이션의 버전입니다.
                      example: 1.2.34
                    user_agent:
                      type: string
                      maxLength: 512
                      description: 최종 사용자의 브라우저 또는 앱의 사용자 에이전트입니다.
                      example: >-
                        Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X)
                        AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3
                        Mobile/15E148 Safari/604.1
                vendor_data:
                  type: string
                  description: >-
                    세션에 유지되고 전송 응답, 일치 확인 응답, webhook 및 Business Console에 그대로
                    반환되는 선택적 호출자 제어 식별자(내부 사용자 ID, 이메일, UUID 등)입니다. Didit의
                    `request_id`를 사용자 레코드와 연결하는 데 사용하십시오.
                metadata:
                  type: object
                  nullable: true
                  description: >-
                    세션에 유지되고 전송 응답, 일치 확인 응답, webhook 및 Business Console에 다시
                    반환되는 선택적 자유 형식 JSON 객체입니다.
              required:
                - email
            examples:
              Numeric 6-digit code:
                summary: 기본값 — 영어로 된 6자리 숫자 코드
                value:
                  email: alice@example.com
                  options:
                    locale: en
                  vendor_data: user-1234
              Alphanumeric 8-character code:
                summary: 대문자 영문 + 숫자, 스페인 템플릿
                value:
                  email: bob@example.com
                  options:
                    code_size: 8
                    alphanumeric_code: true
                    locale: es
              White-label branding:
                summary: 애플리케이션의 화이트 라벨 맞춤 설정을 적용하여 OTP 이메일을 전송합니다.
                value:
                  email: carol@example.com
                  options:
                    locale: en
                    use_white_label_customization: true
                  vendor_data: user-5678
      responses:
        '200':
          description: >-
            전송이 확인되었습니다. `status`를 확인하십시오. `Success` 및 `Retry`는 코드가 발송 중임을 의미하며,
            `Undeliverable`은 해당 주소로 메일을 받을 수 없어 인증이 이미 `Declined`로 완료되었음을 의미합니다.
            `request_id`는 유지되는 세션 ID입니다(`Retry` 시 동일한 ID).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EmailVerificationSendResponse'
              examples:
                Success:
                  summary: 새 인증을 위해 이메일로 전송된 OTP(과금됨)
                  value:
                    request_id: e39cb057-92fc-4b59-b84e-02fec29a0f24
                    status: Success
                    reason: null
                    vendor_data: user-1234
                    metadata: null
                Retry:
                  summary: 5분 기간 내 두 번째 발송 — 새로운 코드, 동일한 request_id, 무료
                  value:
                    request_id: e39cb057-92fc-4b59-b84e-02fec29a0f24
                    status: Retry
                    reason: null
                    vendor_data: user-1234
                    metadata: null
                Undeliverable:
                  summary: 주소가 DNS/MX 유효성 검사에 실패함 — 인증이 거부됨으로 최종 처리되었으며 요금이 청구되지 않음
                  value:
                    request_id: cb1a5011-344d-444d-bdce-218904745d7f
                    status: Undeliverable
                    reason: email_can_not_be_delivered
                    vendor_data: user-1234
                    metadata: null
        '400':
          description: >-
            검증 오류 — DRF의 필드 오류 엔벨로프: 문제가 있는 필드당 하나의 메시지 배열, 옵션 오류의 경우 `options`
            아래에 중첩됩니다.
          content:
            application/json:
              examples:
                Invalid email:
                  summary: 잘못된 형식의 이메일 주소
                  value:
                    email:
                      - Enter a valid email address.
                Unsupported locale:
                  summary: '`options.locale`이 지원되는 집합을 벗어남'
                  value:
                    options:
                      locale:
                        - >-
                          Invalid locale. Supported locales are en, ar, bn, bg,
                          bs, ca, cs, da, de, el, es, et, fa, fi, fr, he, hi,
                          hr, hu, hy, id, it, ja, ka, kk, ko, ky, lt, lv, cnr,
                          mk, mn, ms, nl, no, pl, pt-BR, pt, ro, ru, sk, sl, so,
                          sq, sr, sv, th, tr, uk, uz, vi, zh-CN, zh-TW, zh.
                Code size out of range:
                  summary: '`options.code_size`가 4–8 범위를 벗어남'
                  value:
                    options:
                      code_size:
                        - Ensure this value is less than or equal to 8.
        '403':
          description: >-
            권한이 거부되었습니다. `x-api-key` 헤더가 누락되었을 때 반환됩니다(`{"detail": ...}`).
            잘못되었거나 취소되었거나 만료된 키는 `401`을 반환합니다. 또한 발송 전에 조직의 잔액이 이메일 인증 API 크레딧
            1건을 충당할 수 없을 때도 반환됩니다(`{"error": ...}`).
          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.
        '429':
          description: >-
            속도 제한을 초과했습니다. POST/PATCH/DELETE endpoint는 API 키당 분당 300회의 쓰기 요청 한도를
            공유합니다(거래 생성 및 이벤트 수집은 별도로 600회 한도 적용). 응답에는 `X-RateLimit-Limit`,
            `X-RateLimit-Remaining`, `X-RateLimit-Reset`, `Retry-After` 헤더가
            포함됩니다.
          content:
            application/json:
              examples:
                Write rate limit exceeded:
                  summary: 현재 분 동안 300건을 초과하는 쓰기 요청 발생
                  value:
                    detail: >-
                      Write request rate limit exceeded. You can make up to 300
                      requests per minute.
              schema:
                type: object
                properties:
                  detail:
                    type: string
        '503':
          description: >-
            이메일 주소와 무관한 이유(이메일 제공업체 연결 불가, 시간 초과 또는 전송 자체 거부)로 이메일을 전송할 수 없었습니다.
            따라서 코드가 전송되지 않았으며 결제나 전송 시도 횟수로 집계되지 않았습니다. 동일한 요청을 다시 시도하세요.
          content:
            application/json:
              examples:
                Email delivery unavailable:
                  summary: 1회 자동 재시도 후 이메일 제공업체 오류가 발생했습니다.
                  value:
                    detail: >-
                      Email delivery is temporarily unavailable. Please try
                      again.
              schema:
                type: object
                properties:
                  detail:
                    type: string
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: curl
          source: |-
            curl -X POST https://verification.didit.me/v3/email/send/ \
              -H 'x-api-key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{
                "email": "alice@example.com",
                "options": { "code_size": 6, "locale": "en" },
                "vendor_data": "user-1234"
              }'
        - lang: python
          label: Python
          source: |-
            from didit import Didit

            # Reads DIDIT_API_KEY.
            client = Didit()

            result = client.email.send_code(
                email="alice@example.com",
                options={
                    "locale": "en",
                },
                vendor_data="user-1234",
            )
            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.email.sendCode({
              email: "alice@example.com",
              options: {
                locale: "en",
              },
              vendor_data: "user-1234",
            });
            console.log(result);
        - lang: go
          label: Go
          source: "ctx := context.Background()\n// Reads DIDIT_API_KEY.\nclient := didit.NewClient()\n\nresult, err := client.Email.SendCode(ctx, didit.EmailSendCodeParams{\n\tEmail: \"alice@example.com\",\n\tOptions: didit.Some(didit.EmailSendCodeParamsOptions{\n\t\tLocale: didit.Some(didit.EmailSendCodeParamsOptionsLocale(\"en\")),\n\t}),\n\tVendorData: didit.String(\"user-1234\"),\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.EmailSendCodeParams;

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

            var result = client.email().sendCode(EmailSendCodeParams.builder()
                    .email("alice@example.com")
                    .options(EmailSendCodeParams.Options.builder()
                            .locale(EmailSendCodeParams.Options.Locale.of("en"))
                            .build())
                    .vendorData("user-1234")
                    .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->email->sendCode([
                'email' => 'alice@example.com',
                'options' => [
                    'locale' => 'en',
                ],
                'vendor_data' => 'user-1234',
            ]);
            print_r($result->toArray());
        - lang: ruby
          label: Ruby
          source: |-
            require "didit"

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

            result = didit.email.send_code(
              email: "alice@example.com",
              options: {
                locale: "en",
              },
              vendor_data: "user-1234"
            )
            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.Email.SendCodeAsync(new
            EmailSendCodeParams

            {
                Email = "alice@example.com",
                Options = new EmailSendCodeParamsOptions
                {
                    Locale = new EmailSendCodeParamsOptionsLocale("en"),
                },
                VendorData = "user-1234",
            });

            Console.WriteLine(JsonSerializer.Serialize(result));
components:
  schemas:
    EmailVerificationSendResponse:
      type: object
      properties:
        request_id:
          type: string
          format: uuid
          description: >-
            인증의 세션 id입니다. `Retry` 전송은 최초 전송과 동일한 `request_id`를 반환합니다. 이 id는
            Business Console에 표시되며, 완료된 `POST /v3/email/check/`에 의해 다시 반환되고,
            `GET /v3/session/{sessionId}/decision/`에 전달할 수 있습니다.
        status:
          type: string
          enum:
            - Success
            - Retry
            - Undeliverable
          description: >-
            `Success` — 새 인증에 OTP가 이메일로 전송되었습니다(요금 청구됨). `Retry` — 이전 전송으로 생성된
            대기 중인 인증에 새 OTP가 이메일로 재전송되었습니다(무료). `Undeliverable` — 주소 전송 가능성 검증에
            실패했거나 메시지를 보낼 수 없습니다. 인증은 즉시 `Declined` 상태로 완료 처리되며 요금은 청구되지 않습니다.
        reason:
          type: string
          nullable: true
          enum:
            - email_can_not_be_delivered
            - null
          description: >-
            `status`가 `Undeliverable`인 경우 `email_can_not_be_delivered`, 그 외의 경우
            `null`.
        vendor_data:
          type: string
          nullable: true
          description: 세션에 저장된 `vendor_data`의 에코 값입니다(첫 전송 기준).
        metadata:
          type: object
          nullable: true
          description: 세션에 저장된 `metadata`의 에코 값입니다(첫 전송 기준).
  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.