채널톡 Open API 뜯어고치기

명세 중심의 문서 관리와 Open API 서버 분리

Jayon • Jinyoung Park, Backend Enginner

  • Backend

안녕하세요, 채널톡 백엔드 엔지니어 제이온입니다.

과거 채널톡 Open API를 사용해 보려다가 문서가 복잡해 연동을 보류했다는 글이 Threads에 올라온 적이 있습니다. 깨진 링크와 오래된 설명에 대한 지적도 있었죠.

채널톡 Open API는 고객사가 자신의 서비스에서 고객 정보를 조회하거나 상담에 메시지를 보낼 때 사용하는 공개 API입니다. 다양한 기능을 제공하고 있었지만, 처음 연동하는 개발자가 필요한 API를 찾고 정확하게 호출하기에는 문서가 충분히 친절하지 않았습니다.

이 게시물을 계기로 저희는 Open API 문서 전반을 다시 점검했습니다. 깨진 링크와 오래된 설명을 고치는 데서 시작했지만, 문제는 문서에만 있지 않았습니다.

명세와 실제 API 응답이 어긋나는 경우가 있었고, 이를 바로잡으려면 API를 구현하고 문서를 만드는 방식부터 다시 고민해야 했습니다. 더 나아가 내부에서 사용하는 데이터 구조가 그대로 외부 응답에 노출되는 구조 역시 함께 개선할 필요가 있었습니다.

이 글에서는 Code-first에서 Design-first로 API 개발 방식을 전환한 이유와, 내부 데이터 구조와 공개 API의 계약을 분리하기 위해 별도의 Open API 서버를 만든 과정을 공유합니다.


Open API 개편이 필요했던 이유

설명과 호출 예시가 어긋난 문서

당시 고객이 참고하는 API 문서는 두 곳에 있었습니다. 사용 방법과 호출 예시를 별도로 정리한 가이드 문서와, 서버 코드에서 생성한 API 명세를 보여주는 Swagger UI였습니다.

문제는 두 문서가 서로 다른 방식으로 관리되고 있었다는 점입니다. 가이드는 직접 작성했지만, Swagger UI에 표시되는 호출 경로와 요청·응답 구조, 설명 등은 서버 코드에서 생성했습니다. 시간이 지나면서 두 문서의 내용이 달라지기 시작했고, 하나의 가이드 안에서도 설명과 실제 호출 예시가 어긋나는 경우가 생겼습니다.

예를 들어 상담을 삭제하는 Delete UserChat 문서는 경로를 /user-chats/{userChatId}로 설명하면서, 호출 예시에는 /user-chats/{id}/remove를 사용했습니다. 처음 API를 사용하는 고객 입장에서는 어느 쪽이 실제 동작하는 API인지 판단하기 어려웠습니다.

설명을 최신 상태로 유지하는 과정에도 문제가 있었습니다. Swagger UI에 표시되는 설명은 Java 코드의 어노테이션(annotation)​에 작성되어 있었습니다. 따라서 API 동작에는 아무런 변화가 없더라도 설명 한 줄을 수정해 고객에게 반영하려면 코드 수정과 메인 서버 재배포가 필요했습니다.

당시 이 과정에는 평균 일주일이 걸렸습니다. 문서의 작은 오류를 발견해도 즉시 수정할 수 없었고, 서버의 배포 주기에 맞춰 기다려야 했습니다.

내부 모델 변경에 영향받는 API 응답

문서와 실제 API의 동작을 맞추는 과정에서 더 근본적인 문제도 드러났습니다. 서버 내부에서 사용하는 모델을 고객에게 반환하는 응답에도 그대로 재사용하고 있었습니다.

여기서 모델은 고객, 상담, 봇처럼 서버가 특정 대상을 표현하기 위해 사용하는 데이터 구조입니다.

봇을 생성하거나 수정하는 기존 API 코드를 보겠습니다. 봇은 메시지를 보낼 때 발신자로 사용하는 대상으로, 이름과 프로필 이미지 등의 정보를 가집니다. 아래는 해당 API의 반환문과 응답 객체를 발췌한 코드입니다.

Java

upsert()는 봇을 생성하거나 수정한 뒤 내부 모델인 CustomBot을 반환합니다. 그리고 BotView는 이 객체를 bot 필드에 그대로 담아 고객에게 응답합니다. 즉, 서버 내부에서 사용하는 데이터 구조가 곧 Open API의 응답 구조가 되는 형태였습니다.

