API v1.0

팡고링고 외부 API

팡고링고 CMS의 다국어 기사 처리를 위한 강력하고 간편한 API를 제공합니다. 워드프레스 등 외부 시스템과 원활하게 연동하세요.

RESTful API
API Key 인증
다국어 지원

개요

팡고링고 외부 API는 워드프레스 등 외부 시스템에서 팡고링고 CMS로 기사를 생성하고, 번역을 요청하며, 번역 상태를 조회하고, 최종 승인하는 완전한 워크플로우를 제공합니다.

지원 기능

사용자 조회
기자 목록 조회 및 검색
사용자 생성
기자 계정 생성
카테고리 조회
카테고리 목록 조회
카테고리 생성
카테고리 생성
기사 생성
외부 시스템에서 원문 기사 등록
번역 요청
다국어 자동 번역 요청
상태 조회
번역 진행 상태 실시간 확인
번역본 수정
특정 지역 번역본 수정
번역본 삭제
특정 지역 번역본 삭제
승인 게시
검수 후 최종 게시 승인
기사 수정
기사 원본 내용 수정
게시 취소
게시된 기사 취소 및 삭제

인증

모든 API 요청은 인증이 필요합니다. 다음 방법 중 하나를 사용하여 API 키를 전달하세요.

인증 방법

Header (권장) x-api-key: YOUR_API_KEY
Header (대안) X-API-Key: YOUR_API_KEY
Query Param ?apiKey=YOUR_API_KEY
Bearer Token Authorization: Bearer YOUR_API_KEY
i

API 키 설정: API 키는 시스템 관리자가 Config 테이블에 configType: BASIC_CONFIG, key: api_key, value: 실제 API 키 값으로 등록해야 합니다.

에러 응답

401 Unauthorized - API 키 누락
{
  "error": "API 키가 필요합니다. x-api-key 헤더 또는 apiKey 쿼리 파라미터를 제공하세요."
}
401 Unauthorized - 유효하지 않은 API 키
{
  "error": "유효하지 않은 API 키입니다."
}
GET /api/external/users

페이지네이션, 검색, 필터링을 지원하는 사용자(기자) 목록 조회

쿼리 파라미터
필드 타입 필수 설명
page integer 선택 페이지 번호 (기본값: 1)
limit integer 선택 페이지당 항목 수 (기본값: 10)
search string 선택 검색어 (이름, 이메일, 로그인ID)
status string 선택 상태 필터 (ACTIVE, INACTIVE, DORMANT)
✓ 200 OK
응답
{
  "items": [
    {
      "id": 1,
      "name": "홍길동",
      "email": "hong@example.com",
      "loginId": "hong",
      "userType": "REPORTER",
      "userGradeId": 1,
      "gradeName": "기자",
      "departmentId": 1,
      "departmentName": "사회부",
      "authorDisplayId": 1,
      "authorDisplayName": "홍길동 기자",
      "profileImage": "https://example.com/profile.jpg",
      "profileDescription": "기자 프로필",
      "status": "ACTIVE",
      "createdAt": "2024-01-01T00:00:00.000Z"
    }
  ],
  "total": 100,
  "page": 1,
  "totalPages": 10
}

에러 응답

401 인증 실패
500 서버 오류
POST /api/external/users

id를 지정하여 사용자(기자)를 생성합니다.

