API 레퍼런스
오류
모든 Kanorio API가 반환하는 공통 오류 형식, 코드와 HTTP 상태 매핑, 그리고 재시도 처리 방법을 설명합니다.
Management API, Content Delivery API, Customer API는 모두 동일한 형식으로 오류를 반환합니다. 각 코드는 모든 API에서 항상 동일한 HTTP 상태 코드와 매핑되므로, 하나의 오류 핸들러로 모든 API를 처리할 수 있습니다.
{ "error": { "code": "SLUG_TAKEN", "message": "Another post already uses this slug.", "details": { "slug": "how-we-feed-our-starter" } } }
| 필드 | 타입 | 참고 |
|---|---|---|
error.code | string | 안정적이고 기계가 읽을 수 있는 코드입니다. 조건 분기에 사용하십시오. |
error.message | string | 로그 및 개발자를 위한 영어 문장입니다. 언제든지 변경될 수 있으므로 이 값을 기준으로 로직을 작성하지 마십시오. |
error.details | object, optional | retryAfter, availableAt, issues, requiredScope 등 코드에 대한 구조화된 컨텍스트입니다. |
성공적인 응답에는 error가 포함되지 않으며, API가 성공 여부를 ok 플래그로 감싸지도 않습니다.
코드별 HTTP 상태
모든 코드는 하나의 상태와 매핑됩니다. 나중에 추가되는 코드도 동일한 규칙을 따르므로, 아직 확인하지 못한 코드라도 상태를 기준으로 처리할 수 있습니다.
| 상태 | 의미 | 예시 |
|---|---|---|
400 | 요청이 잘못되었거나 유효성 검사에 실패했습니다 | VALIDATION, INVALID_CURSOR, INVALID_로 시작하는 코드 |
401 | 자격 증명이 없거나, 유효하지 않거나, 만료되었거나, 취소되었습니다 | UNAUTHORIZED, UNAUTHENTICATED |
403 | 자격 증명은 유효하지만 권한, 플랜, 역할 또는 모드에 의해 허용되지 않습니다 | FORBIDDEN, OWNER_REQUIRED, LIMIT_REACHED, LOCKED |
404 | 이 사이트에 리소스가 존재하지 않습니다 | NOT_FOUND, _NOT_FOUND로 끝나는 코드 |
405 | 이 경로에서 지원되지 않는 메서드입니다 | METHOD_NOT_ALLOWED |
409 | 현재 상태와 충돌합니다(오래된 쓰기, 사용 중인 슬러그, 중복 등) | CONFLICT, SLUG_TAKEN, IDEMPOTENCY_CONFLICT |
413 | 업로드 파일이 너무 큽니다 | FILE_TOO_LARGE |
422 | 입력값은 유효하지만 비즈니스 규칙에 의해 허용되지 않습니다 | SITE_NOT_PUBLISHED, ASSET_IN_USE |
429 | 요청이 너무 많거나 백엔드가 혼잡합니다. 나중에 다시 시도하십시오 | RATE_LIMITED, SEARCH_BUSY, ANALYTICS_BUSY |
500 | 예기치 않은 서버 오류가 발생했습니다 | INTERNAL |
502, 503 | 업스트림 서비스가 실패했거나 일시적으로 사용할 수 없습니다 | UPLOAD_FAILED, SERVICE_UNAVAILABLE, SHARED_SENDER_PAUSED |
API 레퍼런스의 각 작업에는 반환 가능한 코드와 해당 작업에서의 의미가 나열되어 있습니다. OpenAPI 문서에도 x-kanorio-errors로 동일한 목록이 포함되어 있습니다.
유효성 검사 오류
VALIDATION은 details.issues 내의 모든 실패한 필드를 나열합니다. path는 점(dot)을 사용하여 중첩 구조를 나타냅니다.
{ "error": { "code": "VALIDATION", "message": "Input does not match the capability schema.", "details": { "issues": [ { "path": "title", "message": "Required", "code": "invalid_type" } ] } } }
Content Delivery API에서 폼 제출 시 유효하지 않은 답변이 있을 경우 동일한 방식으로 보고되며, path에는 질문 ID가 사용됩니다.
재시도(Retry)
429,502,503오류는 백오프(backoff)를 사용하여 재시도하십시오. 응답에Retry-After헤더나details.retryAfter가 포함된 경우, 해당 시간(초)만큼 대기하십시오.- 다른
4xx응답은 수정 없이 재시도하지 마십시오. 먼저 요청을 수정해야 합니다. - 쓰기 작업 중
409 CONFLICT가 발생하면, 읽기 작업 이후 누군가 리소스를 변경했음을 의미합니다. 리소스를 다시 읽고 병합한 다음, 새로운 타임스탬프로 쓰기 요청을 보내십시오. - 생성 요청은 멱등성 키를 사용하여 안전하게 재시도할 수 있도록 하십시오.
권한 오류
403 응답의 details에는 무엇이 부족한지 설명되어 있습니다. 예를 들어 토큰에 부족한 requiredScope나, 서비스 계정이 계정 수준의 작업을 호출했을 때의 reason: "principal_not_allowed" 등이 포함됩니다. 재시도하는 대신 사용자에게 무엇을 수정해야 하는지 안내하십시오.
요청 ID(Request IDs)
Content Delivery API와 Customer API 응답에는 X-Request-Id 헤더가 포함됩니다. 특정 요청에 대해 지원팀에 문의할 때 이 ID를 함께 제공하십시오.
오류 코드
아래 표는 OpenAPI 문서에서 생성된, 각 API가 현재 반환할 수 있는 모든 코드 목록입니다.
Management API codes
| Code | HTTP status |
|---|---|
EMPTY_SLUG | 400 |
INVALID_BODY | 400 |
INVALID_CURSOR | 400 |
INVALID_EDITED_PATH | 400 |
INVALID_FORMAT | 400 |
INVALID_ORDER | 400 |
INVALID_SUBDOMAIN | 400 |
UNSUPPORTED_EDITED_PATH | 400 |
VALIDATION | 400 |
UNAUTHENTICATED | 401 |
UNAUTHORIZED | 401 |
CUSTOM_DOMAIN_CHANGE_FORBIDDEN | 403 |
CUSTOM_DOMAIN_LIMIT_REACHED | 403 |
FORBIDDEN | 403 |
LIMIT_REACHED | 403 |
MODERATION_LOCKED | 403 |
OWNER_REQUIRED | 403 |
PLAN_CANNOT_PUBLISH | 403 |
PRO_REQUIRED | 403 |
REDIRECT_LIMIT | 403 |
SUBDOMAIN_CHANGE_FORBIDDEN | 403 |
TOKEN_WEBSITE_SCOPED | 403 |
HEADER_NOT_FOUND | 404 |
HOME_PAGE_NOT_FOUND | 404 |
NOT_FOUND | 404 |
OWNER_NOT_FOUND | 404 |
PAGE_NOT_FOUND | 404 |
PARENT_NOT_FOUND | 404 |
PRODUCT_NOT_FOUND | 404 |
WEBSITE_NOT_FOUND | 404 |
METHOD_NOT_ALLOWED | 405 |
CONFLICT | 409 |
CUSTOM_DOMAIN_TAKEN | 409 |
HAS_CHILDREN | 409 |
HOSTED_ONLY | 409 |
HOSTNAME_CONFLICT | 409 |
IDEMPOTENCY_CONFLICT | 409 |
IDEMPOTENCY_IN_PROGRESS | 409 |
KEY_TAKEN | 409 |
PRIMARY_HEADER_PROTECTED | 409 |
READD_COOLDOWN | 409 |
REDIRECT_CONFLICT | 409 |
SLUG_TAKEN | 409 |
SUBDOMAIN_TAKEN | 409 |
TAKEN | 409 |
BLOCKED | 422 |
BREADCRUMB_PARENT_INVALID | 422 |
CONTENT_VALIDATION_FAILED | 422 |
CORE_SECTION_VIOLATION | 422 |
CUSTOM_DOMAIN_BLOCKED | 422 |
CUSTOM_DOMAIN_HIGH_RISK_TLD | 422 |
CUSTOM_DOMAIN_TOO_LONG | 422 |
DEPTH_EXCEEDED | 422 |
DNS_NOT_PROPAGATED | 422 |
DOMAIN_CHANGE_NOT_ALLOWED | 422 |
EMPTY_CONTENT | 422 |
FOREIGN_PAGE | 422 |
HIGH_RISK_TLD | 422 |
HOME_HAS_HIERARCHY | 422 |
HOME_NOT_CREATABLE | 422 |
HOME_NOT_DELETABLE | 422 |
HOME_NOT_SORTABLE | 422 |
HOME_SLUG_IMMUTABLE | 422 |
LINK_IN_BIO_DEDICATED_ENTRY | 422 |
LINK_IN_BIO_NOT_DUPLICABLE | 422 |
META_NOT_LIVE | 422 |
NO_PUBLIC_URL | 422 |
OWNERSHIP_REQUIRED | 422 |
PAGE_LIMIT_REACHED | 422 |
PARENT_NOT_ALLOWED | 422 |
RESERVED_SEGMENT | 422 |
RESERVED_SLUG | 422 |
RESERVED_SUBDOMAIN | 422 |
SANITIZE_FAILED | 422 |
SEARCH_CONSOLE_AUTH_EXPIRED | 422 |
SEARCH_CONSOLE_NOT_CONNECTED | 422 |
SEARCH_CONSOLE_PERMISSION_DENIED | 422 |
SEARCH_CONSOLE_PROPERTY_NOT_FOUND | 422 |
SEGMENT_TOO_LONG | 422 |
SITEMAP_NOT_REACHABLE | 422 |
SUBDOMAIN_MISSING | 422 |
SYSTEM_PAGE_LOCKED | 422 |
TEMPLATE_PRODUCT_LOCKED | 422 |
ANALYTICS_BUSY | 429 |
DAILY_LIMIT_REACHED | 429 |
RATE_LIMITED | 429 |
SEARCH_BUSY | 429 |
SEARCH_CONSOLE_QUOTA_EXCEEDED | 429 |
STOCK_BUSY | 429 |
INTERNAL | 500 |
SEARCH_CONSOLE_ERROR | 502 |
BUSY | 503 |
SEARCH_CONSOLE_UNAVAILABLE | 503 |
SERVICE_UNAVAILABLE | 503 |
WRITE_FROZEN | 503 |
Content Delivery API codes
| Code | HTTP status |
|---|---|
BAD_HOST | 400 |
FILE_TYPE_NOT_ALLOWED | 400 |
INVALID_ANSWERS | 400 |
INVALID_BODY | 400 |
INVALID_CURSOR | 400 |
INVALID_KIND | 400 |
INVALID_LIMIT | 400 |
INVALID_PATH | 400 |
INVALID_QUERY | 400 |
QUERY_REQUIRED | 400 |
QUERY_TOO_LONG | 400 |
QUERY_TOO_SHORT | 400 |
TOO_MANY_PARAMS | 400 |
UNKNOWN_BOT | 400 |
UNSUPPORTED_LOCALE | 400 |
VALIDATION | 400 |
VERIFICATION_EXPIRED | 400 |
NOT_PREVIEW | 403 |
COLLECTION_NOT_FOUND | 404 |
FORM_NOT_FOUND | 404 |
HEADER_NOT_FOUND | 404 |
ITEM_NOT_FOUND | 404 |
PAGE_NOT_FOUND | 404 |
PRODUCT_NOT_FOUND | 404 |
SITE_NOT_FOUND | 404 |
UNIT_NOT_FOUND | 404 |
DUPLICATE_SUBMISSION | 409 |
FILE_TOO_LARGE | 413 |
RATE_LIMITED | 429 |
SEARCH_BUSY | 429 |
QUERY_TIMEOUT | 503 |
UPLOAD_UNAVAILABLE | 503 |
UPSTREAM_UNAVAILABLE | 503 |
Customer API codes
| Code | HTTP status |
|---|---|
BAD_HOST | 400 |
INVALID_CODE | 400 |
INVALID_CURSOR | 400 |
INVALID_EMAIL | 400 |
INVALID_LIMIT | 400 |
VALIDATION | 400 |
UNAUTHENTICATED | 401 |
BOT_PROTECTION_FAILED | 403 |
DOWNLOAD_NOT_ALLOWED | 403 |
EXPIRED | 403 |
FORBIDDEN | 403 |
LIMIT_REACHED | 403 |
LOCKED | 403 |
NOT_RELEASED | 403 |
NO_ATTEMPTS_LEFT | 403 |
REVIEWS_DISABLED | 403 |
CERTIFICATE_DISABLED | 404 |
DELIVERABLE_NOT_FOUND | 404 |
NOT_FOUND | 404 |
NO_FILE | 404 |
NO_RECEIPT | 404 |
ORDER_NOT_FOUND | 404 |
SITE_NOT_FOUND | 404 |
UNIT_NOT_FOUND | 404 |
WEBSITE_NOT_FOUND | 404 |
METHOD_NOT_ALLOWED | 405 |
ALREADY_REVIEWED | 409 |
FILE_NOT_PROTECTED | 409 |
NOT_A_QUIZ | 409 |
QUIZ_NOT_READY | 409 |
ACCOUNT_BLOCKED | 422 |
ALREADY_REGISTERED | 422 |
CHALLENGE_EXPIRED | 422 |
EMAIL_NOT_VERIFIED | 422 |
METHOD_DISABLED | 422 |
VERIFY_FAILED | 422 |
RATE_LIMITED | 429 |
SHARED_SENDER_PAUSED | 503 |
SIGN_FAILED | 503 |
UPSTREAM_UNAVAILABLE | 503 |