# 이메일 단건 조회 (본문 포함) (/docs/api/emails/getEmail)
**GET /v1/accounts/{accountId}/emails/{emailId}**
```json
{
  "operationId": "getEmail",
  "summary": "이메일 단건 조회 (본문 포함)",
  "description": "이메일 한 건을 조회합니다. 목록 항목의 모든 필드에 **본문과 첨부 목록**이 더해집니다.\n\n받은 메일이면 `text`·`html` 에 본문이, `attachments` 에 첨부(각각 단기 내려받기 링크\n포함)가, `raw` 에 원문 전체를 받는 단기 링크가 담깁니다. 보낸 메일은 이 필드들이 모두\n`null` 입니다 — 보낸 본문은 여러분이 만든 것이라 우리가 따로 보관하지 않습니다.\n\n⚠️ 응답에 담긴 링크들은 **잠시 뒤 만료됩니다**(`expiresAt`). 저장해 두지 말고 필요할 때\n다시 호출하십시오.\n\n⚠️ 보관기간이 지나면 본문과 `raw` 가 `null` 이 됩니다. 그때도 **발신자·제목·시각·판정\n같은 메타데이터는 그대로 조회됩니다** — 메일이 왔다는 사실은 사라지지 않습니다.\n\n다른 계정의 메일은 조회할 수 없습니다. 남의 것을 요청하면 **없는 것과 같은 `404`** 가\n돌아옵니다 — 구분해서 알리면 그 ID 가 실재하는지 알아낼 수 있기 때문입니다.",
  "tags": [
    "Emails"
  ],
  "parameters": [
    {
      "name": "accountId",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string"
      },
      "description": "계정 ID",
      "example": "AC1a2b3c4d"
    },
    {
      "name": "emailId",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string"
      },
      "description": "발송 응답의 `emailId`, 목록의 `emailId`, 또는 `email.received` 웹훅의 `EmailId`.",
      "example": "clx9eml00001"
    }
  ],
  "responses": {
    "200": {
      "description": "이메일 한 건",
      "content": {
        "application/json": {
          "schema": {
            "allOf": [
              {
                "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"
                ]
              },
              {
                "type": "object",
                "description": "단건 조회 응답. 목록 항목의 모든 필드에 **본문과 첨부**가 더해집니다.\n\n본문은 목록에 실리지 않습니다 — 받은 메일은 한 통이 40MB까지 가능해서(수신 상한은 발송과 별개입니다), 목록에 넣으면\n한 페이지가 수백 MB가 됩니다.",
                "properties": {
                  "text": {
                    "type": "string",
                    "nullable": true,
                    "description": "평문 본문. 받은 메일에만 있습니다.\n\n보관기간이 지났거나 본문을 해석하지 못한 경우 `null` 입니다 — 그때도 발신자·제목·\n시각 같은 메타데이터는 그대로 조회됩니다.",
                    "example": "재고 문의드립니다. 언제쯤 입고될까요?"
                  },
                  "html": {
                    "type": "string",
                    "nullable": true,
                    "description": "HTML 본문. 받은 메일에만 있습니다.\n\n⛔ **이 HTML 은 외부인이 보낸 것이며 우리가 소독(sanitize)하지 않습니다.**\n원문을 손실 없이 전달하는 것이 이 API 의 계약이므로, 그대로 화면에 렌더하면\n스크립트 삽입(XSS)에 노출됩니다. 표시하려면 여러분 쪽에서 정제하십시오.\n\n### 본문 안의 이미지\n\nHTML 메일의 이미지는 첨부로 실려 오고 본문은 `<img src=\"cid:로고\">` 처럼 그것을\n가리킵니다. 그대로 렌더하면 이미지가 깨지므로, `cid:` 뒤의 값과 같은 `contentId`\n를 가진 첨부를 찾아 그 `downloadUrl` 로 바꿔 넣으십시오. 그 URL 은 인증이 필요\n없어 브라우저에서 바로 표시됩니다.",
                    "example": "<p>재고 문의드립니다…</p>"
                  },
                  "bodyTruncated": {
                    "type": "boolean",
                    "description": "본문이 상한(각 1MiB)에 걸려 잘렸는지. 잘린 경우에도 **원문에는 전부 있으므로**\n`raw.downloadUrl` 로 받아 직접 해석할 수 있습니다.",
                    "example": false
                  },
                  "attachments": {
                    "type": "array",
                    "nullable": true,
                    "description": "첨부 목록. 받은 메일에만 있습니다.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "attachmentId": {
                          "type": "string",
                          "example": "clx9att00001"
                        },
                        "filename": {
                          "type": "string",
                          "nullable": true,
                          "description": "⚠️ **보낸 사람이 정한 값**입니다. 파일 시스템 경로로 그대로 쓰지 마십시오.",
                          "example": "주문서.pdf"
                        },
                        "contentType": {
                          "type": "string",
                          "nullable": true,
                          "example": "application/pdf"
                        },
                        "sizeBytes": {
                          "type": "integer",
                          "example": 182034
                        },
                        "contentId": {
                          "type": "string",
                          "nullable": true,
                          "description": "본문의 `<img src=\"cid:...\">` 가 가리키는 값입니다. 인라인 이미지를 이 첨부와\n잇는 유일한 키이며, 일반 첨부는 `null` 입니다.",
                          "example": "logo@example.com"
                        },
                        "inline": {
                          "type": "boolean",
                          "description": "본문에 삽입된 이미지인지(`true`), 별도 첨부인지(`false`).",
                          "example": false
                        },
                        "downloadUrl": {
                          "type": "string",
                          "format": "uri",
                          "nullable": true,
                          "description": "이 첨부를 받는 **단기 링크**입니다. 인증이 필요 없어 `<img src>` 에 그대로\n넣어도 표시됩니다.\n\n⚠️ **저장해 두고 나중에 쓰지 마십시오** — `expiresAt` 이후에는 동작하지\n않습니다. 필요할 때 이 API 를 다시 호출하거나 첨부 내려받기 API 를 쓰십시오.\n\n보관기간이 지난 첨부는 `null` 입니다."
                        },
                        "expiresAt": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true,
                          "description": "`downloadUrl` 이 만료되는 시각.",
                          "example": "2026-09-04T07:15:00.000Z"
                        }
                      },
                      "required": [
                        "attachmentId",
                        "sizeBytes"
                      ]
                    }
                  },
                  "raw": {
                    "type": "object",
                    "nullable": true,
                    "description": "원문(MIME) 전체를 내려받는 **단기 링크**입니다. 받은 메일에만 있고, 보관기간이\n지나면 `null` 입니다.\n\n본문이 잘렸거나(`bodyTruncated`) 우리가 해석하지 못한 메일도 원문에는 전부 있습니다.\n\n⚠️ 이 URL 은 **인증을 거치지 않습니다** — 가진 사람은 누구나 받을 수 있으니 로그나\n외부에 남기지 마십시오. 그리고 **저장해 두고 나중에 쓰지 마십시오**: `expiresAt`\n이후에는 동작하지 않습니다.",
                    "properties": {
                      "downloadUrl": {
                        "type": "string",
                        "format": "uri"
                      },
                      "expiresAt": {
                        "type": "string",
                        "format": "date-time",
                        "description": "이 링크가 만료되는 시각.",
                        "example": "2026-09-04T07:15:00.000Z"
                      }
                    },
                    "required": [
                      "downloadUrl",
                      "expiresAt"
                    ]
                  }
                },
                "required": [
                  "bodyTruncated"
                ]
              }
            ]
          }
        }
      }
    },
    "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": "접근 권한 없음",
      "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"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "`email_not_found` — 없거나 이 계정의 메일이 아님.",
      "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"
                  ]
                }
              }
            }
          }
        }
      }
    }
  }
}
```