요청 파라미터
필드 타입 필수 설명
id integer 필수 사용자 ID (지정 필수)
loginId string 필수 로그인 ID
password string 필수 비밀번호
email string 필수 이메일 주소
name string 필수 이름
phoneNumber string 선택 전화번호
address string 선택 주소
userType string 선택 사용자 타입 (USER, REPORTER, 기본값: REPORTER)
status string 선택 상태 (ACTIVE, INACTIVE, DORMANT, 기본값: INACTIVE)
userGradeId integer 선택 사용자 등급 ID
departmentId integer 선택 부서 ID
authorDisplayId integer 선택 저자 표시명 ID
profileImage string 선택 프로필 이미지 URL
profileDescription string 선택 프로필 설명
isSubscribed boolean 선택 구독 여부 (기본값: false)
isNotificationEnabled boolean 선택 알림 활성화 여부 (기본값: false)
요청 예시
{
  "id": 100,
  "loginId": "hong",
  "password": "password123",
  "email": "hong@example.com",
  "name": "홍길동",
  "phoneNumber": "010-1234-5678",
  "address": "서울시 강남구",
  "userType": "REPORTER",
  "status": "INACTIVE",
  "userGradeId": 1,
  "departmentId": 1,
  "authorDisplayId": 1,
  "profileImage": "https://example.com/profile.jpg",
  "profileDescription": "기자 프로필",
  "isSubscribed": false,
  "isNotificationEnabled": false
}
✓ 201 Created
응답
{
  "id": 100,
  "loginId": "hong",
  "email": "hong@example.com",
  "name": "홍길동",
  "phoneNumber": "010-1234-5678",
  "userType": "REPORTER",
  "userGradeId": 1,
  "gradeName": "기자",
  "departmentId": 1,
  "departmentName": "사회부",
  "authorDisplayId": 1,
  "authorDisplayName": "홍길동 기자",
  "profileImage": "https://example.com/profile.jpg",
  "profileDescription": "기자 프로필",
  "status": "INACTIVE",
  "createdAt": "2024-01-01T00:00:00.000Z"
}
!

중요: id는 필수이며, 지정한 값이 그대로 사용자 ID로 사용됩니다. 이미 존재하는 id, loginId, 또는 email로 생성 시 400 오류가 발생합니다.

userGradeId가 지정되지 않은 경우, 시스템의 기본 사용자 등급이 자동으로 할당됩니다.

에러 응답

400 필수 필드 누락, 이미 존재하는 사용자 ID/아이디/이메일, 또는 외래 키 제약 조건 위반
401 인증 실패
500 서버 오류
POST /api/external/users/{id}/restore

삭제된 사용자를 UserHistory에서 정보를 복구하여 복원합니다. 삭제 시 저장된 원본 정보를 기반으로 사용자 정보를 복구합니다.

경로 파라미터
필드 타입 필수 설명
id integer 필수 사용자 ID
✓ 200 OK
응답
{
  "id": 100,
  "loginId": "hong",
  "email": "hong@example.com",
  "name": "홍길동",
  "phoneNumber": "010-1234-5678",
  "userType": "REPORTER",
  "userGradeId": 1,
  "gradeName": "기자",
  "departmentId": 1,
  "departmentName": "사회부",
  "authorDisplayId": 1,
  "authorDisplayName": "홍길동 기자",
  "profileImage": "https://example.com/profile.jpg",
  "profileDescription": "기자 프로필",
  "status": "INACTIVE",
  "createdAt": "2024-01-01T00:00:00.000Z"
}
!

중요: 삭제된 사용자만 복구할 수 있습니다. loginIddeleted_user_로 시작하는 사용자만 복구 가능합니다.

UserHistory에 DELETE 타입의 이력이 있어야 복구할 수 있습니다.

password는 복구할 수 없습니다. 복구 후 비밀번호를 재설정해야 합니다.

복구하려는 loginId 또는 email이 이미 다른 사용자에게 사용 중이면 복구가 실패합니다.

복구 시 원본 정보(loginId, email, name, phoneNumber, address, status, profileImage, profileDescription, departmentId, userGradeId, authorDisplayId 등)가 복구됩니다.

복구 작업은 UserHistory에 UPDATE 타입으로 기록됩니다.

에러 응답

400 유효하지 않은 사용자 ID, 이미 복구된 사용자, 삭제 이력 형식 오류, 또는 복구하려는 loginId/email이 이미 사용 중
401 인증 실패
404 사용자를 찾을 수 없음 또는 삭제 이력을 찾을 수 없음
500 서버 오류
PATCH /api/external/users/{id}

특정 사용자(기자)의 정보를 수정합니다. 요청 본문에 포함된 필드만 업데이트되며, 포함되지 않은 필드는 기존 값이 유지됩니다.