예를 들어 고객이 응답에서 읽는 bot.name은 CustomBot의 name 필드에서 나옵니다. 내부 기능을 변경하면서 이 필드를 제거하거나 직렬화 대상에서 제외하면 Open API 응답에서도 bot.name이 사라집니다. 내부 구현을 위한 변경이 의도치 않게 고객이 사용하는 API 계약까지 바꿀 수 있는 것입니다.

반대의 문제도 있었습니다. CustomBot에 version처럼 서버 내부에서만 필요한 필드가 추가되더라도, 내부 모델을 그대로 직렬화하는 구조에서는 이 값이 고객 응답에 함께 노출될 수 있었습니다.

결국 내부 모델과 Open API 응답이 강하게 결합되어 있어, 내부 구현은 자유롭게 변경하면서 외부에 제공하는 API 계약은 안정적으로 유지하기 어려운 구조였습니다.


Code-first와 Design-first

API 명세에는 호출 경로와 HTTP 메서드, 입력값, 응답 구조 등을 정해진 형식으로 작성합니다. 이때 널리 사용하는 규격이 OpenAPI Specification(OAS)​입니다. 고객에게 제공하는 Open API와 이름은 비슷하지만, OAS는 API를 기술하기 위한 규격입니다.

OAS를 만드는 방법은 크게 두 가지입니다. 코드를 먼저 작성하고 여기서 명세를 추출하는 Code-first, 명세를 먼저 정의하고 이에 맞춰 구현하는 Design-first​입니다.

두 방식의 차이를 보기 위해 사용자 조회에 접속 상태를 추가하는 변경을 예로 들어보겠습니다. 기존 사용자 조회 API에서 필요한 경우에만 접속 상태를 함께 받을 수 있도록 expand=online을 추가한다고 가정합니다.

Plaintext
GET /open/users/user-123
GET /open/users/user-123?expand=online

첫 번째 요청은 기존 사용자 정보만, 두 번째 요청은 접속 상태까지 함께 조회합니다. 인증 정보는 생략했습니다.

아래 그림의 주황색 상자는 각 방식에서 먼저 작성하는 대상입니다. Code-first는 코드에서 명세를 만들고, Design-first는 명세에서 코드의 틀을 만든다는 차이가 있습니다.

코드에서 명세를 만드는 Code-first

Code-first에서는 사용자 조회 코드부터 수정합니다. expand 입력을 처리하고, online이 요청되면 접속 상태를 조회해 응답에 포함합니다. 타입과 필수 여부, 설명과 예시 같은 문서 정보도 코드의 어노테이션에 작성하고, 도구가 이를 읽어 OAS를 생성합니다.

장점은 구현 코드와 문서 정보를 한곳에서 관리할 수 있다는 점입니다. 코드에 이미 선언된 타입을 명세에 다시 작성할 필요도 없습니다. 기존에 어노테이션 기반 명세 생성 도구를 사용하고 있다면 도입 부담도 작습니다.

하지만 코드의 타입만으로 API의 사용 방법을 모두 표현할 수는 없습니다. 예를 들어 online이 항상 포함되는지, expand=online일 때만 포함되는지 같은 조건은 별도의 설명이 필요합니다.

저희의 기존 구조에서는 이 설명까지 Java 어노테이션에 작성했습니다. 설명 한 줄을 수정해도 메인 서버를 다시 배포해야 했고, 설명이 많아질수록 구현 코드 안에서 문서가 차지하는 비중도 커졌습니다.

Code-first에서도 구조만 코드에서 추출하고 설명과 예시는 별도 파일에서 관리하는 방식으로 이 문제를 줄일 수 있습니다. 다만 그렇게 하면 코드와 설명 중 어디를 기준으로 관리할 것인지 다시 정해야 합니다. 이미 여러 곳에 흩어진 문서를 맞추는 데 어려움을 겪고 있던 저희에게는 새로운 관리 지점을 만드는 방향이 적합하지 않았습니다.

명세에서 코드를 만드는 Design-first

Design-first에서는 같은 변경을 OAS에 먼저 정의합니다. expand가 받을 수 있는 값과 online이 응답에 포함되는 조건, 응답 구조를 먼저 작성하고 리뷰합니다.

