# 배치 발신(캠페인) 생성 (/docs/api/callbatches/createCallBatch)
**POST /v1/accounts/{accountId}/call-batches**
```json
{
  "operationId": "createCallBatch",
  "summary": "배치 발신(캠페인) 생성",
  "description": "명단에 자동으로 전화를 거는 배치를 만듭니다. 생성 즉시 반환되며, 실제 발신은\n동시 통화 한도·분당 발신 속도·발신 가능 시간대를 지켜가며 순차적으로 진행됩니다.\n\n**대상은 `CallFlowId` · `AgentId` · `Url` 중 정확히 하나**를 지정합니다 (발신 API와 동일).\n\n수신자별로 다른 값을 쓰려면 `Tasks[].Variables`에 넣습니다. 변수 **이름**은\n영문/숫자/밑줄만 가능합니다(값은 한글 가능). 대상에 따라 쓰이는 방식이 다릅니다.\n- **콜 플로우**: 멘트에서 `{{변수명}}`으로 참조합니다.\n- **매니지드 에이전트**: 그 통화의 `CallContext.Variables`로 전달되어 에이전트 지시문 뒤에\n  이번 통화의 데이터로 붙습니다. 에이전트 지시문에는 `{{변수명}}` 치환이 없으므로\n  「데이터의 `customer_name`으로 부르세요」처럼 변수 이름으로 가리킵니다.\n\n**발신 차수(`Rounds`)**: 몇 번 걸지, 얼마 간격으로 걸지, **각 차수를 언제 걸지**를\n한 배열로 정합니다. 배열 인덱스가 곧 차수라 `Rounds[0]`이 1차 발신이고 그 뒤가 재시도입니다.\n차수마다 시간대를 따로 줄 수 있어 \"1차는 낮에, 안 받으면 2·3차는 저녁에\" 같은 진행이 됩니다.\n\n**발신 가능 시간대**: 광고성 전화는 21시~익일 8시 발신이 법으로 금지되어 있어\n이 시간에는 `Rounds[].Windows` 설정과 무관하게 발신되지 않습니다. `Windows`는 그보다\n**더 좁게** 제한할 때 사용합니다.\n\n배치 발신은 계정별로 활성화가 필요합니다.",
  "tags": [
    "CallBatches"
  ],
  "parameters": [
    {
      "name": "accountId",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string"
      },
      "example": "AC1a2b3c4d"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "example": {
          "Name": "7월 예약 확인",
          "From": "07052358010",
          "CallFlowId": "cf_9a8b7c6d",
          "MaxConcurrency": 3,
          "PacingPerMinute": 20,
          "MachineDetection": "Enable",
          "Rounds": [
            {
              "Windows": [
                {
                  "Days": [
                    1,
                    2,
                    3,
                    4,
                    5
                  ],
                  "Start": "10:00",
                  "End": "18:00"
                }
              ]
            },
            {
              "After": 30,
              "On": [
                "no-answer",
                "busy"
              ],
              "Windows": [
                {
                  "Days": [
                    1,
                    2,
                    3,
                    4,
                    5
                  ],
                  "Start": "18:00",
                  "End": "21:00"
                }
              ]
            },
            {
              "After": 45,
              "On": [
                "no-answer",
                "busy"
              ],
              "Windows": [
                {
                  "Days": [
                    1,
                    2,
                    3,
                    4,
                    5
                  ],
                  "Start": "18:00",
                  "End": "21:00"
                }
              ]
            }
          ],
          "MessagePolicy": {
            "OnFinalFail": {
              "Body": "{{customer_name}}님, {{visit_date}} 예약 확인차 전화드렸는데 연결이 어려워 문자 남깁니다."
            }
          },
          "Tasks": [
            {
              "To": "01012345678",
              "Variables": {
                "customer_name": "홍길동",
                "visit_date": "7월 30일"
              }
            },
            {
              "To": "01087654321",
              "Variables": {
                "customer_name": "김영희",
                "visit_date": "7월 31일"
              }
            }
          ]
        },
        "schema": {
          "type": "object",
          "required": [
            "Name",
            "From",
            "Tasks"
          ],
          "properties": {
            "Name": {
              "type": "string",
              "example": "7월 예약 확인"
            },
            "From": {
              "type": "string",
              "description": "발신 번호 (계정에 등록된 번호)",
              "example": "07052358010"
            },
            "CallFlowId": {
              "type": "string",
              "description": "콜 플로우로 발신. AgentId·Url과 배타."
            },
            "AgentId": {
              "type": "string",
              "description": "매니지드 에이전트로 발신. CallFlowId·Url과 배타."
            },
            "Url": {
              "type": "string",
              "description": "VoiceML을 반환할 URL. CallFlowId·AgentId와 배타."
            },
            "Tasks": {
              "type": "array",
              "description": "수신자 목록. 건수 제한은 없고 요청 본문 크기(10MB)가 상한이다 — 초과하면 413. 3만건 규모까지 한 번에 넣을 수 있다.",
              "items": {
                "type": "object",
                "required": [
                  "To"
                ],
                "properties": {
                  "To": {
                    "type": "string",
                    "example": "01012345678"
                  },
                  "Variables": {
                    "type": "object",
                    "description": "이 수신자에게만 적용할 변수. 콜 플로우는 `{{변수명}}` 치환, 매니지드 에이전트는 통화 데이터(`CallContext.Variables`)로 전달. 이름은 영문/숫자/밑줄.",
                    "additionalProperties": true,
                    "example": {
                      "customer_name": "홍길동",
                      "visit_date": "7월 30일"
                    }
                  }
                }
              }
            },
            "Status": {
              "type": "string",
              "enum": [
                "running",
                "paused"
              ],
              "description": "생성 직후 상태. 기본값 running(만들면 바로 발신 대기). paused 로 만들면 명단을 확인한 뒤 actions 의 resume 으로 시작한다.",
              "example": "running"
            },
            "MachineDetection": {
              "type": "string",
              "enum": [
                "None",
                "Enable",
                "Hangup"
              ],
              "description": "자동응답기(음성사서함) 감지. 기본값 None(사용 안 함). `Enable` 은 감지만 해서 결과의 `answeredBy` 에 human·machine·unknown 을 남기고 통화는 그대로 진행합니다. `Hangup` 은 자동응답기로 판정되면 통화를 끊습니다. **AMD 애드온이 활성화된 계정만** 쓸 수 있고(없으면 422), 감지한 통화마다 요금이 붙습니다.\n애드온 활성 여부는 **발신할 때마다** 다시 확인합니다 — 배치를 만든 뒤 애드온을 해지하면 남은 통화는 감지 없이 걸립니다(배치가 실패하지는 않습니다).",
              "example": "Enable"
            },
            "Rounds": {
              "type": "array",
              "description": "발신 차수. **배열 인덱스가 곧 차수**이고 `Rounds[0]` 이 1차 발신, 그 뒤가 재시도입니다. 생략하면 **한 번 걸고 끝**(발신 가능 시간대 전체)입니다. 최대 5개.\n차수마다 시간대를 따로 줄 수 있는 것이 핵심입니다 — \"1차는 낮(10~18시)에 걸고, 안 받으면 2·3차는 받을 확률이 높은 저녁(18~21시)에\" 같은 진행을 한 배치로 표현합니다.\n재시도도 최초 발신과 똑같이 동시통화 한도·분당 상한·발신 가능 시간대의 적용을 받습니다. 정책상의 시각이 그 차수의 시간대 밖이면 **시간대가 열릴 때까지 기다렸다가** 걸립니다 — 20시 50분에 실패한 통화의 \"30분 뒤\"는 21시 20분이지만 그 시각은 발신 금지라 실제로는 다음 열리는 시각에 걸립니다.",
              "maxItems": 5,
              "example": [
                {
                  "Windows": [
                    {
                      "Days": [
                        1,
                        2,
                        3,
                        4,
                        5
                      ],
                      "Start": "10:00",
                      "End": "18:00"
                    }
                  ]
                },
                {
                  "After": 30,
                  "On": [
                    "no-answer",
                    "busy"
                  ],
                  "Windows": [
                    {
                      "Days": [
                        1,
                        2,
                        3,
                        4,
                        5
                      ],
                      "Start": "18:00",
                      "End": "21:00"
                    }
                  ]
                }
              ],
              "items": {
                "type": "object",
                "properties": {
                  "After": {
                    "type": "integer",
                    "description": "직전 차수 통화를 마무리한 뒤 이 차수까지 기다릴 시간(분). 1~1440(하루).\n**1차(`Rounds[0]`)에는 쓸 수 없습니다** — 기준이 될 직전 통화가 없기 때문입니다. 발신 시작 시각은 `StartAt` 으로 지정하세요. 2차부터는 필수입니다.",
                    "example": 30
                  },
                  "On": {
                    "type": "array",
                    "description": "직전 통화가 이 결과일 때만 이 차수를 진행합니다. `no-answer`(안 받음) · `busy`(통화 중) · `rejected`(거절/차단) · `failed`(발신 실패) · `machine`(자동응답기 판정).\n**1차에는 쓸 수 없고**(직전 결과가 없습니다) 2차부터는 필수입니다. 차수마다 다르게 줄 수 있습니다 — 2차는 안 받은 경우만, 3차는 통화 중도 포함하는 식입니다.\n`machine` 은 `MachineDetection` 을 함께 켠 배치에서만 동작합니다. 감지를 끈 채로 넣으면 거절되지는 않지만 **아무 일도 일어나지 않습니다** — 판정값(`answeredBy`)이 아예 없어 맞출 대상이 없기 때문입니다.\n켜더라도 신중히 고르세요 — 한국어 자동응답기 감지는 오탐이 잦아 **사람이 받은 통화를 기계로 잘못 본** 경우가 많고, 그러면 이미 통화한 분께 다시 걸게 됩니다.",
                    "items": {
                      "type": "string",
                      "enum": [
                        "no-answer",
                        "busy",
                        "rejected",
                        "failed",
                        "machine"
                      ]
                    },
                    "example": [
                      "no-answer",
                      "busy"
                    ]
                  },
                  "Windows": {
                    "type": "array",
                    "description": "이 차수의 발신 가능 시간대. 생략하면 법정 허용 시간(08:00~21:00) 전체입니다. 법정 허용 시간과 겹치는 구간이 전혀 없으면(예: 22:00~23:00) 400 으로 거절합니다 — 통과시키면 그 차수가 영원히 걸리지 않습니다.",
                    "example": [
                      {
                        "Days": [
                          1,
                          2,
                          3,
                          4,
                          5
                        ],
                        "Start": "18:00",
                        "End": "21:00"
                      }
                    ],
                    "items": {
                      "type": "object",
                      "required": [
                        "Days",
                        "Start",
                        "End"
                      ],
                      "properties": {
                        "Days": {
                          "type": "array",
                          "description": "1(월)~7(일)",
                          "items": {
                            "type": "integer"
                          },
                          "example": [
                            1,
                            2,
                            3,
                            4,
                            5
                          ]
                        },
                        "Start": {
                          "type": "string",
                          "example": "18:00"
                        },
                        "End": {
                          "type": "string",
                          "example": "21:00"
                        }
                      }
                    }
                  }
                }
              }
            },
            "MessagePolicy": {
              "type": "object",
              "description": "끝내 통화가 안 된 분께 보낼 문자. 생략하면 보내지 않습니다. 본문의 `{{변수}}` 는 그 수신자의 `Variables` 값으로 치환됩니다(콜 플로우 멘트와 같은 문법). 참조한 변수가 없는 수신자가 한 명이라도 있으면 400 으로 거절합니다 — 빈칸으로 나가는 문자는 되돌릴 수 없기 때문입니다.\n문자는 통화가 실패한 **직후** 나갑니다(차수 시간대를 따로 기다리지 않습니다). 다만 법정 금지 시간(21~08시)에 걸리면 다음 날 아침으로 밀리고, 보낼 시점이 24시간 이상 지나면 보내지 않습니다(일시정지해 둔 배치를 며칠 뒤 재개했을 때 뒤늦은 문자가 나가는 것을 막습니다).\n⚠️ 문자 발신번호 등록은 음성 발신 등록과 **별개 절차**입니다. 등록되지 않은 번호는 발송 요청이 성공해도 통신사에서 거절될 수 있어, 생성 응답의 `warnings` 로 알려 드립니다.",
              "properties": {
                "OnFirstFail": {
                  "type": "object",
                  "description": "**첫 통화**가 안 됐을 때 바로 보낼 문자. 재시도 전화가 그 뒤에 이어집니다. 재시도 차수 없이는(`Rounds` 가 1개) 쓸 수 없습니다 — 다시 걸지 않으면 첫 실패가 곧 최종 실패라 OnFinalFail 과 같은 뜻이 됩니다.",
                  "required": [
                    "Body"
                  ],
                  "properties": {
                    "Body": {
                      "type": "string",
                      "example": "{{customer_name}}님, [상호명]입니다. 전화드렸는데 연결이 어려워 문자 남깁니다."
                    }
                  }
                },
                "OnFinalFail": {
                  "type": "object",
                  "description": "재시도를 모두 소진하고 **끝내** 통화가 안 됐을 때 보낼 문자.",
                  "required": [
                    "Body"
                  ],
                  "properties": {
                    "Body": {
                      "type": "string",
                      "example": "{{customer_name}}님, 연락이 닿지 않아 문자로 안내드립니다. 편하실 때 회신 부탁드립니다."
                    }
                  }
                }
              }
            },
            "MaxConcurrency": {
              "type": "integer",
              "description": "이 배치가 동시에 유지할 통화 수. 기본값: 1",
              "example": 3
            },
            "PacingPerMinute": {
              "type": "integer",
              "description": "분당 최대 발신 수. 기본값: 10",
              "example": 20
            },
            "Timezone": {
              "type": "string",
              "description": "발신 시간대 판정 기준. 기본값: Asia/Seoul"
            },
            "StartAt": {
              "type": "string",
              "format": "date-time",
              "description": "이 시각 이후부터 발신 시작"
            },
            "EndAt": {
              "type": "string",
              "format": "date-time",
              "description": "이 시각이 지나면 남은 대상은 발신하지 않고 종료"
            },
            "Priority": {
              "type": "integer",
              "description": "같은 계정에 배치가 여럿일 때 우선순위(높을수록 먼저). 기본값: 0"
            }
          }
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "생성 성공",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "batchId": {
                "type": "string",
                "example": "clx1a2b3c4d5e"
              },
              "name": {
                "type": "string",
                "example": "7월 예약 확인"
              },
              "status": {
                "type": "string",
                "description": "running=발신 중 · paused=일시정지(진행 중 통화는 유지) · canceled=취소 ·\ncompleted=완료 · expired=EndAt 경과로 종료",
                "enum": [
                  "draft",
                  "scheduled",
                  "running",
                  "paused",
                  "completed",
                  "canceled",
                  "expired"
                ]
              },
              "from": {
                "type": "string",
                "example": "07052358010"
              },
              "callFlowId": {
                "type": "string"
              },
              "agentId": {
                "type": "string"
              },
              "url": {
                "type": "string"
              },
              "maxConcurrency": {
                "type": "integer"
              },
              "pacingPerMinute": {
                "type": "integer"
              },
              "timezone": {
                "type": "string"
              },
              "startAt": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "endAt": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "machineDetection": {
                "type": "string",
                "nullable": true,
                "enum": [
                  "Enable",
                  "Hangup",
                  null
                ],
                "description": "자동응답기 감지 모드. 사용하지 않는 배치는 null 입니다."
              },
              "rounds": {
                "type": "array",
                "description": "발신 차수. 배열 인덱스가 곧 차수이고 rounds[0] 이 1차 발신입니다. 길이 1 = 한 번 걸고 끝. 각 차수가 자기 시간창(windows)을 가집니다.",
                "items": {
                  "type": "object",
                  "properties": {
                    "after": {
                      "type": "integer",
                      "description": "직전 차수를 마무리한 뒤 기다릴 시간(분). 1차에는 없습니다."
                    },
                    "on": {
                      "type": "array",
                      "description": "직전 통화가 이 결과일 때만 진행. 1차에는 없습니다.",
                      "items": {
                        "type": "string"
                      }
                    },
                    "windows": {
                      "type": "array",
                      "description": "이 차수의 발신 가능 시간대. 없으면 법정 허용 시간 전체입니다.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "days": {
                            "type": "array",
                            "items": {
                              "type": "integer"
                            }
                          },
                          "start": {
                            "type": "string"
                          },
                          "end": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              },
              "messagePolicy": {
                "type": "object",
                "nullable": true,
                "description": "끝내 통화가 안 된 분께 보낼 문자. null 이면 보내지 않습니다.",
                "properties": {
                  "onFirstFail": {
                    "type": "object",
                    "properties": {
                      "body": {
                        "type": "string"
                      }
                    }
                  },
                  "onFinalFail": {
                    "type": "object",
                    "properties": {
                      "body": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "warnings": {
                "type": "array",
                "description": "**생성 응답에만** 포함됩니다. 거절할 정도는 아니지만 알아야 하는 것들 — 발신번호에 문자 전송 이력이 없거나(문자 발신번호 미등록 가능성), 남은 문자 한도가 수신자 수보다 적은 경우입니다.",
                "items": {
                  "type": "string"
                },
                "example": [
                  "07052358010 번호로 문자가 전송된 이력이 없습니다. 문자 발신번호 등록은 음성과 별개 절차라, 등록되지 않은 번호는 발송 요청은 성공해도 통신사에서 전량 거절될 수 있습니다."
                ]
              },
              "dateCreated": {
                "type": "string",
                "format": "date-time"
              },
              "dateUpdated": {
                "type": "string",
                "format": "date-time"
              },
              "counts": {
                "type": "object",
                "description": "상태별 수신자 수 (pending·dialing·done·failed·canceled·expired)",
                "additionalProperties": {
                  "type": "integer"
                },
                "example": {
                  "pending": 120,
                  "dialing": 3,
                  "done": 77
                }
              }
            }
          }
        }
      }
    },
    "400": {
      "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"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "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": "CallFlowId 또는 AgentId를 찾을 수 없음",
      "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"
                  ]
                }
              }
            }
          }
        }
      }
    }
  }
}
```