경로 파라미터
필드 타입 필수 설명
id integer 필수 사용자 ID
요청 파라미터
필드 타입 필수 설명
email string 선택 이메일 주소
name string 선택 사용자 이름
phoneNumber string 선택 전화번호
address string 선택 주소
userGradeId integer 선택 사용자 등급 ID (null 가능)
departmentId integer 선택 부서 ID (null 가능)
authorDisplayId integer 선택 저자 표시명 ID (null 가능)
status string 선택 계정 상태 (ACTIVE, INACTIVE, DORMANT)
profileImage string 선택 프로필 이미지 URL
profileDescription string 선택 프로필 설명
isSubscribed boolean 선택 구독 여부
isNotificationEnabled boolean 선택 알림 활성화 여부
password string 선택 새 비밀번호 (최소 8자 이상)
요청 예시
{
  "name": "홍길동 (수정됨)",
  "profileDescription": "업데이트된 프로필 설명"
}
✓ 200 OK
응답
{
  "id": 1,
  "loginId": "hong",
  "email": "hong@example.com",
  "name": "홍길동",
  "phoneNumber": "010-1234-5678",
  "address": "서울시 강남구",
  "userType": "REPORTER",
  "userGradeId": 1,
  "gradeName": "기자",
  "departmentId": 1,
  "departmentName": "사회부",
  "authorDisplayId": 1,
  "authorDisplayName": "홍길동 기자",
  "profileImage": "https://example.com/profile.jpg",
  "profileDescription": "기자 프로필 설명",
  "isSubscribed": true,
  "isNotificationEnabled": true,
  "status": "ACTIVE",
  "createdAt": "2024-01-01T00:00:00.000Z"
}
!

중요: 요청 본문에 포함된 필드만 업데이트됩니다. 포함되지 않은 필드는 기존 값이 유지됩니다.

이메일 변경 시 형식 검증 및 중복 검사가 수행됩니다.

userGradeId, departmentId, authorDisplayIdnull로 설정 가능합니다 (관계 제거).

외래 키(userGradeId, departmentId, authorDisplayId)는 존재 여부를 검증합니다.

비밀번호 변경 시 최소 8자 이상이어야 합니다.

변경 이력은 자동으로 UserHistory에 기록됩니다.

에러 응답

400 유효하지 않은 사용자 ID, 유효하지 않은 이메일 형식, 이미 사용 중인 이메일, 존재하지 않는 사용자 등급/부서/저자 표시명 ID, 유효하지 않은 상태 값, 비밀번호가 8자 미만, 수정할 데이터가 없음
401 인증 실패
404 사용자를 찾을 수 없음
500 서버 오류
GET /api/external/categories

카테고리 목록을 조회합니다. RSS 활성화 여부로 필터링 가능합니다.

쿼리 파라미터
필드 타입 필수 설명
rssEnabled boolean 선택 RSS 활성화 여부로 필터링 (true, false)
✓ 200 OK
응답
[
  {
    "id": 1,
    "name": "정치",
    "code": "politics",
    "regionCode": "ko-kr",
    "parentCategoryId": null,
    "rssEnabled": true,
    "rssDescription": "정치 뉴스",
    "rssItemCount": 20,
    "rssUpdateInterval": 60,
    "sortOrder": 1,
    "article_count": 150,
    "childCategories": [
      {
        "id": 2,
        "name": "국회",
        "code": "parliament",
        "regionCode": "ko-kr",
        "parentCategoryId": 1,
        "rssEnabled": true,
        "sortOrder": 1,
        "article_count": 50
      }
    ]
  }
]

에러 응답

401 인증 실패
500 서버 오류
POST /api/external/categories

id와 code를 지정하여 카테고리를 생성합니다.

요청 파라미터
필드 타입 필수 설명
id integer 필수 카테고리 ID (지정 필수)
name string 필수 카테고리 이름
code string 필수 카테고리 코드 (지정 필수)
parentCategoryId integer 선택 상위 카테고리 ID
regionCode string 선택 지역 코드 (기본값: ko-KO)
요청 예시
{
  "id": 100,
  "name": "정치",
  "code": "politics",
  "parentCategoryId": null,
  "regionCode": "ko-KO"
}
✓ 201 Created
응답
{
  "id": 100,
  "name": "정치",
  "code": "politics",
  "regionCode": "ko-KO",
  "parentCategoryId": null,
  "sortOrder": 1,
  "rssEnabled": true,
  "childCategories": []
}
!

중요: idcode는 필수이며, 지정한 값이 그대로 사용됩니다. 이미 존재하는 id 또는 code로 생성 시 400 오류가 발생합니다.

