# 오류 코드

> API가 돌려주는 error 코드와 발송 거부 사유 코드, 그리고 각각 할 일.

오류 응답은 대개 `{"error": "...", "detail": "..."}` 모양입니다. 분기에는 `error`만 씁니다. `403 policy_denied`의 첫 응답에는 `detail` 대신 `decision`이 옵니다.

## HTTP 오류

| 상태 | `error` | 뜻과 할 일 |
|---|---|---|
| `400` | `invalid_request` | 요청 모양이 틀렸습니다. `detail`을 보고 고칩니다. |
| `400` | `invalid_recipient` | 받을 수 없는 주소 모양입니다. 일반적인 `로컬@도메인` 주소만 됩니다. |
| `400` | `idempotency_key_required` | `Idempotency-Key` 헤더를 넣습니다. |
| `401` | `unauthorized` | 토큰이 없거나 틀렸거나 폐기·만료됐습니다. |
| `403` | `forbidden` | 토큰에 권한이 없거나 다른 에이전트의 것을 요청했습니다. |
| `403` | `policy_denied` | 정책이 발송을 막았습니다. `decision.reasons`를 봅니다(아래 표). |
| `404` | `message_not_found` · `thread_not_found` · `approval_not_found` · `attachment_not_found` · `schedule_not_found` · `audit_not_found` | 없거나 볼 수 없는 대상입니다. 격리된 메일도 없는 것과 같게 보입니다. |
| `409` | `idempotency_key_reused` | 같은 키를 다른 요청에 썼습니다. 새 키를 씁니다. |
| `409` | `policy_changing` | 정책이 바뀌는 중입니다. 잠시 뒤 다시 합니다. |
| `422` | `forward_refused_injection_risk` | 이 메일의 전달은 거부됐습니다. 자기 말로 새 메일을 씁니다. |
| `429` | `cancel_rate_limited` | 예약 취소가 너무 잦습니다. 소유자에게 알립니다. |
| `502` | `send_failed` | 메일이 나가지 않았습니다. 새 멱등 키로 다시 보낼 수 있습니다. |

## 모든 경로에 공통인 오류

| 상태 | `error` | 뜻과 할 일 |
|---|---|---|
| `400` | `invalid_json` | 본문이 올바른 JSON이 아닙니다. |
| `400` | `invalid_request` | 같은 쿼리 파라미터가 두 번 왔습니다. |
| `404` | `route_not_found` | 없는 경로입니다. 경로와 메서드를 확인합니다. |
| `405` | `method_not_allowed` | 이 경로가 받지 않는 메서드입니다. `Allow` 응답 헤더에 받는 메서드가 있습니다. |
| `413` | `payload_too_large` | 요청 본문은 10 MiB(10,485,760바이트)까지입니다. |
| `500` | `internal_error` | 서버에서 처리하지 못했습니다. `detail`에 요청 ID가 있습니다. |
| `503` | `service_unavailable` | 잠시 쓸 수 없습니다. `detail`에 요청 ID가 있습니다. |

