팡고링고 외부 API
팡고링고 CMS의 다국어 기사 처리를 위한 강력하고 간편한 API를 제공합니다. 워드프레스 등 외부 시스템과 원활하게 연동하세요.
개요
팡고링고 외부 API는 워드프레스 등 외부 시스템에서 팡고링고 CMS로 기사를 생성하고, 번역을 요청하며, 번역 상태를 조회하고, 최종 승인하는 완전한 워크플로우를 제공합니다.
지원 기능
인증
모든 API 요청은 인증이 필요합니다. 다음 방법 중 하나를 사용하여 API 키를 전달하세요.
인증 방법
x-api-key: YOUR_API_KEY
X-API-Key: YOUR_API_KEY
?apiKey=YOUR_API_KEY
Authorization: Bearer YOUR_API_KEY
API 키 설정: API 키는 시스템 관리자가 Config 테이블에 configType: BASIC_CONFIG, key: api_key, value: 실제 API 키 값으로 등록해야 합니다.
에러 응답
{
"error": "API 키가 필요합니다. x-api-key 헤더 또는 apiKey 쿼리 파라미터를 제공하세요."
}
{
"error": "유효하지 않은 API 키입니다."
}
페이지네이션, 검색, 필터링을 지원하는 사용자(기자) 목록 조회
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| page | integer | 선택 | 페이지 번호 (기본값: 1) |
| limit | integer | 선택 | 페이지당 항목 수 (기본값: 10) |
| search | string | 선택 | 검색어 (이름, 이메일, 로그인ID) |
| status | string | 선택 | 상태 필터 (ACTIVE, INACTIVE, DORMANT) |
{
"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
}
에러 응답
id를 지정하여 사용자(기자)를 생성합니다.
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| id | integer | 필수 | 사용자 ID (지정 필수) |
| loginId | string | 필수 | 로그인 ID |
| password | string | 필수 | 비밀번호 |
| 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
}
{
"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가 지정되지 않은 경우, 시스템의 기본 사용자
등급이 자동으로 할당됩니다.
에러 응답
삭제된 사용자를 UserHistory에서 정보를 복구하여 복원합니다. 삭제 시 저장된 원본 정보를 기반으로 사용자 정보를 복구합니다.
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| id | integer | 필수 | 사용자 ID |
{
"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"
}
중요: 삭제된 사용자만 복구할 수 있습니다. loginId가 deleted_user_로 시작하는 사용자만 복구 가능합니다.
UserHistory에 DELETE 타입의 이력이 있어야 복구할 수 있습니다.
password는 복구할 수 없습니다. 복구 후 비밀번호를 재설정해야 합니다.
복구하려는 loginId 또는 email이 이미 다른 사용자에게 사용 중이면 복구가 실패합니다.
복구 시 원본 정보(loginId, email, name, phoneNumber, address, status, profileImage, profileDescription, departmentId, userGradeId, authorDisplayId 등)가 복구됩니다.
복구 작업은 UserHistory에 UPDATE 타입으로 기록됩니다.
에러 응답
특정 사용자(기자)의 정보를 수정합니다. 요청 본문에 포함된 필드만 업데이트되며, 포함되지 않은 필드는 기존 값이 유지됩니다.
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| id | integer | 필수 | 사용자 ID |
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| 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": "업데이트된 프로필 설명"
}
{
"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, authorDisplayId는 null로 설정 가능합니다 (관계 제거).
외래 키(userGradeId, departmentId, authorDisplayId)는 존재 여부를 검증합니다.
비밀번호 변경 시 최소 8자 이상이어야 합니다.
변경 이력은 자동으로 UserHistory에 기록됩니다.
에러 응답
카테고리 목록을 조회합니다. RSS 활성화 여부로 필터링 가능합니다.
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| rssEnabled | boolean | 선택 | RSS 활성화 여부로 필터링 (true, false) |
[
{
"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
}
]
}
]
에러 응답
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"
}
{
"id": 100,
"name": "정치",
"code": "politics",
"regionCode": "ko-KO",
"parentCategoryId": null,
"sortOrder": 1,
"rssEnabled": true,
"childCategories": []
}
중요: id와 code는 필수이며, 지정한 값이 그대로 사용됩니다. 이미 존재하는 id 또는 code로 생성 시 400 오류가 발생합니다.
parentCategoryId가 지정된 경우, 해당 상위 카테고리가 존재해야 합니다. 동일한 이름의 카테고리가 같은 상위 카테고리 하위에 이미 존재하면 400 오류가 발생합니다.
에러 응답
워드프레스에서 사용 중인 고유 기사 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]
}
{
"id": 1234567890,
"externalId": "1234567890",
"title": "기사 제목",
"subTitle": "기사 부제목",
"status": "DRAFT",
"message": "기사가 성공적으로 생성되었습니다."
}
중요: id는 externalId와 동일한 값입니다. externalId로 전달한 값이 그대로 Article.id로 사용됩니다. 이후 모든 API 호출 시 이 id 값을 사용하세요 (예: /api/external/articles/{id}/translate).
에러 응답
입력된 한국어 텍스트를 시스템에 등록된 모든 활성 리전의 언어로 자동 번역합니다. 한국어 리전(ko로 시작하는 리전 코드)은 제외됩니다. 번역은 병렬로 처리되며, OpenAI GPT-4o-mini 모델을 사용합니다.
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| text | string | 필수 | 번역할 한국어 텍스트 |
{
"text": "안녕하세요. 이것은 테스트 메시지입니다."
}
{
"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
}
에러 응답
생성된 기사에 대해 지정한 언어로 번역을 요청합니다. 번역은 비동기로 처리됩니다.
| 필드 | 타입 | 설명 |
|---|---|---|
| id | integer | 원문 기사 ID |
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| regions | array | 필수 | 번역 대상 언어 코드 목록 (예: ["en-us", "ja-jp"]) |
| prompt | string | 선택 | 번역 시 추가 지시사항 |
{
"regions": ["en-us", "ja-jp"],
"prompt": "번역 시 추가 지시사항"
}
{
"message": "번역 요청이 성공적으로 접수되었습니다.",
"articleId": 1234567890,
"targetRegions": ["en-us", "ja-jp"]
}
번역 요청은 비동기로 처리되며, 즉시 결과를 반환하지 않습니다. 번역 진행 상태는 번역 상태 조회 API를 통해 확인하세요.
에러 응답
생성된 기사에 대해 지정한 언어로 번역을 요청합니다. 번역은 비동기로 처리됩니다.
| 필드 | 타입 | 설명 |
|---|---|---|
| id | integer | 원문 기사 ID |
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| regions | array | 필수 | 번역 대상 언어 코드 목록 (예: ["en-us", "ja-jp"]) |
| prompt | string | 선택 | 번역 시 추가 지시사항 |
{
"regions": ["en-us", "ja-jp"],
"prompt": "번역 시 추가 지시사항"
}
{
"message": "번역 요청이 성공적으로 접수되었습니다.",
"articleId": 1234567890,
"targetRegions": ["en-us", "ja-jp"]
}
번역 요청은 비동기로 처리되며, 즉시 결과를 반환하지 않습니다. 번역 진행 상태는 번역 상태 조회 API를 통해 확인하세요.
에러 응답
원문 기사 ID를 기준으로 모든 번역본의 상태와 결과를 조회합니다.
| 필드 | 타입 | 설명 |
|---|---|---|
| id | integer | 원문 기사 ID |
{
"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"
}
]
}
번역 상태
에러 응답
특정 지역의 번역본을 수정합니다. 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"
}
{
"id": 101,
"title": "수정된 번역 제목",
"subTitle": "수정된 번역 부제목",
"region": "en-us",
"status": "SUCCESS",
"updatedAt": "2024-01-01T12:00:00.000Z"
}
요청 본문에 포함된 필드만 업데이트됩니다. 포함되지 않은 필드는 기존 값이 유지됩니다.
본문 내 연관기사 블록의 기사 ID는 자동으로 번역된 기사 ID로 매핑됩니다. 썸네일 관련 필드(thumbnailUrl_1_1, thumbnailUrl_3_2 등)도 업데이트 가능합니다.
에러 응답
특정 지역의 번역본을 삭제합니다.
| 필드 | 타입 | 설명 |
|---|---|---|
| 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"
{
"message": "번역본이 성공적으로 삭제되었습니다.",
"articleId": 1234567890,
"region": "en-us"
}
주의: 번역본 삭제 시 원본 기사는 영향받지 않습니다. 삭제된 번역본은 복구할 수 없으므로 주의하세요.
에러 응답
번역 검수 후 기사를 승인하여 게시 상태를 최종 확정합니다.
| 필드 | 타입 | 설명 |
|---|---|---|
| id | integer | 원문 기사 ID |
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| publishAt | string | 선택 | 게시 날짜 (ISO 8601 형식, 기본값: 현재 시간) |
{
"publishAt": "2024-01-01T00:00:00.000Z"
}
{
"message": "기사가 성공적으로 승인되고 게시되었습니다.",
"articleId": 1234567890,
"publishedAt": "2024-01-01T00:00:00.000Z"
}
승인 시 번역 완료된 번역본(status: SUCCESS)만 게시됩니다. 번역 진행 중이거나 실패한 번역본은 게시되지 않습니다.
에러 응답
생성된 기사 원본의 내용을 수정합니다. 변경된 필드만 업데이트되며, 번역본(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
}
{
"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"
}
}
]
}
}
중요: 요청 본문에 포함된 필드만 업데이트됩니다. 포함되지 않은 필드는 기존 값이 유지됩니다.
주의: categoryIds, reporterIds, relatedArticleIds를 전달하면 기존 관계가 모두 삭제되고 새로운 관계로 교체됩니다.
기사 수정 시 한국어 번역본(ko-kr)도 함께 업데이트됩니다. 썸네일 이미지는 S3에 자동으로 복사되어 지역별 폴더에 저장됩니다.
에러 응답
게시된 기사를 취소하고 원본 기사 상태를 DRAFT로 변경합니다. PublishedArticle 및 관련 데이터가 모두 삭제되며, 소셜 미디어 포스트(트위터, 페이스북)도 함께 삭제됩니다.
| 필드 | 타입 | 설명 |
|---|---|---|
| id | integer | 원문 기사 ID |
curl -X DELETE https://api.example.com/api/external/articles/1234567890/cancel \
-H "x-api-key: YOUR_API_KEY"
{
"message": "게시가 성공적으로 취소되었습니다.",
"articleId": 1234567890
}
게시 취소 시 수행되는 작업:
- PublishedArticle 및 관련 데이터 삭제 (카테고리, 기자, 관련기사, 댓글 등)
- 원본 기사 상태를
DRAFT로 변경 - NewsSubmission 상태 업데이트 (MSN, ZUM:
NOT_SUBMITTED, TWITTER, FACEBOOK:DELETED) - 트위터/페이스북 포스트 삭제 (비동기 처리)
- 캐시 무효화
주의: 게시되지 않은 기사에 대해 호출하면 404 오류가 발생합니다.
에러 응답
전체 플로우 예시
기사 생성부터 최종 게시까지의 완전한 워크플로우를 살펴보세요.
참고: id는 externalId와 동일한 값입니다. externalId로 전달한 값이 그대로 Article.id로 사용됩니다. 이후 모든 API 호출 시 이 id 값을 사용하세요.
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": "기사가 성공적으로 생성되었습니다."
}
# 위에서 받은 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"]
}
# 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"
}
]
}
# 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 상태 코드
에러 응답 형식
{
"error": "에러 메시지",
"details": "상세 에러 정보 (선택)"
}
주의사항
- externalId와 id의 관계:
externalId로 전달한 값이 그대로Article.id로 사용됩니다. 즉,id와externalId는 동일한 값입니다. 이후 모든 API 호출 시 이id값을 경로 파라미터로 사용하세요. - externalId 중복 방지: 동일한
externalId로 중복 생성 시409 Conflict오류가 발생합니다. - 번역 비동기 처리: 번역 요청은 비동기로 처리되므로, 번역 상태 조회 API를 통해 주기적으로 상태를 확인해야 합니다.
- 번역 상태 확인: 번역이 완료되기 전에 승인하면, 번역 완료된 번역본만 게시됩니다.
- 미리보기 URL: 번역 상태 조회 API에서 반환되는
previewUrl을 통해 번역된 기사 내용을 검토할 수 있습니다. - 지역 코드: 지원되는 지역 코드는 시스템 설정에 따라 다를 수 있습니다. 일반적으로
ko-kr,en-us,ja-jp,zh-cn등을 지원합니다. - id 사용: 기사 생성 후 반환되는
id는externalId와 동일한 값입니다. 이후 번역 요청, 번역 상태 조회, 승인 등 모든 API 호출에서 이id를 경로 파라미터로 사용하세요.