parentCategoryId가 지정된 경우, 해당 상위 카테고리가 존재해야 합니다. 동일한 이름의 카테고리가 같은 상위 카테고리 하위에 이미 존재하면 400 오류가 발생합니다.

에러 응답

400 필수 필드 누락, 이미 존재하는 카테고리 ID/코드/이름, 또는 상위 카테고리가 존재하지 않음
401 인증 실패
500 서버 오류
POST /api/external/articles

워드프레스에서 사용 중인 고유 기사 ID를 포함하여 팡고링고 CMS에 새로운 기사를 생성합니다.

요청 파라미터
필드 타입 필수 설명
externalId Long 필수 워드프레스 고유 기사 ID (이 값이 Article.id로 사용됨)
title string 필수 기사 제목
articleContent string 필수 기사 내용 (HTML 지원)
subTitle string 선택 기사 부제목
thumbnailUrl string 선택 썸네일 이미지 URL
keyword string 선택 키워드 (쉼표로 구분)
categoryIds array 선택 카테고리 ID 목록
reporterIds array 선택 기자 ID 목록
요청 예시
{
  "externalId": "1234567890",
  "title": "기사 제목",
  "subTitle": "기사 부제목",
  "articleContent": "<p>기사 내용 HTML</p>",
  "thumbnailUrl": "https://example.com/image.jpg",
  "keyword": "키워드1, 키워드2",
  "categoryIds": [1, 2, 3],
  "reporterIds": [1, 2]
}
✓ 201 Created
응답
{
  "id": 1234567890,
  "externalId": "1234567890",
  "title": "기사 제목",
  "subTitle": "기사 부제목",
  "status": "DRAFT",
  "message": "기사가 성공적으로 생성되었습니다."
}
!

중요: idexternalId와 동일한 값입니다. externalId로 전달한 값이 그대로 Article.id로 사용됩니다. 이후 모든 API 호출 시 이 id 값을 사용하세요 (예: /api/external/articles/{id}/translate).

에러 응답

400 필수 필드 누락 또는 잘못된 요청
409 이미 존재하는 externalId
500 서버 오류
POST /api/external/translations/auto-translate

입력된 한국어 텍스트를 시스템에 등록된 모든 활성 리전의 언어로 자동 번역합니다. 한국어 리전(ko로 시작하는 리전 코드)은 제외됩니다. 번역은 병렬로 처리되며, OpenAI GPT-4o-mini 모델을 사용합니다.

요청 파라미터
필드 타입 필수 설명
text string 필수 번역할 한국어 텍스트
요청 예시
{
  "text": "안녕하세요. 이것은 테스트 메시지입니다."
}
✓ 200 OK
응답
{
  "translations": [
    {
      "regionCode": "en-us",
      "regionName": "영어 (미국)",
      "translated": "Hello. This is a test message."
    },
    {
      "regionCode": "ja-jp",
      "regionName": "일본어",
      "translated": "こんにちは。これはテストメッセージです。"
    },
    {
      "regionCode": "zh-cn",
      "regionName": "중국어 (간체)",
      "translated": "你好。这是一条测试消息。"
    }
  ],
  "sourceLanguage": "ko",
  "totalRegions": 3
}
!

중요: 시스템에 등록된 모든 활성 리전(status: true)에 대해 번역을 수행합니다.

한국어 리전(리전 코드가 ko로 시작)은 자동으로 제외됩니다.

번역은 병렬로 처리되므로, 여러 리전이 있어도 빠르게 처리됩니다.

개별 리전의 번역이 실패하더라도 다른 리전의 번역은 계속 진행됩니다.

번역 실패 시 해당 리전의 응답에 error 필드가 포함되며, translated 필드는 [리전코드] 원본텍스트 형식으로 반환됩니다.

번역 모델은 뉴스 포털 웹사이트의 UI/UX 요소에 최적화되어 있습니다 (네비게이션 메뉴, 버튼 레이블, 플레이스홀더 텍스트 등).

번역 품질을 위해 전문 뉴스 미디어 웹사이트에서 사용하는 용어를 사용합니다.