합의된 명세에서는 코드 생성기를 이용해 입력·응답 타입과 서버 인터페이스를 만듭니다. 개발자는 생성된 인터페이스에 맞춰 실제 접속 상태를 조회하는 로직을 구현합니다.

가장 큰 차이는 고객이 사용할 API의 형태를 구현 전에 검토할 수 있다는 점입니다. 접속 상태를 항상 응답할지, 필요한 경우에만 요청하도록 할지 같은 결정을 코드 작성 전에 논의할 수 있습니다. API를 연동하는 쪽에서도 서버 구현이 끝나기 전에 명세를 기준으로 작업을 준비할 수 있습니다.

설명과 예시 역시 같은 명세에서 관리합니다. 설명만 바뀌었다면 문서를 다시 생성하면 되고, 입력이나 응답 구조가 바뀌었다면 명세에서 코드를 다시 생성한 뒤 구현을 맞춥니다.

물론 비용도 있습니다. OAS 작성 방식과 코드 생성 도구를 익혀야 하고, 기존 구현을 생성된 인터페이스에 맞추는 과정도 필요합니다. 빠르게 만들고 버리는 실험성 API라면 오히려 부담이 될 수 있습니다.

왜 Design-first를 택했나

저희에게 중요했던 것은 두 가지였습니다.

첫째, 고객에게 공개할 입력과 응답을 구현 전에 검토할 수 있어야 했습니다. 내부 구현보다 외부에 제공하는 API의 계약을 먼저 정하고 싶었습니다.

둘째, 문서 수정이 메인 서버 배포에 묶이지 않아야 했습니다. 입력·응답 구조와 설명을 하나의 OAS에서 관리하고, 여기서 문서와 코드의 틀을 각각 생성하기로 했습니다.

새로운 작성 방식과 코드 생성 도구를 익혀야 하는 비용은 있었지만, 저희가 겪고 있던 문제에는 이 구조가 더 적합하다고 판단해 Design-first로 전환했습니다.

문서와 API 구현은 하나의 Open API 저장소에서 관리하기로 했습니다.


OAS를 기준으로 문서와 코드를 관리하기

Design-first로 전환한 뒤에는 OAS를 고객용 REST API의 기준으로 삼았습니다. 문서와 API 구현은 하나의 Open API 저장소에서 관리하고, OAS에서 문서와 서버 인터페이스를 생성했습니다.

OAS에서 문서와 서버 코드 생성

명세를 작성하고 리뷰한 뒤 oapi-codegen으로 Go 타입과 서버 인터페이스를 생성했습니다. 개발자는 생성된 인터페이스에 맞춰 실제 요청을 처리하는 로직을 구현했습니다.

예를 들어 GET /open/users/{userId}의 userId는 OAS에 다음과 같이 정의합니다.

YAML

여기서는 userId가 필수 경로 입력이며 문자열이라고 정의했습니다. 코드 생성 후 서버 인터페이스에도 같은 타입이 반영됩니다.

Go

개발자는 이 인터페이스를 구현해 실제 데이터를 조회하고 응답합니다.

이 구조에서는 설명이나 예시만 바뀌면 OAS에서 문서를 다시 생성해 반영할 수 있습니다. 입력이나 응답 구조가 달라졌다면 코드를 다시 생성한 뒤 구현과 테스트도 함께 수정합니다.

기존처럼 문구 하나를 고치기 위해 메인 서버의 배포 일정을 기다릴 필요가 없어졌습니다.

API 문서 도구 선택

OAS를 고객에게 보여줄 문서 도구도 새로 골랐습니다. 저희가 중요하게 본 것은 설명과 예시의 가독성, 문서 안에서 API를 직접 호출하는 기능(Try it), 스키마 표현의 정확성이었습니다.

인증, 버저닝, Rate Limit처럼 특정 API에 속하지 않는 사용 가이드도 API Reference와 같은 문서에서 제공할 수 있어야 했습니다.

검토한 도구는 ReDoc, Stoplight Elements, Scalar였습니다. 당시 저희 구성에 적용하며 확인한 특징은 다음과 같습니다.

도구

특징과 장점

당시 적용에서의 제약

ReDoc

설명과 요청·응답 예시를 나란히 보여주며 정적 HTML 문서 생성이 쉬움

검토한 오픈소스 구성에서는 Try It을 제공하지 않았음

