# 이메일 발송 (/docs/api/emails/sendEmail)
**POST /v1/accounts/{accountId}/emails**
```json
{
  "operationId": "sendEmail",
  "summary": "이메일 발송",
  "description": "이메일 한 통을 발송합니다. `from` 은 **이 계정에 등록되고 검증(`verified`)된 도메인의\n주소**여야 합니다 — 도메인 등록·검증은 「이메일 발신 도메인」 API 로 먼저 마치십시오.\n\n### 기본 사용법\n\n```json\n{\n  \"from\": \"no-reply@example.com\",\n  \"to\": [\"customer@gmail.com\"],\n  \"subject\": \"주문이 접수되었습니다\",\n  \"body\": \"주문번호 1024 접수되었습니다.\"\n}\n```\n\n### 첨부\n\n첨부는 **URL 로 전달합니다.** 파일 바이트를 요청 본문에 실을 수 없습니다.\n\n```json\n{\n  \"from\": \"no-reply@example.com\",\n  \"to\": [\"customer@gmail.com\"],\n  \"subject\": \"영수증\",\n  \"body\": \"영수증을 첨부합니다.\",\n  \"attachmentUrl\": [\"https://files.example.com/receipt-1024.pdf\"]\n}\n```\n\n우리가 그 URL 을 **서버에서 내려받아** 메일에 붙입니다. 그래서 URL 은 인증 없이\n접근 가능한 공개 주소여야 하고, 사설 대역(`10.*`·`192.168.*`·`127.*`)이나 클라우드\n메타데이터 주소를 가리키면 `400 attachment_url_not_allowed` 로 거절합니다.\n\n### 수신자와 크기 상한\n\n- **수신자는 to·cc·bcc 를 합쳐 최대 50명**입니다(공급자 제약, 조정 불가).\n  넘으면 `400 too_many_recipients`.\n- **메시지 전체는 5MB** 입니다. ⚠️ 이 값은 **첨부를 base64 로 인코딩한 뒤** 기준이라\n  원본 파일 크기의 약 1.37배로 계산됩니다 — 즉 **원본 파일 기준 약 3.6MB** 까지입니다.\n  넘으면 `400 message_too_large`.\n\n  대부분의 거래 메일(영수증·주문확인·계약서 PDF)은 이 안에 들어갑니다. 더 큰 파일은\n  첨부 대신 **링크로 보내 주세요** — 받는 사람의 메일 서버가 큰 첨부를 거부하는 경우가\n  많아(Gmail 25MB · Outlook 20MB 대) 반송으로 돌아올 가능성이 높습니다.\n\n### 과금 단위는 \"통\"이 아니라 \"수신자\"입니다\n\n⚠️ 한 통을 3명에게 보내면 **3건으로 과금**됩니다. to·cc·bcc 를 가리지 않습니다.\n첨부가 있으면 전송 데이터량도 함께 과금됩니다.\n\n### 발송 결과\n\n이 API 의 `201` 은 **공급자가 접수했다**는 뜻이지 수신함에 도착했다는 뜻이 아닙니다.\n실제 전달·반송·수신거부는 비동기로 확인되며, 그 결과를 보는 API 는 아직 제공하지\n않습니다.",
  "tags": [
    "Emails"
  ],
  "parameters": [
    {
      "name": "accountId",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string"
      },
      "description": "계정 ID",
      "example": "AC1a2b3c4d"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "required": [
            "from",
            "to",
            "subject"
          ],
          "properties": {
            "from": {
              "type": "string",
              "minLength": 3,
              "maxLength": 512,
              "description": "발신 주소. **이 계정에서 검증된 도메인**의 주소여야 합니다.\n\n받는 사람에게 보일 이름을 붙이려면 `표시명 <주소>` 로 보내십시오\n(`\"한국AI통신(고객지원)\" <hello@example.com>` 또는 `한국AI통신 <hello@example.com>`).\n한글 등 비 ASCII 표시명은 우리가 메일 헤더 규격(RFC 2047)에 맞게 인코딩합니다.\n표시명에 특수문자(`(`·`)`·`,`·`:`·`;`·`@`·`[`·`]`·`\\` 등)가 있으면 **반드시\n큰따옴표로 감싸야 합니다** — 따옴표 밖의 괄호는 표준(RFC 5322)상 이름이 아니라\n주석이라, 감싸지 않으면 `400 invalid_email_address` 입니다.\n도메인 검증은 꺾쇠 안의 **주소**로만 합니다. 응답의 `from` 은 같은 RFC 5322\nmailbox 문자열로 돌아옵니다(정규화된 표기). 표시명은 최대 100자이고 줄바꿈을\n넣을 수 없습니다.\n\n검증되지 않았거나 남의 계정 도메인이면 `403 email_domain_not_verified` 입니다.\n도메인이 `pending` 인 동안에도 발신할 수 없습니다 — DNS 레코드를 심고 검증\nAPI 로 `verified` 를 만든 뒤에 쓰십시오.",
              "example": "no-reply@example.com"
            },
            "to": {
              "type": "array",
              "items": {
                "type": "string",
                "format": "email"
              },
              "minItems": 1,
              "description": "수신 주소. `cc`·`bcc` 와 **합쳐** 50명을 넘을 수 없습니다.",
              "example": [
                "customer@gmail.com"
              ]
            },
            "cc": {
              "type": "array",
              "items": {
                "type": "string",
                "format": "email"
              },
              "description": "참조. 수신자 수에 포함됩니다."
            },
            "bcc": {
              "type": "array",
              "items": {
                "type": "string",
                "format": "email"
              },
              "description": "숨은 참조. 수신자 수에 **포함되며 과금됩니다.**\n\n다른 수신자에게는 보이지 않지만 발송 이력에는 남습니다."
            },
            "subject": {
              "type": "string",
              "maxLength": 998,
              "description": "제목. 한글 등 비ASCII 문자를 그대로 쓸 수 있습니다.",
              "example": "주문이 접수되었습니다"
            },
            "body": {
              "type": "string",
              "description": "본문(평문). `html` 과 **둘 중 하나 이상**은 있어야 합니다 — 둘 다 없으면\n`400 body_required` 입니다.\n\n둘 다 주면 수신자의 메일 클라이언트가 표시 가능한 쪽을 고릅니다. HTML 만\n보내는 것보다 평문을 함께 주는 편이 스팸 판정에 유리합니다.",
              "example": "주문번호 1024 접수되었습니다."
            },
            "html": {
              "type": "string",
              "description": "본문(HTML). `body` 와 둘 중 하나 이상 필요합니다.",
              "example": "<p>주문번호 <b>1024</b> 접수되었습니다.</p>"
            },
            "attachmentUrl": {
              "type": "array",
              "items": {
                "type": "string",
                "format": "uri"
              },
              "maxItems": 10,
              "description": "첨부 파일 URL. 우리가 **서버에서 내려받아** 메일에 붙입니다.\n\n- `https` 만 받습니다. 인증 없이 접근 가능해야 합니다.\n- 사설 대역·루프백·클라우드 메타데이터 주소는 `400 attachment_url_not_allowed`.\n- 내려받지 못하면(404·타임아웃 등) `400 attachment_fetch_failed` 이고\n  **메일은 발송되지 않습니다.**\n- 파일명은 URL 경로에서 가져옵니다.\n\n⚠️ 공급자가 거부하는 확장자가 있습니다(실행 파일 등). 그 거부는 발송 시점에\n일어나므로 `502` 로 돌아옵니다 — 요청 검증 단계에서는 걸러지지 않습니다.",
              "example": [
                "https://files.example.com/receipt-1024.pdf"
              ]
            },
            "replyTo": {
              "type": "array",
              "items": {
                "type": "string",
                "format": "email"
              },
              "maxItems": 10,
              "description": "답장 주소(`Reply-To`). 받는 사람이 답장하면 `from` 이 아니라 이 주소로\n갑니다. `no-reply@` 로 보내고 `support@` 로 받는 구성에 씁니다.\n\n⚠️ **스레드와는 무관합니다.** 대화를 잇는 것은 아래 두 필드입니다.",
              "example": [
                "support@example.com"
              ]
            },
            "inReplyTo": {
              "type": "string",
              "maxLength": 200,
              "description": "답장하는 원본 메일의 `Message-ID`. 조회 응답이나 `email.received` webhook 의\n`messageId` 를 그대로 넣으십시오. 꺾쇠(`< >`)는 있어도 없어도 됩니다.\n\n⚠️ 이것만으로는 부족합니다 — 2회차 이후의 답장은 `references` 도 함께\n채워야 여러 클라이언트에서 한 대화로 묶입니다.\n\n⛔ **헤더가 완벽해도 제목이 다르면 Gmail·Outlook 은 새 대화로 엽니다.**\n두 클라이언트는 정규화한 제목을 함께 봅니다. 원본 제목에 `Re: ` 를 붙인\n형태를 그대로 쓰시고, 이미 `Re:` 로 시작하면 덧붙이지 마십시오.",
              "example": "CAF7n8xW1p_abc@mail.gmail.com"
            },
            "references": {
              "type": "array",
              "items": {
                "type": "string",
                "maxLength": 200
              },
              "maxItems": 100,
              "description": "대화의 조상 사슬. **오래된 것이 앞**입니다. 원본 메일 `m` 에 답장한다면\n`[...m.references, m.messageId]` 입니다.\n\n⚠️ 긴 대화는 공급자 헤더 길이 상한(986자) 때문에 **RFC 5537 §3.4.4 에 따라\n줄여서** 보냅니다 — 첫 항목과 최근 항목은 남고 가운데가 빠집니다. 발송은\n실패하지 않으며, **응답의 `references` 가 실제로 나간 목록**입니다.",
              "example": [
                "CAF7n8xW1p_xyz@mail.gmail.com",
                "CAF7n8xW1p_abc@mail.gmail.com"
              ]
            },
            "idempotencyKey": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "description": "발송 멱등키. 같은 계정에서 같은 키로 다시 요청하면 **발송하지 않고**\n1회차 결과를 그대로 돌려줍니다. 재시도 경로가 있는 호출자만 채우십시오.\n\n미지정이면 매번 발송합니다. 빈 문자열은 `400` 입니다 — 템플릿에서 빈 값이\n들어가 멱등이 조용히 꺼진 채 중복 발송되는 걸 막습니다.\n\n키는 **발송 전에** 잡힙니다. 같은 키의 앞선 요청이 아직 처리 중이면(또는\n공급자 접수 직후 처리가 끊겼으면) `409 idempotency_key_in_progress` 가 나고\n**발송하지 않습니다** — 잠시 뒤 같은 키로 다시 보내면 1회차 결과를 받습니다.\n409 가 계속되면 메일이 나갔을 수 있으니 목록 조회로 확인하십시오.\n\n공급자가 발송을 **거절**한 경우에는 키가 풀려 같은 키로 다시 보낼 수 있습니다.\n공급자 응답을 받지 못한 경우(타임아웃 등 `503`)에는 메일이 나갔을 수 있어\n키를 풀지 않으며, 같은 키의 재시도는 `409` 를 받습니다.\n\n⚠️ **본문이 달라도 검사하지 않습니다.** 같은 키로 다른 내용을 보내면 새 메일은\n나가지 않고 1회차 결과가 돌아옵니다. 키는 *메일 한 통* 단위로 만드십시오\n(`order-1024-접수` 처럼). 만료도 없습니다.",
              "example": "order-1024-receipt"
            }
          }
        },
        "example": {
          "from": "no-reply@example.com",
          "to": [
            "customer@gmail.com"
          ],
          "subject": "주문이 접수되었습니다",
          "body": "주문번호 1024 접수되었습니다.",
          "attachmentUrl": [
            "https://files.example.com/receipt-1024.pdf"
          ],
          "idempotencyKey": "order-1024-receipt"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "발송 접수 성공. 공급자가 받았다는 뜻이며 수신함 도착을 보장하지 않습니다.",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "description": "이메일 한 건. **보낸 것과 받은 것이 같은 모양**이며 `direction` 으로 구분합니다\n(통화·문자와 같은 규약입니다).\n\n방향 전용 필드는 반대 방향에서 `null` 입니다 — 받은 메일에는 `failureCode` 가,\n보낸 메일에는 `verdicts`·`recipients` 가 `null` 입니다.\n\n⚠️ **스레드 필드(`replyTo`·`inReplyTo`·`references`)는 방향 전용이 아닙니다.** 답장으로\n보낸 메일도 사슬을 가집니다. 예외는 `messageId` 하나이며, 보낸 메일에서 `null` 인\n이유는 \"해당 없음\" 이 아니라 **공급자가 그 헤더를 덮어써서 우리도 모른다**는 것입니다.",
            "properties": {
              "emailId": {
                "type": "string",
                "description": "한국AI통신 이메일 리소스 ID.",
                "example": "clx9eml00001"
              },
              "direction": {
                "type": "string",
                "enum": [
                  "outbound",
                  "inbound"
                ],
                "description": "`outbound` 는 이 계정이 보낸 메일, `inbound` 는 이 계정의 **수신 도메인으로 들어온**\n메일입니다.",
                "example": "inbound"
              },
              "status": {
                "type": "string",
                "enum": [
                  "sending",
                  "sent",
                  "failed",
                  "received"
                ],
                "description": "보낸 메일은 `sent`(공급자 접수) 또는 `failed` 입니다 — `sent` 는 **접수됐다**는\n뜻이지 수신함 도착이 아닙니다. 받은 메일은 항상 `received` 입니다.\n\n`sending` 은 발송 요청을 처리하는 중이라는 뜻입니다. 조회에서 오래 남아 있으면\n공급자 접수 직후 처리가 끊긴 건이며, 메일은 **나갔을 수 있습니다.**"
              },
              "from": {
                "type": "string",
                "description": "발신자. **보낸 메일은 RFC 5322 mailbox** 문자열입니다 — 요청에 표시명을 넣었으면\n`\"한국AI통신(고객지원)\" <hello@example.com>` 처럼 표시명과 주소를, 없었으면 주소만\n담습니다. 특수문자가 있는 표시명은 따옴표로 싸고 안의 `\"`·`\\` 는 이스케이프합니다.\n\n**받은 메일은 현재 주소만** 담습니다.",
                "example": "\"한국AI통신(고객지원)\" <no-reply@example.com>"
              },
              "to": {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "email"
                },
                "example": [
                  "customer@gmail.com"
                ]
              },
              "cc": {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "email"
                },
                "example": []
              },
              "bcc": {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "email"
                },
                "example": []
              },
              "suppressed": {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "email"
                },
                "description": "수신거부 명단에 있어 이 발송에서 **빠진** 주소들. 요청한 표기 그대로 돌려줍니다.\n\n⚠️ 이메일은 차단된 수신자가 있어도 **나머지에게는 보냅니다**(전화·문자가 발신 전체를\n거절하는 것과 다릅니다). 그래서 `201` 을 받고도 일부가 안 갔을 수 있고, **이 칸이 그걸\n알려주는 유일한 자리**입니다. 비어 있으면 아무도 빠지지 않았다는 뜻입니다.\n\n`recipientCount` 에는 포함되지 않습니다 — 요청한 수신자 수는\n`recipientCount + suppressed.length` 입니다. 받은 메일에서는 항상 빈 배열입니다.",
                "example": []
              },
              "subject": {
                "type": "string",
                "nullable": true,
                "example": "주문이 접수되었습니다"
              },
              "recipientCount": {
                "type": "integer",
                "description": "보낸 메일에서는 **과금 단위**입니다 — 실제로 발송한 To+Cc+Bcc 의 합계이며 한 통을\n3명에게 보내면 3입니다. **수신거부로 빠진 주소는 세지 않습니다**(`suppressed` 참고).\n받은 메일에서는 **이 계정에 실제로 배달된 주소 수**(`recipients` 의 길이)입니다.",
                "example": 1
              },
              "attachmentCount": {
                "type": "integer",
                "example": 1
              },
              "createdAt": {
                "type": "string",
                "format": "date-time",
                "example": "2026-09-03T07:20:00.000Z"
              },
              "failureCode": {
                "type": "string",
                "nullable": true,
                "description": "실패 사유 코드. `status` 가 `sent` 면 `null` 입니다.\n\n`provider_unavailable` 은 **공급자를 부르지 못한** 경우이고, 그 밖의 값은 공급자가\n거절한 경우입니다.",
                "example": null
              },
              "failureMessage": {
                "type": "string",
                "nullable": true,
                "description": "사람이 읽는 실패 설명. `status` 가 `sent` 면 `null` 입니다.",
                "example": null
              },
              "replyTo": {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "email"
                },
                "description": "답장 주소(`Reply-To`). 받은 메일은 발신자가 지정한 주소, 보낸 메일은 발송할 때\n지정한 값입니다.\n\n⭐ **답장은 `from` 이 아니라 이 주소로 보내십시오.** 비어 있을 때만 `from` 이\n답장 주소입니다(RFC 5322 §3.6.2). 뉴스레터·티켓 시스템은 대부분 이 값을 다르게\n둡니다.",
                "example": [
                  "support@example.com"
                ]
              },
              "messageId": {
                "type": "string",
                "nullable": true,
                "description": "이 메일 자신의 `Message-ID`(꺾쇠 `< >` 제외). **답장할 때 `inReplyTo` 에 그대로\n넣는 값입니다.**\n\n⛔ **보낸 메일은 항상 `null`** 입니다. 이 헤더는 공급자가 발급하며 우리가 지정한\n값을 덮어쓰기 때문에 우리도 그 값을 모릅니다.\n⚠️ 받은 메일도 `null` 일 수 있습니다 — 이 헤더는 RFC 상 필수가 아니고, 붙이지 않고\n보내는 발신자가 실제로 있습니다. 그 메일에는 스레드로 답장할 수 없습니다.",
                "example": "CAF7n8xW1p_abc@mail.gmail.com"
              },
              "inReplyTo": {
                "type": "string",
                "nullable": true,
                "description": "이 메일이 답장한 원본의 `Message-ID`(꺾쇠 제외). 답장이 아니면 `null` 입니다.",
                "example": null
              },
              "references": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "대화의 조상 사슬. **오래된 것이 앞**입니다. 다음 답장에 넘길 값은\n`[...references, messageId]` 입니다.\n\n⚠️ 보낸 메일의 값은 요청하신 목록이 아니라 **실제로 헤더에 실어 보낸 목록**입니다.\n긴 대화는 공급자 헤더 길이 상한 때문에 RFC 5537 §3.4.4 에 따라 첫 항목과 최근\n항목만 남기고 줄여 보냅니다.",
                "example": [
                  "CAF7n8xW1p_xyz@mail.gmail.com",
                  "CAF7n8xW1p_abc@mail.gmail.com"
                ]
              },
              "recipients": {
                "type": "array",
                "nullable": true,
                "items": {
                  "type": "string",
                  "format": "email"
                },
                "description": "**실제로 이 계정에 배달된 주소.** 받은 메일에만 있습니다(보낸 메일은 `null`).\n\n⚠️ **`to` 를 보고 라우팅하지 마십시오.** 숨은 참조(BCC)로 온 메일은 `to` 에 그\n주소가 **없습니다** — 이 필드에만 있습니다. 한 도메인에 `support@`·`sales@` 처럼\n여러 주소를 두고 처리를 나눈다면 반드시 이 값을 쓰십시오.",
                "example": [
                  "support@example.com"
                ]
              },
              "receivedAt": {
                "type": "string",
                "format": "date-time",
                "nullable": true,
                "description": "공급자가 메일을 받은 시각. 받은 메일에만 있습니다.",
                "example": "2026-09-04T05:48:00.000Z"
              },
              "sizeBytes": {
                "type": "integer",
                "nullable": true,
                "description": "받은 메일의 원문 크기(바이트). ⚠️ 공급자가 덧붙인 헤더(약 3.6KB)가 포함된 값이라\n메일 클라이언트가 보여 주는 크기와 다를 수 있습니다. **과금은 이 값 기준입니다.**",
                "example": 4030
              },
              "verdicts": {
                "type": "object",
                "nullable": true,
                "description": "공급자의 스팸·바이러스·인증 판정. 받은 메일에만 있습니다.\n\n⚠️ **값은 공급자 원문 그대로**입니다(`PASS`·`FAIL`·`GRAY`·`PROCESSING_FAILED` 등).\n우리가 해석하지 않으므로 목록이 늘어날 수 있습니다 — 모르는 값을 만나면 안전한\n쪽으로 처리하십시오.\n\n⛔ **`from` 만 믿고 자동 처리하지 마십시오.** 발신자는 위조될 수 있고, 그걸\n판별하라고 `spf`·`dkim`·`dmarc` 를 함께 드립니다.",
                "properties": {
                  "spam": {
                    "type": "string",
                    "nullable": true,
                    "example": "PASS"
                  },
                  "virus": {
                    "type": "string",
                    "nullable": true,
                    "example": "PASS"
                  },
                  "spf": {
                    "type": "string",
                    "nullable": true,
                    "example": "PASS"
                  },
                  "dkim": {
                    "type": "string",
                    "nullable": true,
                    "example": "PASS"
                  },
                  "dmarc": {
                    "type": "string",
                    "nullable": true,
                    "example": "GRAY"
                  }
                }
              },
              "parseStatus": {
                "type": "string",
                "nullable": true,
                "enum": [
                  "parsed",
                  "unparsable",
                  null
                ],
                "description": "받은 메일의 본문 해석 결과. `unparsable` 이면 본문을 읽지 못한 것이며, 그때도\n원문은 그대로 보관되어 단건 조회의 `raw` 로 받을 수 있습니다.",
                "example": "parsed"
              }
            },
            "required": [
              "emailId",
              "direction",
              "status",
              "from",
              "to",
              "recipientCount",
              "createdAt"
            ]
          }
        }
      }
    },
    "400": {
      "description": "잘못된 요청. `code` 로 구분합니다.\n\n| code | 뜻 |\n|---|---|\n| `invalid_email_address` | from·to·cc·bcc·replyTo 형식이 이메일이 아님 |\n| `body_required` | `body` 와 `html` 이 둘 다 없음 |\n| `too_many_recipients` | to+cc+bcc 합계가 50명 초과 |\n| `message_too_large` | 본문+첨부가 base64 인코딩 후 5MB 초과(원본 약 3.6MB) |\n| `attachment_url_not_allowed` | 첨부 URL 이 사설 대역·메타데이터·비 https |\n| `attachment_fetch_failed` | 첨부를 내려받지 못함(404·타임아웃 등) |\n| `invalid_input` | `to` 가 비었거나, 첨부가 10개를 넘거나, `idempotencyKey` 가 빈 문자열, 또는 `inReplyTo`·`references` 가 Message-ID 형식이 아님 |",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "error": {
                "type": "string",
                "description": "사람이 읽을 수 있는 에러 메시지"
              },
              "code": {
                "type": "string",
                "description": "기계 판독용 에러 코드. **분기는 이 값으로 하세요** — `error` 문구는 안내를 다듬으면서\n바뀔 수 있지만 코드는 계약입니다.\n\n같은 상태 코드라도 대응이 갈리는 경우가 있습니다. 예를 들어 발신의 `422` 는\n  - `recipient_blocked`: 수신거부 명단에 있는 번호입니다. 재시도하지 말고 명단에서\n    해제해야 발신됩니다.\n  - `quota_exceeded`: 플랜 한도를 넘었습니다. 다음 주기에 다시 발신됩니다.\n\n전화번호 정규화 관련:\n  - `INVALID_PHONE_NUMBER`: 전화번호 포맷 오류 (한국 번호 형식 아님)\n  - `UNSUPPORTED_COUNTRY`: 국제 발신 미지원 (+82 외 국가코드)",
                "example": "recipient_blocked"
              },
              "ip": {
                "type": "string",
                "description": "`overseas_ip_blocked` 일 때만 옵니다. 국외 IP 라고 판정한 요청 IP 입니다.\n해외 리전 클라우드 서버에서 호출한다면 이 값이 그 서버의 공인 IP 이며, 콘솔\n「국외 접속 예외」에서 예외를 신청할 때 이 고정 IP 를 적습니다.",
                "example": "52.79.213.41"
              },
              "processedAt": {
                "type": "string",
                "format": "date-time",
                "description": "문자 발송 요청을 거부한 서버가 오류 응답을 생성한 시각(UTC). 콘솔은 이 값을 한국 시각으로 표시합니다. 인증·요청 형식 검증 등 발송 서비스 진입 전 오류에는 없을 수 있습니다.",
                "example": "2026-10-21T04:10:34.303Z"
              },
              "blockers": {
                "type": "array",
                "description": "`certificate_not_eligible` 일 때만 옵니다. 발급할 수 없는 번호와 그 이유입니다.",
                "items": {
                  "type": "object",
                  "description": "번호 하나가 발급되지 않는(또는 안내가 필요한) 이유.\n\n| code | 뜻 | 발급 |\n|---|---|---|\n| `number_not_owned` | 이 계정이 보유한 번호가 아님(반납·재배정 포함) | 막힘 |\n| `number_not_carrier_issued` | 한국AI통신이 개통한 070·대표번호가 아님(모바일 게이트웨이, 타사 번호) | 막힘 |\n| `business_info_incomplete` | 사업자 계정인데(관리번호 제외) 상호·사업자등록번호·대표자명·사업장 주소 중 빈 칸 | 막힘 |\n| `identity_unverified` | 개인 계정 번호 또는 관리번호인데 그 번호에 본인확인 정보가 없음 | 막힘 |\n| `account_restricted` | 이용 제한 계정 | 막힘 |\n| `business_recheck_pending` | 사업자 계정인데 사업자 정보 재확인이 진행 중(통과 전) — 관리번호를 뺀 계정의 모든 번호 | 막힘 |\n| `holder_is_personal` | 개인 명의로 찍힌다는 안내 | 가능 |",
                  "properties": {
                    "number": {
                      "type": "string",
                      "description": "422 응답의 blockers 에만 있다",
                      "example": "07012340002"
                    },
                    "code": {
                      "type": "string",
                      "enum": [
                        "number_not_owned",
                        "number_not_carrier_issued",
                        "business_info_incomplete",
                        "identity_unverified",
                        "account_restricted",
                        "business_recheck_pending",
                        "holder_is_personal"
                      ],
                      "example": "number_not_carrier_issued"
                    },
                    "message": {
                      "type": "string",
                      "example": "이용증명원은 한국AI통신이 개통한 070·대표번호만 발급됩니다."
                    }
                  },
                  "required": [
                    "code",
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "401": {
      "description": "인증 실패",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "error": {
                "type": "string",
                "description": "사람이 읽을 수 있는 에러 메시지"
              },
              "code": {
                "type": "string",
                "description": "기계 판독용 에러 코드. **분기는 이 값으로 하세요** — `error` 문구는 안내를 다듬으면서\n바뀔 수 있지만 코드는 계약입니다.\n\n같은 상태 코드라도 대응이 갈리는 경우가 있습니다. 예를 들어 발신의 `422` 는\n  - `recipient_blocked`: 수신거부 명단에 있는 번호입니다. 재시도하지 말고 명단에서\n    해제해야 발신됩니다.\n  - `quota_exceeded`: 플랜 한도를 넘었습니다. 다음 주기에 다시 발신됩니다.\n\n전화번호 정규화 관련:\n  - `INVALID_PHONE_NUMBER`: 전화번호 포맷 오류 (한국 번호 형식 아님)\n  - `UNSUPPORTED_COUNTRY`: 국제 발신 미지원 (+82 외 국가코드)",
                "example": "recipient_blocked"
              },
              "ip": {
                "type": "string",
                "description": "`overseas_ip_blocked` 일 때만 옵니다. 국외 IP 라고 판정한 요청 IP 입니다.\n해외 리전 클라우드 서버에서 호출한다면 이 값이 그 서버의 공인 IP 이며, 콘솔\n「국외 접속 예외」에서 예외를 신청할 때 이 고정 IP 를 적습니다.",
                "example": "52.79.213.41"
              },
              "processedAt": {
                "type": "string",
                "format": "date-time",
                "description": "문자 발송 요청을 거부한 서버가 오류 응답을 생성한 시각(UTC). 콘솔은 이 값을 한국 시각으로 표시합니다. 인증·요청 형식 검증 등 발송 서비스 진입 전 오류에는 없을 수 있습니다.",
                "example": "2026-10-21T04:10:34.303Z"
              },
              "blockers": {
                "type": "array",
                "description": "`certificate_not_eligible` 일 때만 옵니다. 발급할 수 없는 번호와 그 이유입니다.",
                "items": {
                  "type": "object",
                  "description": "번호 하나가 발급되지 않는(또는 안내가 필요한) 이유.\n\n| code | 뜻 | 발급 |\n|---|---|---|\n| `number_not_owned` | 이 계정이 보유한 번호가 아님(반납·재배정 포함) | 막힘 |\n| `number_not_carrier_issued` | 한국AI통신이 개통한 070·대표번호가 아님(모바일 게이트웨이, 타사 번호) | 막힘 |\n| `business_info_incomplete` | 사업자 계정인데(관리번호 제외) 상호·사업자등록번호·대표자명·사업장 주소 중 빈 칸 | 막힘 |\n| `identity_unverified` | 개인 계정 번호 또는 관리번호인데 그 번호에 본인확인 정보가 없음 | 막힘 |\n| `account_restricted` | 이용 제한 계정 | 막힘 |\n| `business_recheck_pending` | 사업자 계정인데 사업자 정보 재확인이 진행 중(통과 전) — 관리번호를 뺀 계정의 모든 번호 | 막힘 |\n| `holder_is_personal` | 개인 명의로 찍힌다는 안내 | 가능 |",
                  "properties": {
                    "number": {
                      "type": "string",
                      "description": "422 응답의 blockers 에만 있다",
                      "example": "07012340002"
                    },
                    "code": {
                      "type": "string",
                      "enum": [
                        "number_not_owned",
                        "number_not_carrier_issued",
                        "business_info_incomplete",
                        "identity_unverified",
                        "account_restricted",
                        "business_recheck_pending",
                        "holder_is_personal"
                      ],
                      "example": "number_not_carrier_issued"
                    },
                    "message": {
                      "type": "string",
                      "example": "이용증명원은 한국AI통신이 개통한 070·대표번호만 발급됩니다."
                    }
                  },
                  "required": [
                    "code",
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "403": {
      "description": "| code | 의미 |\n| --- | --- |\n| `email_domain_not_verified` | `from` 도메인이 이 계정에서 검증된 발신 도메인이 아님 |\n| `no_active_subscription` | 활성 구독이 없음 |\n| `email_blocked` | 이메일 발송이 제한된 계정(고객센터 문의) |\n| `email_sending_paused` | 반송·스팸신고 비율이 높아 발송이 정지됨(고객센터 문의) |\n\n접근 권한이 없을 때도 403 입니다.",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "error": {
                "type": "string",
                "description": "사람이 읽을 수 있는 에러 메시지"
              },
              "code": {
                "type": "string",
                "description": "기계 판독용 에러 코드. **분기는 이 값으로 하세요** — `error` 문구는 안내를 다듬으면서\n바뀔 수 있지만 코드는 계약입니다.\n\n같은 상태 코드라도 대응이 갈리는 경우가 있습니다. 예를 들어 발신의 `422` 는\n  - `recipient_blocked`: 수신거부 명단에 있는 번호입니다. 재시도하지 말고 명단에서\n    해제해야 발신됩니다.\n  - `quota_exceeded`: 플랜 한도를 넘었습니다. 다음 주기에 다시 발신됩니다.\n\n전화번호 정규화 관련:\n  - `INVALID_PHONE_NUMBER`: 전화번호 포맷 오류 (한국 번호 형식 아님)\n  - `UNSUPPORTED_COUNTRY`: 국제 발신 미지원 (+82 외 국가코드)",
                "example": "recipient_blocked"
              },
              "ip": {
                "type": "string",
                "description": "`overseas_ip_blocked` 일 때만 옵니다. 국외 IP 라고 판정한 요청 IP 입니다.\n해외 리전 클라우드 서버에서 호출한다면 이 값이 그 서버의 공인 IP 이며, 콘솔\n「국외 접속 예외」에서 예외를 신청할 때 이 고정 IP 를 적습니다.",
                "example": "52.79.213.41"
              },
              "processedAt": {
                "type": "string",
                "format": "date-time",
                "description": "문자 발송 요청을 거부한 서버가 오류 응답을 생성한 시각(UTC). 콘솔은 이 값을 한국 시각으로 표시합니다. 인증·요청 형식 검증 등 발송 서비스 진입 전 오류에는 없을 수 있습니다.",
                "example": "2026-10-21T04:10:34.303Z"
              },
              "blockers": {
                "type": "array",
                "description": "`certificate_not_eligible` 일 때만 옵니다. 발급할 수 없는 번호와 그 이유입니다.",
                "items": {
                  "type": "object",
                  "description": "번호 하나가 발급되지 않는(또는 안내가 필요한) 이유.\n\n| code | 뜻 | 발급 |\n|---|---|---|\n| `number_not_owned` | 이 계정이 보유한 번호가 아님(반납·재배정 포함) | 막힘 |\n| `number_not_carrier_issued` | 한국AI통신이 개통한 070·대표번호가 아님(모바일 게이트웨이, 타사 번호) | 막힘 |\n| `business_info_incomplete` | 사업자 계정인데(관리번호 제외) 상호·사업자등록번호·대표자명·사업장 주소 중 빈 칸 | 막힘 |\n| `identity_unverified` | 개인 계정 번호 또는 관리번호인데 그 번호에 본인확인 정보가 없음 | 막힘 |\n| `account_restricted` | 이용 제한 계정 | 막힘 |\n| `business_recheck_pending` | 사업자 계정인데 사업자 정보 재확인이 진행 중(통과 전) — 관리번호를 뺀 계정의 모든 번호 | 막힘 |\n| `holder_is_personal` | 개인 명의로 찍힌다는 안내 | 가능 |",
                  "properties": {
                    "number": {
                      "type": "string",
                      "description": "422 응답의 blockers 에만 있다",
                      "example": "07012340002"
                    },
                    "code": {
                      "type": "string",
                      "enum": [
                        "number_not_owned",
                        "number_not_carrier_issued",
                        "business_info_incomplete",
                        "identity_unverified",
                        "account_restricted",
                        "business_recheck_pending",
                        "holder_is_personal"
                      ],
                      "example": "number_not_carrier_issued"
                    },
                    "message": {
                      "type": "string",
                      "example": "이용증명원은 한국AI통신이 개통한 070·대표번호만 발급됩니다."
                    }
                  },
                  "required": [
                    "code",
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "409": {
      "description": "| code | 의미 |\n| --- | --- |\n| `idempotency_key_in_progress` | 같은 `idempotencyKey` 의 앞선 요청이 처리 중(발송하지 않음) |",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "error": {
                "type": "string",
                "description": "사람이 읽을 수 있는 에러 메시지"
              },
              "code": {
                "type": "string",
                "description": "기계 판독용 에러 코드. **분기는 이 값으로 하세요** — `error` 문구는 안내를 다듬으면서\n바뀔 수 있지만 코드는 계약입니다.\n\n같은 상태 코드라도 대응이 갈리는 경우가 있습니다. 예를 들어 발신의 `422` 는\n  - `recipient_blocked`: 수신거부 명단에 있는 번호입니다. 재시도하지 말고 명단에서\n    해제해야 발신됩니다.\n  - `quota_exceeded`: 플랜 한도를 넘었습니다. 다음 주기에 다시 발신됩니다.\n\n전화번호 정규화 관련:\n  - `INVALID_PHONE_NUMBER`: 전화번호 포맷 오류 (한국 번호 형식 아님)\n  - `UNSUPPORTED_COUNTRY`: 국제 발신 미지원 (+82 외 국가코드)",
                "example": "recipient_blocked"
              },
              "ip": {
                "type": "string",
                "description": "`overseas_ip_blocked` 일 때만 옵니다. 국외 IP 라고 판정한 요청 IP 입니다.\n해외 리전 클라우드 서버에서 호출한다면 이 값이 그 서버의 공인 IP 이며, 콘솔\n「국외 접속 예외」에서 예외를 신청할 때 이 고정 IP 를 적습니다.",
                "example": "52.79.213.41"
              },
              "processedAt": {
                "type": "string",
                "format": "date-time",
                "description": "문자 발송 요청을 거부한 서버가 오류 응답을 생성한 시각(UTC). 콘솔은 이 값을 한국 시각으로 표시합니다. 인증·요청 형식 검증 등 발송 서비스 진입 전 오류에는 없을 수 있습니다.",
                "example": "2026-10-21T04:10:34.303Z"
              },
              "blockers": {
                "type": "array",
                "description": "`certificate_not_eligible` 일 때만 옵니다. 발급할 수 없는 번호와 그 이유입니다.",
                "items": {
                  "type": "object",
                  "description": "번호 하나가 발급되지 않는(또는 안내가 필요한) 이유.\n\n| code | 뜻 | 발급 |\n|---|---|---|\n| `number_not_owned` | 이 계정이 보유한 번호가 아님(반납·재배정 포함) | 막힘 |\n| `number_not_carrier_issued` | 한국AI통신이 개통한 070·대표번호가 아님(모바일 게이트웨이, 타사 번호) | 막힘 |\n| `business_info_incomplete` | 사업자 계정인데(관리번호 제외) 상호·사업자등록번호·대표자명·사업장 주소 중 빈 칸 | 막힘 |\n| `identity_unverified` | 개인 계정 번호 또는 관리번호인데 그 번호에 본인확인 정보가 없음 | 막힘 |\n| `account_restricted` | 이용 제한 계정 | 막힘 |\n| `business_recheck_pending` | 사업자 계정인데 사업자 정보 재확인이 진행 중(통과 전) — 관리번호를 뺀 계정의 모든 번호 | 막힘 |\n| `holder_is_personal` | 개인 명의로 찍힌다는 안내 | 가능 |",
                  "properties": {
                    "number": {
                      "type": "string",
                      "description": "422 응답의 blockers 에만 있다",
                      "example": "07012340002"
                    },
                    "code": {
                      "type": "string",
                      "enum": [
                        "number_not_owned",
                        "number_not_carrier_issued",
                        "business_info_incomplete",
                        "identity_unverified",
                        "account_restricted",
                        "business_recheck_pending",
                        "holder_is_personal"
                      ],
                      "example": "number_not_carrier_issued"
                    },
                    "message": {
                      "type": "string",
                      "example": "이용증명원은 한국AI통신이 개통한 070·대표번호만 발급됩니다."
                    }
                  },
                  "required": [
                    "code",
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "422": {
      "description": "| code | 의미 |\n| --- | --- |\n| `plan_not_supported` | 이메일을 사용할 수 없는 플랜(유료 플랜으로 변경 필요) |\n| `daily_quota_exceeded` | **오늘**(KST 자정 기준) 발송 한도 초과 |\n| `quota_exceeded` | **이번 청구월** 발송 한도 초과 |\n| `override_quota_exceeded` | 계정에 별도 한도가 걸려 있고 그 한도를 초과 |\n| `recipient_blocked` | 수신자가 **전원** 수신거부 명단에 있어 보낼 대상이 없음 |\n\n한도는 **수신자 수**로 셉니다 — 발송 요청 수가 아닙니다. 한 번의 요청에 수신자를\n50명까지 넣을 수 있어, 요청 수로 세면 한도가 50배로 헐거워지기 때문입니다.\n\n한도는 **월과 일 두 축**이고 플랜마다 다릅니다. 두 축인 이유는 월 한도만으로는 하루에\n몰아 보내는 것을 막을 수 없기 때문입니다 — 메일 서비스의 평판은 총량보다 그 순간의\n발송량에 훨씬 민감합니다. 오류 메시지에 `사용량+이번 요청/한도` 가 함께 담기므로\n어느 축에 얼마나 걸렸는지 바로 알 수 있습니다.\n\n한도를 올려야 하면 고객센터로 문의해 주세요. 계정별로 조정할 수 있고, 조정된 계정은\n플랜 한도 대신 그 값이 적용됩니다(그때는 `override_quota_exceeded` 가 납니다).\n\n⚠️ `recipient_blocked` 는 **전원이 걸렸을 때만** 납니다. 일부만 명단에 있으면 그 사람만\n빼고 나머지에게 발송하며(`201`), 빠진 주소는 응답의 `suppressed` 에 담깁니다 —\n**`2xx` 를 받아도 그 칸을 확인해야 누가 안 갔는지 알 수 있습니다.**",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "error": {
                "type": "string",
                "description": "사람이 읽을 수 있는 에러 메시지"
              },
              "code": {
                "type": "string",
                "description": "기계 판독용 에러 코드. **분기는 이 값으로 하세요** — `error` 문구는 안내를 다듬으면서\n바뀔 수 있지만 코드는 계약입니다.\n\n같은 상태 코드라도 대응이 갈리는 경우가 있습니다. 예를 들어 발신의 `422` 는\n  - `recipient_blocked`: 수신거부 명단에 있는 번호입니다. 재시도하지 말고 명단에서\n    해제해야 발신됩니다.\n  - `quota_exceeded`: 플랜 한도를 넘었습니다. 다음 주기에 다시 발신됩니다.\n\n전화번호 정규화 관련:\n  - `INVALID_PHONE_NUMBER`: 전화번호 포맷 오류 (한국 번호 형식 아님)\n  - `UNSUPPORTED_COUNTRY`: 국제 발신 미지원 (+82 외 국가코드)",
                "example": "recipient_blocked"
              },
              "ip": {
                "type": "string",
                "description": "`overseas_ip_blocked` 일 때만 옵니다. 국외 IP 라고 판정한 요청 IP 입니다.\n해외 리전 클라우드 서버에서 호출한다면 이 값이 그 서버의 공인 IP 이며, 콘솔\n「국외 접속 예외」에서 예외를 신청할 때 이 고정 IP 를 적습니다.",
                "example": "52.79.213.41"
              },
              "processedAt": {
                "type": "string",
                "format": "date-time",
                "description": "문자 발송 요청을 거부한 서버가 오류 응답을 생성한 시각(UTC). 콘솔은 이 값을 한국 시각으로 표시합니다. 인증·요청 형식 검증 등 발송 서비스 진입 전 오류에는 없을 수 있습니다.",
                "example": "2026-10-21T04:10:34.303Z"
              },
              "blockers": {
                "type": "array",
                "description": "`certificate_not_eligible` 일 때만 옵니다. 발급할 수 없는 번호와 그 이유입니다.",
                "items": {
                  "type": "object",
                  "description": "번호 하나가 발급되지 않는(또는 안내가 필요한) 이유.\n\n| code | 뜻 | 발급 |\n|---|---|---|\n| `number_not_owned` | 이 계정이 보유한 번호가 아님(반납·재배정 포함) | 막힘 |\n| `number_not_carrier_issued` | 한국AI통신이 개통한 070·대표번호가 아님(모바일 게이트웨이, 타사 번호) | 막힘 |\n| `business_info_incomplete` | 사업자 계정인데(관리번호 제외) 상호·사업자등록번호·대표자명·사업장 주소 중 빈 칸 | 막힘 |\n| `identity_unverified` | 개인 계정 번호 또는 관리번호인데 그 번호에 본인확인 정보가 없음 | 막힘 |\n| `account_restricted` | 이용 제한 계정 | 막힘 |\n| `business_recheck_pending` | 사업자 계정인데 사업자 정보 재확인이 진행 중(통과 전) — 관리번호를 뺀 계정의 모든 번호 | 막힘 |\n| `holder_is_personal` | 개인 명의로 찍힌다는 안내 | 가능 |",
                  "properties": {
                    "number": {
                      "type": "string",
                      "description": "422 응답의 blockers 에만 있다",
                      "example": "07012340002"
                    },
                    "code": {
                      "type": "string",
                      "enum": [
                        "number_not_owned",
                        "number_not_carrier_issued",
                        "business_info_incomplete",
                        "identity_unverified",
                        "account_restricted",
                        "business_recheck_pending",
                        "holder_is_personal"
                      ],
                      "example": "number_not_carrier_issued"
                    },
                    "message": {
                      "type": "string",
                      "example": "이용증명원은 한국AI통신이 개통한 070·대표번호만 발급됩니다."
                    }
                  },
                  "required": [
                    "code",
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "502": {
      "description": "공급자 요청 실패(영구). 같은 요청을 다시 보내도 같은 결과입니다.",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "error": {
                "type": "string",
                "description": "사람이 읽을 수 있는 에러 메시지"
              },
              "code": {
                "type": "string",
                "description": "기계 판독용 에러 코드. **분기는 이 값으로 하세요** — `error` 문구는 안내를 다듬으면서\n바뀔 수 있지만 코드는 계약입니다.\n\n같은 상태 코드라도 대응이 갈리는 경우가 있습니다. 예를 들어 발신의 `422` 는\n  - `recipient_blocked`: 수신거부 명단에 있는 번호입니다. 재시도하지 말고 명단에서\n    해제해야 발신됩니다.\n  - `quota_exceeded`: 플랜 한도를 넘었습니다. 다음 주기에 다시 발신됩니다.\n\n전화번호 정규화 관련:\n  - `INVALID_PHONE_NUMBER`: 전화번호 포맷 오류 (한국 번호 형식 아님)\n  - `UNSUPPORTED_COUNTRY`: 국제 발신 미지원 (+82 외 국가코드)",
                "example": "recipient_blocked"
              },
              "ip": {
                "type": "string",
                "description": "`overseas_ip_blocked` 일 때만 옵니다. 국외 IP 라고 판정한 요청 IP 입니다.\n해외 리전 클라우드 서버에서 호출한다면 이 값이 그 서버의 공인 IP 이며, 콘솔\n「국외 접속 예외」에서 예외를 신청할 때 이 고정 IP 를 적습니다.",
                "example": "52.79.213.41"
              },
              "processedAt": {
                "type": "string",
                "format": "date-time",
                "description": "문자 발송 요청을 거부한 서버가 오류 응답을 생성한 시각(UTC). 콘솔은 이 값을 한국 시각으로 표시합니다. 인증·요청 형식 검증 등 발송 서비스 진입 전 오류에는 없을 수 있습니다.",
                "example": "2026-10-21T04:10:34.303Z"
              },
              "blockers": {
                "type": "array",
                "description": "`certificate_not_eligible` 일 때만 옵니다. 발급할 수 없는 번호와 그 이유입니다.",
                "items": {
                  "type": "object",
                  "description": "번호 하나가 발급되지 않는(또는 안내가 필요한) 이유.\n\n| code | 뜻 | 발급 |\n|---|---|---|\n| `number_not_owned` | 이 계정이 보유한 번호가 아님(반납·재배정 포함) | 막힘 |\n| `number_not_carrier_issued` | 한국AI통신이 개통한 070·대표번호가 아님(모바일 게이트웨이, 타사 번호) | 막힘 |\n| `business_info_incomplete` | 사업자 계정인데(관리번호 제외) 상호·사업자등록번호·대표자명·사업장 주소 중 빈 칸 | 막힘 |\n| `identity_unverified` | 개인 계정 번호 또는 관리번호인데 그 번호에 본인확인 정보가 없음 | 막힘 |\n| `account_restricted` | 이용 제한 계정 | 막힘 |\n| `business_recheck_pending` | 사업자 계정인데 사업자 정보 재확인이 진행 중(통과 전) — 관리번호를 뺀 계정의 모든 번호 | 막힘 |\n| `holder_is_personal` | 개인 명의로 찍힌다는 안내 | 가능 |",
                  "properties": {
                    "number": {
                      "type": "string",
                      "description": "422 응답의 blockers 에만 있다",
                      "example": "07012340002"
                    },
                    "code": {
                      "type": "string",
                      "enum": [
                        "number_not_owned",
                        "number_not_carrier_issued",
                        "business_info_incomplete",
                        "identity_unverified",
                        "account_restricted",
                        "business_recheck_pending",
                        "holder_is_personal"
                      ],
                      "example": "number_not_carrier_issued"
                    },
                    "message": {
                      "type": "string",
                      "example": "이용증명원은 한국AI통신이 개통한 070·대표번호만 발급됩니다."
                    }
                  },
                  "required": [
                    "code",
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "503": {
      "description": "공급자에 일시적으로 연결할 수 없음, 또는 이메일 발송이 아직 설정되지 않음.\n잠시 후 다시 시도하십시오.",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "error": {
                "type": "string",
                "description": "사람이 읽을 수 있는 에러 메시지"
              },
              "code": {
                "type": "string",
                "description": "기계 판독용 에러 코드. **분기는 이 값으로 하세요** — `error` 문구는 안내를 다듬으면서\n바뀔 수 있지만 코드는 계약입니다.\n\n같은 상태 코드라도 대응이 갈리는 경우가 있습니다. 예를 들어 발신의 `422` 는\n  - `recipient_blocked`: 수신거부 명단에 있는 번호입니다. 재시도하지 말고 명단에서\n    해제해야 발신됩니다.\n  - `quota_exceeded`: 플랜 한도를 넘었습니다. 다음 주기에 다시 발신됩니다.\n\n전화번호 정규화 관련:\n  - `INVALID_PHONE_NUMBER`: 전화번호 포맷 오류 (한국 번호 형식 아님)\n  - `UNSUPPORTED_COUNTRY`: 국제 발신 미지원 (+82 외 국가코드)",
                "example": "recipient_blocked"
              },
              "ip": {
                "type": "string",
                "description": "`overseas_ip_blocked` 일 때만 옵니다. 국외 IP 라고 판정한 요청 IP 입니다.\n해외 리전 클라우드 서버에서 호출한다면 이 값이 그 서버의 공인 IP 이며, 콘솔\n「국외 접속 예외」에서 예외를 신청할 때 이 고정 IP 를 적습니다.",
                "example": "52.79.213.41"
              },
              "processedAt": {
                "type": "string",
                "format": "date-time",
                "description": "문자 발송 요청을 거부한 서버가 오류 응답을 생성한 시각(UTC). 콘솔은 이 값을 한국 시각으로 표시합니다. 인증·요청 형식 검증 등 발송 서비스 진입 전 오류에는 없을 수 있습니다.",
                "example": "2026-10-21T04:10:34.303Z"
              },
              "blockers": {
                "type": "array",
                "description": "`certificate_not_eligible` 일 때만 옵니다. 발급할 수 없는 번호와 그 이유입니다.",
                "items": {
                  "type": "object",
                  "description": "번호 하나가 발급되지 않는(또는 안내가 필요한) 이유.\n\n| code | 뜻 | 발급 |\n|---|---|---|\n| `number_not_owned` | 이 계정이 보유한 번호가 아님(반납·재배정 포함) | 막힘 |\n| `number_not_carrier_issued` | 한국AI통신이 개통한 070·대표번호가 아님(모바일 게이트웨이, 타사 번호) | 막힘 |\n| `business_info_incomplete` | 사업자 계정인데(관리번호 제외) 상호·사업자등록번호·대표자명·사업장 주소 중 빈 칸 | 막힘 |\n| `identity_unverified` | 개인 계정 번호 또는 관리번호인데 그 번호에 본인확인 정보가 없음 | 막힘 |\n| `account_restricted` | 이용 제한 계정 | 막힘 |\n| `business_recheck_pending` | 사업자 계정인데 사업자 정보 재확인이 진행 중(통과 전) — 관리번호를 뺀 계정의 모든 번호 | 막힘 |\n| `holder_is_personal` | 개인 명의로 찍힌다는 안내 | 가능 |",
                  "properties": {
                    "number": {
                      "type": "string",
                      "description": "422 응답의 blockers 에만 있다",
                      "example": "07012340002"
                    },
                    "code": {
                      "type": "string",
                      "enum": [
                        "number_not_owned",
                        "number_not_carrier_issued",
                        "business_info_incomplete",
                        "identity_unverified",
                        "account_restricted",
                        "business_recheck_pending",
                        "holder_is_personal"
                      ],
                      "example": "number_not_carrier_issued"
                    },
                    "message": {
                      "type": "string",
                      "example": "이용증명원은 한국AI통신이 개통한 070·대표번호만 발급됩니다."
                    }
                  },
                  "required": [
                    "code",
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    }
  }
}
```