지원되는 리전 코드 예시:

  • en-us: 영어 (미국)
  • ja-jp: 일본어
  • zh-cn: 중국어 (간체)
  • zh-tw: 중국어 (번체)
  • fr-fr: 프랑스어
  • de-de: 독일어
  • es-es: 스페인어
  • it-it: 이탈리아어
  • ru-ru: 러시아어
  • ar-ar: 아랍어
  • hi-in: 힌디어
  • pt-br: 포르투갈어 (브라질)
  • pt-pt: 포르투갈어 (포르투갈)
  • nl-nl: 네덜란드어

번역 실패 시 응답 예시

응답
{
  "translations": [
    {
      "regionCode": "en-us",
      "regionName": "영어 (미국)",
      "translated": "Hello. This is a test message."
    },
    {
      "regionCode": "ja-jp",
      "regionName": "일본어",
      "translated": "[JA-JP] 안녕하세요. 이것은 테스트 메시지입니다.",
      "error": "OpenAI API 오류 메시지"
    }
  ],
  "sourceLanguage": "ko",
  "totalRegions": 2
}

에러 응답

400 번역할 텍스트가 없음, 활성화된 리전이 없음
401 인증 실패
500 서버 오류
POST /api/external/articles/{id}/translate

생성된 기사에 대해 지정한 언어로 번역을 요청합니다. 번역은 비동기로 처리됩니다.

경로 파라미터
필드 타입 설명
id integer 원문 기사 ID
요청 파라미터
필드 타입 필수 설명
regions array 필수 번역 대상 언어 코드 목록 (예: ["en-us", "ja-jp"])
prompt string 선택 번역 시 추가 지시사항
요청 예시
{
  "regions": ["en-us", "ja-jp"],
  "prompt": "번역 시 추가 지시사항"
}
✓ 202 Accepted
응답
{
  "message": "번역 요청이 성공적으로 접수되었습니다.",
  "articleId": 1234567890,
  "targetRegions": ["en-us", "ja-jp"]
}
!

번역 요청은 비동기로 처리되며, 즉시 결과를 반환하지 않습니다. 번역 진행 상태는 번역 상태 조회 API를 통해 확인하세요.

에러 응답

400 유효하지 않은 지역 코드
404 기사를 찾을 수 없음
500 서버 오류
POST /api/external/articles/{id}/translate-enhance

생성된 기사에 대해 지정한 언어로 번역을 요청합니다. 번역은 비동기로 처리됩니다.

경로 파라미터
필드 타입 설명
id integer 원문 기사 ID
요청 파라미터
필드 타입 필수 설명
regions array 필수 번역 대상 언어 코드 목록 (예: ["en-us", "ja-jp"])
prompt string 선택 번역 시 추가 지시사항
요청 예시
{
  "regions": ["en-us", "ja-jp"],
  "prompt": "번역 시 추가 지시사항"
}
✓ 202 Accepted
응답
{
  "message": "번역 요청이 성공적으로 접수되었습니다.",
  "articleId": 1234567890,
  "targetRegions": ["en-us", "ja-jp"]
}
!

번역 요청은 비동기로 처리되며, 즉시 결과를 반환하지 않습니다. 번역 진행 상태는 번역 상태 조회 API를 통해 확인하세요.

에러 응답

400 유효하지 않은 지역 코드
404 기사를 찾을 수 없음
500 서버 오류
GET /api/external/articles/{id}/translations

원문 기사 ID를 기준으로 모든 번역본의 상태와 결과를 조회합니다.

경로 파라미터
필드 타입 설명
id integer 원문 기사 ID
✓ 200 OK
응답
{
  "articleId": 1234567890,
  "translations": [
    {
      "region": "en-us",
      "status": "SUCCESS",
      "previewUrl": "https://example.com/preview/en-us/desktop/preview?returnUrl=/en-us/articles/101",
      "title": "Article Title",
      "updatedAt": "2024-01-01T00:00:00.000Z"
    },
    {
      "region": "ja-jp",
      "status": "PROGRESS",
      "previewUrl": "https://example.com/preview/ja-jp/desktop/preview?returnUrl=/ja-jp/articles/102",
      "title": "",
      "updatedAt": "2024-01-01T00:00:00.000Z"
    }
  ]
}

번역 상태

SUCCESS
번역 완료
PROGRESS
번역 진행 중
FAILED
번역 실패

에러 응답

400 잘못된 기사 ID
404 기사를 찾을 수 없음
500 서버 오류
PUT /api/external/articles/{id}/translations/{region}