Stoplight Elements

문서와 Try It을 함께 제공하고 기존 웹 페이지에 삽입할 수 있음

nullable 타입 표시 문제와 함께, 당시 구성에서는 자유롭게 작성한 가이드를 API Reference와 같은 탐색 구조에 넣기 어려웠음

Scalar

Try It을 기본 제공하고 화면 구성이 저희가 원하던 형태에 가까웠음

도입을 막는 큰 제약을 발견하지 못했음

당시 검토한 Stoplight Elements 구성에서는 OAS 기반 API Reference는 제공할 수 있었지만, 자유롭게 작성한 가이드를 같은 탐색 메뉴에 배치하기 어려웠습니다.

저희는 가이드와 API Reference를 한곳에서 제공할 수 있고, 문서를 읽은 자리에서 바로 API를 호출할 수 있다는 점을 기준으로 Scalar를 선택했습니다.

아래는 채널톡의 팀 대화방인 그룹을 조회하는 문서 화면입니다. 왼쪽에서 입력값과 설명을 확인하고, 오른쪽에서 실제 요청 예시를 보거나 바로 API를 호출할 수 있습니다.

번역 누락과 문서 검수

한국어와 영어 문서를 제공하기 위해 OAS의 영어 설명을 추출해 Tolgee에 등록하고, 번역 결과를 한국어 명세에 반영했습니다.

그룹 메시지 목록을 검수하던 중 파일과 반응 정보의 설명 일부가 번역되지 않은 것을 발견했습니다. 원인은 번역 문자열을 추출하는 코드가 배열 내부에 중첩된 객체까지 탐색하지 못한 것이었습니다.

OAS의 구조를 재귀적으로 순회하도록 수정해 중첩된 설명도 모두 번역 대상으로 추출했습니다.

하지만 이것만으로는 누락을 완전히 막을 수 없었습니다.

기존 검사는 영어와 한국어 번역 파일의 항목이 같은지만 비교했습니다. 따라서 어떤 설명이 영어와 한국어 양쪽에서 모두 빠지면 두 파일은 서로 일치하기 때문에 검사에 걸리지 않았습니다.

이를 막기 위해 원본 OAS까지 비교 대상으로 추가했습니다. OAS에 있는 설명이 영어 파일에 모두 추출됐는지 확인한 뒤, 영어와 한국어 번역 파일의 항목이 일치하는지도 검사하도록 했습니다.

CI에서는 OAS의 설명이 번역 대상으로 모두 추출됐는지, 영어와 한국어의 번역 항목이 일치하는지, 제품 용어와 문체 규칙을 지키는지 확인합니다. 문서와 코드를 다시 생성했을 때 저장소에 반영된 결과와 차이가 있는지도 검사합니다.

자동 검사만으로 끝내지는 않았습니다. 실제 고객이 보게 될 문서 화면도 직접 읽으며 설명과 예시가 자연스럽고 정확한지 검수했습니다.

이렇게 OAS를 문서와 코드의 기준으로 두면서, API의 구조와 설명을 한곳에서 관리하고 변경 사항이 문서와 구현에 함께 반영되는 흐름을 만들었습니다.


AppStore 호출 체계와의 통합 검토

Open API 서버의 구조를 정하면서, 기존 Open API를 채널톡의 AppStore 호출 체계와 통합할 수 있을지 검토했습니다.

AppStore는 외부 앱과 채널톡의 기능을 연결하는 플랫폼입니다. 채널톡이 앱의 기능을 호출할 수도 있고, 반대로 앱이 채널톡의 고객이나 상담 정보를 조회하고 메시지를 작성할 수도 있습니다.

AppStore에서도 사용자 조회, 상담 조회, 메시지 작성처럼 Open API와 겹치는 기능이 필요했습니다. Open API까지 같은 호출 체계로 통합한다면 중복된 인터페이스를 줄이고, AppStore의 호출·권한 관리 구조와 공개 리소스 모델을 함께 사용할 수 있었습니다.

문제는 기존 고객이 사용하던 호출 방식까지 바뀐다는 점이었습니다.

REST와 Native Function의 차이

기존 Open API는 REST 방식으로 제공하고 있었습니다. 사용자나 상담 같은 리소스를 URL 경로로 표현하고, GET, POST, PATCH 같은 HTTP 메서드로 수행할 작업을 구분합니다.