`500`, `503`, 타임아웃, 네트워크 오류가 나면 잠시 기다렸다 **같은** `Idempotency-Key`로 다시 보냅니다. 이미 나간 메일은 두 번 나가지 않습니다. 요청이 몰리면 `429`가 올 수 있고, 이때 본문은 이 표의 모양이 아닐 수 있습니다. 역시 기다렸다 같은 키로 다시 보냅니다. 계속되면 요청 ID를 적어 [지원팀](https://docs.atmark.ai/help/contact)에 알려 주세요.

예약·인증 코드·웹훅 전용 코드는 각 페이지에 있습니다: [예약](https://docs.atmark.ai/api/scheduled#cancel), [인증 코드](https://docs.atmark.ai/api/verification-code), [웹훅](https://docs.atmark.ai/api/webhooks).

## 자주 보는 거부 사유

`policy_denied`의 `decision.reasons`, MCP의 `denied` 결과에 오는 코드 가운데 자주 보는 것입니다. 원인이 그대로면 다시 보내도 결과가 같습니다. 같은 멱등 키로 다시 보내면 원인을 고친 뒤에도 같은 거부가 돌아오므로, 원인을 고쳤거나 `retry_after_seconds`만큼 기다린 뒤에는 **새** 멱등 키로 보냅니다.

| 사유 | 뜻 | 할 일 |
|---|---|---|
| `recipient_not_allowlisted` | 받는 사람이 발신 허용 목록에 없습니다. | 소유자가 허용 목록에 넣습니다. |
| `recipient_blocklisted` | 받는 사람이 발신 차단 목록에 있습니다. | 소유자가 차단 목록에서 뺍니다. |
| `outbound_disabled` | 발신 모드가 "모두 막기"입니다. | 소유자가 모드를 바꿉니다. |
| `recipient_is_self` | 에이전트 자기 주소로 보내려 했습니다. | 자기에게는 보낼 수 없습니다. |
| `suppression_list` | 반송됐거나 스팸으로 신고한 이력이 있는 주소입니다. | 주소를 확인합니다. |
| `rate_limit_per_minute` · `rate_limit_per_hour` · `rate_limit_per_day` | 발송 한도에 닿았습니다. | 기다렸다 보냅니다. |
| `recipients_per_message` · `plan_recipients_per_message` | 메일당 받는 사람이 너무 많습니다. | 나눠 보냅니다. |
| `daily_send_limit` | 조직의 하루 발송 한도에 닿았습니다. 새 조직의 이 한도는 첫 발송 뒤 몇 주에 걸쳐 오릅니다. | 기다렸다 나중에 보냅니다. 요금제로 풀리지 않습니다. |
| `plan_daily_cap` | 요금제의 조직 하루 수신자 한도에 닿았습니다. | 내일 보냅니다. 요금제를 올리면 풀리지만, 베타 기간에는 결제가 열리지 않습니다. |
| `org_pending_review` | 조직이 운영자 검토 중입니다. | 검토가 끝날 때까지 기다립니다. |
| `org_review_rejected` | 가입이 승인되지 않았습니다. | 지원팀에 문의합니다. |
| `org_owner_paused` | 조직 전체가 긴급 정지 중입니다. | 소유자가 정지를 풉니다. |
| `org_abuse_freeze` | 운영자가 조직의 발송을 동결했습니다. | 지원팀에 문의합니다. |
| `org_billing_blocked` | 결제 문제로 발송이 막혔습니다. | 소유자가 **설정 › 요금제**를 확인합니다. |
| `agent_not_active` | 에이전트가 긴급 정지 중이거나 활성 상태가 아닙니다. | 소유자가 확인합니다. |
| `from_forgery` | `from`이 이 에이전트의 주소가 아닙니다. | 에이전트 자기 주소를 씁니다. |
| `evaluation_error` | 판정하지 못해 안전하게 막았습니다. | 잠시 뒤 새 멱등 키로 다시 보냅니다. 계속되면 지원팀에 문의합니다. |

## 사유 코드 전체

공개 API가 지금 `decision.reasons`와 감사 기록의 `reasons`로 돌려주는 코드입니다. 오래된 감사 기록에는 예전 이름이 보일 수 있습니다. 허용된 발송에도 사유가 붙습니다. "예전 모드"는 Atmark 운영자가 설정한 예전 발신 모드(승인 필요·회신만)를 뜻합니다. [승인](https://docs.atmark.ai/email/approvals)

### 거부

| 코드 | 뜻 |
|---|---|
| `org_pending_review` | 조직이 운영자 검토 중입니다. |
| `org_review_rejected` | 가입이 승인되지 않았습니다. |
| `org_owner_paused` | 조직 전체가 긴급 정지 중입니다. |
| `org_abuse_freeze` | 운영자가 조직의 발송을 동결했습니다. |
| `org_billing_blocked` | 결제 문제로 발송이 막혔습니다. |
| `agent_not_active` | 에이전트가 긴급 정지 중이거나 활성 상태가 아닙니다. |
| `outbound_disabled` | 발신 모드가 "모두 막기"입니다. |
| `from_forgery` | `from`이 이 에이전트의 주소가 아닙니다. |
| `recipient_is_self` | 에이전트 자기 주소로 보내려 했습니다. |
| `suppression_list` | 반송되거나 스팸으로 신고된 이력이 있는 주소입니다. |
| `recipient_blocklisted` | 받는 사람이 발신 차단 목록에 있습니다. |
| `recipient_not_allowlisted` | 받는 사람이 발신 허용 목록에 없습니다. |
| `rate_limit_per_minute` · `rate_limit_per_hour` · `rate_limit_per_day` | 에이전트의 분당·시간당·하루 발송 한도에 닿았습니다. |
| `recipients_per_message` | 메일당 받는 사람 수가 에이전트 정책의 한도를 넘었습니다. |
| `plan_recipients_per_message` | 메일당 받는 사람 수가 요금제 한도를 넘었습니다. |
| `recipient_ceiling_exceeded` | 메일당 받는 사람 수가 어떤 요금제로도 넘을 수 없는 상한을 넘었습니다. |
| `daily_send_limit` | 조직의 하루 발송 한도에 닿았습니다. 새 조직은 첫 발송 뒤 몇 주에 걸쳐 오릅니다. |
| `plan_daily_cap` | 요금제의 조직 하루 수신자 한도에 닿았습니다. |
| `budget_exhausted` | 에이전트의 발송 예산에 닿았습니다. 지원팀에 문의합니다. |
| `evaluation_error` | 판정하지 못해 안전하게 막았습니다. |
| `release_window_expired` | 승인은 됐지만 정해진 시간 안에 보내지 못해 닫혔습니다(예전 모드). |
| `reply_only_no_inbound_thread` | 받은 메일의 스레드 밖으로 보내려 했습니다(예전 모드 "회신만"). |
| `reply_only_inbound_quarantined` | 회신하려는 받은 메일이 격리돼 있습니다(예전 모드 "회신만"). |

### 허용

| 코드 | 뜻 |
|---|---|
| `allowlist_match` | 받는 사람이 모두 발신 허용 목록에 있습니다. |
| `unrestricted_mode` | 발신 모드가 "전체"입니다. |
| `not_blocklisted` | "차단 목록" 모드에서 받는 사람이 차단 목록에 없습니다. |
| `approval_granted` | 사람이 승인했습니다. |
| `standing_approval` | 전에 승인한 상대(또는 도메인)입니다(예전 모드). |
| `seed_relationship` | 에이전트를 만들 때 소유자가 넣어 둔 상대입니다(예전 모드). |
| `reply_within_thread` · `auto_approve_reply_within_thread` | 같은 스레드 안의 회신이라 허용됐습니다(예전 모드). |
| `auto_approve_verification_sender` | 인증 메일을 보낸 쪽에 대한 회신이라 허용됐습니다(예전 모드). |
| `auto_approve_domain` | 소유자가 자동 허용한 도메인입니다(예전 모드). |

### 승인 대기

| 코드 | 뜻 |
|---|---|
| `new_recipient` | 처음 보내는 상대라 사람의 승인이 필요합니다(예전 모드 "승인 필요"). |
| `bootstrap_grace` | 예전 모드 "회신만"의 시작 기간에 내려진 판정이라는 표시입니다. |

---

원문: https://docs.atmark.ai/api/errors · 마지막 수정 2026-09-27