특정 지역의 번역본을 수정합니다. title과 subTitle의 HTML 엔티티는 자동으로 실제 문자로 변환됩니다.

경로 파라미터
필드 타입 설명
id integer 원문 기사 ID
region string 지역 코드 (예: en-us, ja-jp)
요청 파라미터
필드 타입 필수 설명
title string 필수 번역 제목
subTitle string 선택 번역 부제목
articleContent string 필수 번역 내용 (HTML 지원)
thumbnailUrl string 선택 썸네일 이미지 URL
keyword string 선택 키워드
status string 선택 번역 상태 (SUCCESS, FAILED, PROGRESS, 기본값: SUCCESS)
요청 예시
{
  "title": "수정된 번역 제목",
  "subTitle": "수정된 번역 부제목",
  "articleContent": "<p>수정된 번역 내용 HTML</p>",
  "thumbnailUrl": "https://example.com/new-image.jpg",
  "keyword": "수정된 키워드",
  "status": "SUCCESS"
}
✓ 200 OK
응답
{
  "id": 101,
  "title": "수정된 번역 제목",
  "subTitle": "수정된 번역 부제목",
  "region": "en-us",
  "status": "SUCCESS",
  "updatedAt": "2024-01-01T12:00:00.000Z"
}
TIP

요청 본문에 포함된 필드만 업데이트됩니다. 포함되지 않은 필드는 기존 값이 유지됩니다.

본문 내 연관기사 블록의 기사 ID는 자동으로 번역된 기사 ID로 매핑됩니다. 썸네일 관련 필드(thumbnailUrl_1_1, thumbnailUrl_3_2 등)도 업데이트 가능합니다.

에러 응답

400 필수 필드 누락 또는 잘못된 요청
401 인증 실패
404 기사 또는 번역본을 찾을 수 없음
500 서버 오류
DELETE /api/external/articles/{id}/translations/{region}

특정 지역의 번역본을 삭제합니다.

경로 파라미터
필드 타입 설명
id integer 원문 기사 ID
region string 지역 코드 (예: en-us, ja-jp)
요청 예시
curl -X DELETE https://api.example.com/api/external/articles/1234567890/translations/en-us \
  -H "x-api-key: YOUR_API_KEY"
✓ 200 OK
응답
{
  "message": "번역본이 성공적으로 삭제되었습니다.",
  "articleId": 1234567890,
  "region": "en-us"
}
!

주의: 번역본 삭제 시 원본 기사는 영향받지 않습니다. 삭제된 번역본은 복구할 수 없으므로 주의하세요.

에러 응답

400 잘못된 기사 ID
401 인증 실패
404 기사 또는 번역본을 찾을 수 없음
500 서버 오류
POST /api/external/articles/{id}/approve

번역 검수 후 기사를 승인하여 게시 상태를 최종 확정합니다.

경로 파라미터
필드 타입 설명
id integer 원문 기사 ID
요청 파라미터
필드 타입 필수 설명
publishAt string 선택 게시 날짜 (ISO 8601 형식, 기본값: 현재 시간)
요청 예시
{
  "publishAt": "2024-01-01T00:00:00.000Z"
}
✓ 200 OK
응답
{
  "message": "기사가 성공적으로 승인되고 게시되었습니다.",
  "articleId": 1234567890,
  "publishedAt": "2024-01-01T00:00:00.000Z"
}
TIP

승인 시 번역 완료된 번역본(status: SUCCESS)만 게시됩니다. 번역 진행 중이거나 실패한 번역본은 게시되지 않습니다.

에러 응답

400 잘못된 기사 ID
404 기사를 찾을 수 없음
500 서버 오류
PUT /api/external/articles/{id}

생성된 기사 원본의 내용을 수정합니다. 변경된 필드만 업데이트되며, 번역본(RegionalArticle)도 함께 업데이트됩니다.