반면 AppStore에서 앱이 채널톡의 기능을 호출하는 인터페이스를 Native Function이라고 합니다. 앱이 함수 이름과 인자를 전달하면 채널톡이 해당 기능을 실행하는 RPC 형태입니다.

사용자 한 명을 조회하는 상황을 두 방식으로 표현하면 다음과 같습니다. 호출 형태만 비교하기 위해 인증 정보와 일부 인자는 생략했습니다.

Plaintext
GET /open/users/user-123
JSON

REST에서는 users라는 리소스의 user-123을 GET으로 조회합니다. Native Function에서는 공통 경로로 요청하면서 getUser라는 함수 이름과 userId 인자를 전달합니다.

서버가 제공하는 기능은 같지만, 고객이 작성하는 호출 코드는 달라집니다. 기존 Open API 고객이 Native Function으로 전환하려면 URL과 HTTP 메서드뿐 아니라 요청을 구성하고 응답을 처리하는 코드까지 다시 확인해야 했습니다.

기존 고객의 전환 비용 검토

AppStore로 통합하면 저희가 관리해야 하는 호출 체계를 하나로 줄일 수 있었습니다. 하지만 그 비용을 기존 고객이 부담하게 된다는 문제가 있었습니다.

자체 개발팀이 연동을 관리하는 고객도 있었지만, 외주 개발을 통해 Open API 연동을 구축한 고객도 있었습니다. 이런 고객은 호출 방식을 바꾸기 위해 개발을 다시 의뢰해야 할 수도 있었습니다.

고객의 기술 연동을 지원하는 FDE에서도 이러한 전환 비용을 짚었습니다. 저희의 관리 부담을 줄이기 위해 기존 고객에게 연동을 다시 개발하고 검증하도록 요청하기는 어려웠습니다.

비교 기준

AppStore 호출 방식으로 통합

REST 유지

팀의 관리 범위

AppStore를 중심으로 하나의 호출 체계를 운영할 수 있음

외부에 제공하는 REST 인터페이스를 별도로 관리해야 함

기존 고객의 전환 비용

호출 방식 변경과 기존 연동 재검증이 필요함

기존 REST 호출 방식을 그대로 사용할 수 있음

결국 이번 개편에서는 고객이 사용하는 REST 호출 방식은 유지하기로 했습니다.

대신 Open API와 AppStore가 함께 사용할 공개 리소스 모델을 정의했습니다. 외부 호출 방식은 각각 유지하되, 공개 리소스 모델은 공유하는 구조를 선택한 것입니다.


고객용 응답을 위한 Open API 서버 분리

처음에는 Open API 전용 서버를 따로 둘 필요가 있는지 의문이 있었습니다. 고객 요청을 기존 서버에 전달하기만 하는 단순한 프록시라면 서버 하나를 더 운영할 이유가 크지 않았기 때문입니다.

하지만 일부 Open API는 여러 내부 API의 결과를 고객용 응답 하나로 조합해야 했습니다.

고객용 응답 구성과 외부 API 정책을 메인 서버에서 분리하기 위해 Go 기반 Open API 서버를 만들었습니다. 실제 리소스의 조회와 수정은 기존 메인 서버의 Core API가 담당합니다.

전체 호출 구조는 아래와 같습니다. Dropwizard는 기존 Java 메인 서버에서 사용하는 프레임워크이며, Core API는 이 서버 내부에 있습니다.

고객은 Open API 서버에 REST 요청을 보내고 JSON 응답을 받습니다. Open API 서버가 Core API를 호출할 때는 요청과 응답을 Protocol Buffers(Protobuf)로 직렬화해 HTTP POST로 주고받습니다.

내부 모델과 외부 응답 모델의 분리

서버를 분리하는 것만으로는 내부 모델이 고객 응답에 노출되는 문제를 해결할 수 없었습니다.

Open API 서버가 내부 모델을 그대로 반환한다면, 내부 모델의 변경이 외부 API에도 영향을 주기 때문입니다.

그래서 고객에게 공개하는 리소스 모델을 내부 비즈니스 모델과 분리했습니다.

Open API와 AppStore가 함께 사용할 공개 리소스 모델은 ch-proto-public의 proto에 정의했습니다. 반면 OAS에는 고객이 호출하는 경로, HTTP 메서드, 입력값과 최종 JSON 응답 구조를 정의했습니다.