경로 파라미터
필드 타입 설명
id integer 원문 기사 ID
요청 파라미터
필드 타입 필수 설명
title string 선택 기사 제목
subTitle string 선택 기사 부제목
articleContent string 선택 기사 내용 (HTML 지원)
thumbnailUrl string 선택 썸네일 이미지 URL
keyword string 선택 키워드
categoryIds array 선택 카테고리 ID 목록 (전체 교체)
reporterIds array 선택 기자 ID 목록 (전체 교체)
relatedArticleIds array 선택 관련 기사 ID 목록 (전체 교체)
grade string 선택 기사 등급 (NORMAL, IMPORTANT, HEADLINE)
status string 선택 기사 상태 (DRAFT, REVIEW, PUBLISHED, REJECTED, DELETED)
type string 선택 기사 타입 (ARTICLE 등)
exposureStartTime string 선택 노출 시작 시간 (ISO 8601 형식)
exposureEndTime string 선택 노출 종료 시간 (ISO 8601 형식)
isMemberOnly boolean 선택 회원 전용 여부
webhookTriggerEnabled boolean 선택 웹훅 트리거 활성화 여부
webPushEnabled boolean 선택 웹푸시 전송 활성화 여부
요청 예시
{
  "title": "수정된 기사 제목",
  "subTitle": "수정된 기사 부제목",
  "articleContent": "<p>수정된 기사 내용 HTML</p>",
  "thumbnailUrl": "https://example.com/new-image.jpg",
  "keyword": "수정된 키워드",
  "categoryIds": [1, 2, 3],
  "reporterIds": [1, 2],
  "relatedArticleIds": [10, 20],
  "grade": "IMPORTANT",
  "status": "REVIEW",
  "type": "ARTICLE",
  "exposureStartTime": "2024-01-01T00:00:00.000Z",
  "exposureEndTime": "2024-01-31T23:59:59.000Z",
  "isMemberOnly": false,
  "webhookTriggerEnabled": true,
  "webPushEnabled": false
}
✓ 200 OK
응답
{
  "message": "기사가 성공적으로 수정되었습니다.",
  "article": {
    "id": 1234567890,
    "title": "수정된 기사 제목",
    "subTitle": "수정된 기사 부제목",
    "articleContent": "<p>수정된 기사 내용 HTML</p>",
    "status": "REVIEW",
    "categories": [
      {
        "category": {
          "id": 1,
          "name": "정치",
          "code": "politics"
        }
      }
    ],
    "reporters": [
      {
        "reporter": {
          "id": 1,
          "name": "홍길동",
          "email": "hong@example.com"
        }
      }
    ]
  }
}
TIP

중요: 요청 본문에 포함된 필드만 업데이트됩니다. 포함되지 않은 필드는 기존 값이 유지됩니다.

주의: categoryIds, reporterIds, relatedArticleIds를 전달하면 기존 관계가 모두 삭제되고 새로운 관계로 교체됩니다.

기사 수정 시 한국어 번역본(ko-kr)도 함께 업데이트됩니다. 썸네일 이미지는 S3에 자동으로 복사되어 지역별 폴더에 저장됩니다.

에러 응답

400 잘못된 기사 ID 또는 잘못된 요청
404 기사를 찾을 수 없음
500 서버 오류
DELETE /api/external/articles/{id}/cancel

게시된 기사를 취소하고 원본 기사 상태를 DRAFT로 변경합니다. PublishedArticle 및 관련 데이터가 모두 삭제되며, 소셜 미디어 포스트(트위터, 페이스북)도 함께 삭제됩니다.

경로 파라미터
필드 타입 설명
id integer 원문 기사 ID
요청 예시
curl -X DELETE https://api.example.com/api/external/articles/1234567890/cancel \
  -H "x-api-key: YOUR_API_KEY"
✓ 200 OK
응답
{
  "message": "게시가 성공적으로 취소되었습니다.",
  "articleId": 1234567890
}
!

게시 취소 시 수행되는 작업:

  • PublishedArticle 및 관련 데이터 삭제 (카테고리, 기자, 관련기사, 댓글 등)
  • 원본 기사 상태를 DRAFT로 변경
  • NewsSubmission 상태 업데이트 (MSN, ZUM: NOT_SUBMITTED, TWITTER, FACEBOOK: DELETED)
  • 트위터/페이스북 포스트 삭제 (비동기 처리)
  • 캐시 무효화

주의: 게시되지 않은 기사에 대해 호출하면 404 오류가 발생합니다.

에러 응답

400 잘못된 기사 ID
404 기사를 찾을 수 없음 또는 게시된 기사를 찾을 수 없음
500 서버 오류

전체 플로우 예시

기사 생성부터 최종 게시까지의 완전한 워크플로우를 살펴보세요.

i

참고: idexternalId와 동일한 값입니다. externalId로 전달한 값이 그대로 Article.id로 사용됩니다. 이후 모든 API 호출 시 이 id 값을 사용하세요.

원문 기사 생성
cURL
curl -X POST https://api.example.com/api/external/articles \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "externalId": "1234567890",
    "title": "새로운 기사",
    "articleContent": "<p>기사 내용</p>"
  }'
응답
{
  "id": 1234567890,
  "externalId": "1234567890",
  "title": "새로운 기사",
  "subTitle": "테스트 기사 부제목",
  "status": "DRAFT",
  "message": "기사가 성공적으로 생성되었습니다."
}
번역 요청
cURL
# 위에서 받은 id를 사용 (예: 1234567890)
curl -X POST https://api.example.com/api/external/articles/1234567890/translate \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "regions": ["en-us", "ja-jp"]
  }'
응답
{
  "message": "번역 요청이 성공적으로 접수되었습니다.",
  "articleId": 1234567890,
  "targetRegions": ["en-us", "ja-jp"]
}
번역 상태 조회 (폴링)
cURL
# articleId를 사용 (예: 1234567890)
curl https://api.example.com/api/external/articles/1234567890/translations \
  -H "x-api-key: YOUR_API_KEY"
응답 (번역 완료)
{
  "articleId": 1234567890,
  "translations": [
    {
      "region": "en-us",
      "status": "SUCCESS",
      "previewUrl": "https://example.com/preview/en-us/desktop/preview?returnUrl=/en-us/articles/101",
      "title": "New Article",
      "updatedAt": "2024-01-01T01:00:00.000Z"
    },
    {
      "region": "ja-jp",
      "status": "SUCCESS",
      "previewUrl": "https://example.com/preview/ja-jp/desktop/preview?returnUrl=/ja-jp/articles/102",
      "title": "新しい記事",
      "updatedAt": "2024-01-01T01:00:00.000Z"
    }
  ]
}
기사 승인
cURL
# articleId를 사용 (예: 1234567890)
curl -X POST https://api.example.com/api/external/articles/1234567890/approve \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "publishAt": "2024-01-01T12:00:00.000Z"
  }'
응답
{
  "message": "기사가 성공적으로 승인되고 게시되었습니다.",
  "articleId": 1234567890,
  "publishedAt": "2024-01-01T12:00:00.000Z"
}

에러 처리

모든 API는 표준 HTTP 상태 코드를 사용합니다.

HTTP 상태 코드

200 성공
201 생성 성공
202 요청 접수 (비동기 처리)
400 잘못된 요청
401 인증 실패
404 리소스를 찾을 수 없음
409 리소스 충돌 (중복)
500 서버 오류

에러 응답 형식

에러 응답
{
  "error": "에러 메시지",
  "details": "상세 에러 정보 (선택)"
}

주의사항

  • externalId와 id의 관계: externalId로 전달한 값이 그대로 Article.id로 사용됩니다. 즉, idexternalId는 동일한 값입니다. 이후 모든 API 호출 시 이 id 값을 경로 파라미터로 사용하세요.
  • externalId 중복 방지: 동일한 externalId로 중복 생성 시 409 Conflict 오류가 발생합니다.
  • 번역 비동기 처리: 번역 요청은 비동기로 처리되므로, 번역 상태 조회 API를 통해 주기적으로 상태를 확인해야 합니다.
  • 번역 상태 확인: 번역이 완료되기 전에 승인하면, 번역 완료된 번역본만 게시됩니다.
  • 미리보기 URL: 번역 상태 조회 API에서 반환되는 previewUrl을 통해 번역된 기사 내용을 검토할 수 있습니다.
  • 지역 코드: 지원되는 지역 코드는 시스템 설정에 따라 다를 수 있습니다. 일반적으로 ko-kr, en-us, ja-jp, zh-cn 등을 지원합니다.
  • id 사용: 기사 생성 후 반환되는 idexternalId와 동일한 값입니다. 이후 번역 요청, 번역 상태 조회, 승인 등 모든 API 호출에서 이 id를 경로 파라미터로 사용하세요.