같은 필드를 두 곳에서 중복 정의하지 않도록 proto에서 리소스 모델 스키마를 생성하고, OAS에서는 이를 참조했습니다.

예를 들어 사용자 자체의 필드는 proto에서 정의한 공개 모델을 사용합니다. 사용자 정보와 접속 상태를 어떤 조건에서 하나의 응답으로 묶을지는 고객용 OAS에서 정의합니다.

이렇게 경계를 나누면서 내부 모델을 자유롭게 변경해도 공개 모델로 변환하는 과정에서 영향을 제어할 수 있게 됐습니다. 반대로 공개 모델을 변경하는 경우에는 고객이 받는 데이터도 달라지므로, 명세와 생성 코드뿐 아니라 기존 고객의 연동에 미칠 영향까지 함께 검토합니다.

여러 Core API를 조합해 고객 응답 만들기

Open API 서버가 맡은 역할을 그룹 상세 조회로 살펴보겠습니다. 여기서 매니저는 고객사에서 채널톡을 사용하는 담당자입니다.

고객이 다음 API를 호출합니다.

Plaintext
GET /open/groups/{groupId}

Open API 서버는 먼저 Core API의 getGroup을 호출해 그룹 정보를 조회합니다. 조회한 그룹에 매니저 ID가 있다면 batchGetManagers를 추가로 호출해 필요한 매니저 정보를 한 번에 가져옵니다.

두 API의 결과는 Open API 서버에서 하나의 고객용 응답으로 조합됩니다.

응답의 group에는 그룹 정보가 들어갑니다. managers와 onlines는 그룹의 매니저를 추가로 조회했을 때 얻은 매니저 정보와 접속 상태입니다.

bookmark와 session처럼 요청에 따라 선택적으로 필요한 정보도 있습니다. bookmark는 현재 읽은 위치를 나타내고, session은 대화 참여 정보를 나타냅니다. 이런 값은 요청의 expand 조건과 조회 결과에 따라 응답에 포함합니다.

즉, 고객은 그룹 상세 조회 API 하나만 호출하지만, Open API 서버 내부에서는 필요한 Core API를 여러 번 호출해 고객에게 필요한 형태의 응답 하나를 만듭니다.

Core API와 Open API 서버의 책임 나누기

API를 조합하다 보면 비슷한 조회 기능을 하나의 범용 Core API로 합치고 싶어질 수 있습니다. 하지만 같은 데이터를 조회하더라도, 어떤 리소스를 통해 접근하느냐에 따라 권한을 확인하는 기준이 달라지는 경우가 있었습니다.

예를 들어 대화 참여 정보는 팀 대화방을 통해 조회할 수도 있고, 고객 상담을 통해 조회할 수도 있습니다. 두 경우에는 접근 권한을 판단할 기준이 서로 다릅니다.

이를 하나의 범용 조회 API로 합치면 호출하는 쪽에서 이러한 차이를 알고 권한 맥락까지 전달해야 합니다. 저희는 그보다는 각 리소스를 담당하는 Core API가 접근 권한까지 판단하도록 했습니다. 그래서 비슷한 API가 생기더라도 그룹 서비스와 상담 서비스에 각각 정의하는 것을 허용했습니다.

역할은 다음과 같이 나눴습니다.

  1. Core API: 리소스를 조회·수정하고, 해당 리소스에 대한 접근 권한을 확인

  2. Open API 서버: 필요한 Core API를 호출해 고객용 응답으로 조합하고, API Key 검증과 Rate Limit을 처리

이 구조를 통해 Core API는 각 리소스의 규칙과 권한을 책임지고, Open API 서버는 여러 내부 데이터를 조합해 고객에게 필요한 형태로 제공할 수 있게 됐습니다.


개편 이후

85개 API 공개와 사용 현황

2026년 7월 9일, 85개의 REST API와 새로운 문서를 공개했습니다.

한국어와 영어 문서, API 사용 가이드, 문서 안에서 직접 요청을 보내볼 수 있는 기능을 함께 제공했습니다.

2026년 9월 6일 기준 직전 24시간 동안 Open API는 1,913,186회 호출됐습니다.

문서에는 만족도와 불편한 점, 필요한 기능을 받을 수 있는 설문도 추가했습니다. 월별 중복 응답을 제외한 결과는 다음과 같습니다.

응답 기간

평균 만족도(5점 만점)

응답 수

2026년 7월

3.71점

21건

2026년 8월

3.67점

24건

2026년 9월

4.60점

30건

AI 연동: MCP와 문서 질의

문서를 사람이 읽는 것뿐 아니라 AI에서도 Open API를 사용할 수 있도록 두 가지 연결 방식을 추가했습니다.

먼저 MCP(Model Context Protocol)를 통해 AI 에이전트가 Open API를 도구처럼 호출할 수 있도록 했습니다. MCP는 AI가 외부 도구와 기능을 사용할 때 활용하는 통신 규약입니다.

또 채널톡의 AI 상담 기능인 ALF에는 Open API 문서를 연결했습니다. 고객은 문서를 읽다가 이해하기 어려운 개념이나 API 사용 방법을 바로 질문할 수 있습니다.

아래는 캠페인과 캠페인 유저의 차이를 질문한 예시입니다.

ALF는 문서를 바탕으로 캠페인을 캠페인 자체의 설정 정보, 캠페인 유저를 해당 캠페인에 대한 사용자별 반응 기록으로 구분해 설명합니다.

즉, 같은 API 명세와 문서를 사람이 읽는 문서뿐 아니라 AI가 API를 호출하고 내용을 이해하기 위한 기반으로도 활용할 수 있게 됐습니다.

새 기능을 추가하는 흐름의 변화

개편 전후에는 새 API를 추가하는 과정도 달라졌습니다.

항목

개편 전

개편 후

기능 구현

리소스 처리와 고객용 응답 구성을 메인 서버에서 함께 담당

Core API의 리소스 작업과 Open API의 응답 조합을 분리

고객 응답

내부 모델 변경이 외부 응답에 영향을 줄 수 있음

공개 리소스 모델과 최종 응답을 별도로 정의

문서 반영

Java 코드 수정 후 메인 서버 배포 필요

OAS 수정 후 문서를 생성해 Open API 서버에 반영

공개 이후에는 제가 리딩하고 있는 팀의 커비(Kirby)​가 유저챗 집계 API를 추가했습니다. 기간과 집계 기준을 지정해 유저챗을 집계하는 기능입니다.

예를 들어 다음 요청은 managedAt을 기준으로 기간을 지정하고, 유저챗을 state별로 묶어 개수를 집계합니다.

JSON

응답에서는 각 상담 상태의 집계 결과를 받을 수 있습니다.

JSON

Core API에는 실제 집계 로직을 구현하고, Open API 서버에는 해당 Core API를 호출해 고객용 응답을 만드는 코드를 추가했습니다. 고객에게 공개할 경로와 입력·응답 구조는 OAS에 정의했습니다.

이렇게 작성한 명세는 API 문서와 MCP 연동에도 함께 활용됩니다.


마무리

이번 개편은 오래된 문서를 고치는 일에서 시작했습니다. 하지만 문서와 실제 API를 맞추는 과정에서, 내부 모델이 외부 응답에 노출되는 구조와 문서를 서버 코드에 의존해 관리하던 방식까지 함께 바꾸게 됐습니다.

OAS를 먼저 정의하는 Design-first 방식으로 전환하고, 내부 모델과 공개 리소스 모델을 분리했습니다. Open API 서버에서는 여러 Core API의 결과를 조합해 고객에게 필요한 응답을 만들고, 같은 명세를 문서와 코드 생성, 번역 검수, MCP 연동에도 활용하고 있습니다.

채널톡 Open API를 직접 사용해 보세요!한국어·영어 가이드와 요청·응답 예시를 확인하고, 문서 안에서 바로 API를 호출해 볼 수 있습니다.

Open API 문서 열기 https://api-doc.channel.works/

문서를 읽다가 궁금한 내용은 ALF에 질문할 수도 있고, AI 에이전트에서 API를 사용하려면 MCP를 연결할 수 있습니다.

사용하면서 불편했던 점이나 필요한 기능이 있다면 문서의 채널톡으로 알려주세요!


API 설계부터 문서와 AI 도구 연동까지, 고객의 개발 경험을 함께 개선하고 싶다면 채널톡 엔지니어링 팀에 합류해 주세요! https://channel.io/ko/careers

We Make a Future Classic Product