토스페이먼츠의 Open API 생태계
안녕하세요, 토스페이먼츠 Server Developer 허지훈입니다.
온라인에서 ‘구매하기’ 버튼을 누르는 그 순간, 사용자는 단 몇 초 만에 결제가 완료되는 경험을 합니다. 하지만 그 짧은 순간 동안, 서버와 서버 사이에서는 수많은 API 호출이 오가며 결제를 처리하고 있죠. 결제창을 띄우는 것부터 승인 요청, 결제 완료, 정산, 그리고 금액 검증까지. 이 모든 과정은 API를 통해 연결됩니다.
토스페이먼츠는 이런 흐름의 중심에서 가맹점이 결제 서비스를 연동할 수 있도록 Open API를 제공합니다. 현재 토스페이먼츠의 Open API는 20만 개 이상의 가맹점에서 사용되고 있습니다. 이 수치는 단순히 규모를 넘어, API가 얼마나 오랫동안 안정적으로 운영되어야 하는지를 보여줍니다. 한 번 연동된 API는 수년, 혹은 수십 년 동안 유지될 수 있고, 잘못 설계된 API 하나는 그만큼의 시간 동안 불편과 유지 비용을 낳습니다.
그래서 토스페이먼츠는 Open API를 단순히 잘 동작하는 것을 넘어, 앞으로 수십 년간 안전하게 운영될 인프라라는 관점에서 설계하고 관리하고 있습니다. API는 단순한 통신 수단이 아니라, 토스페이먼츠와 가맹점이 안정적으로 연결될 수 있는 기반이기 때문입니다.
그렇다면 수십만 개의 가맹점이 사용하는 Open API를 오랫동안 안정적으로 운영하기 위해서는 어떤 것들을 고려해야 할까요? API 설계 방식은 어떻게 정하고, 외부 개발자에게는 어떤 환경을 제공해야 할까요? 보안은 어떻게 보장하고, 내부적으로는 품질을 어떻게 유지할까요?
토스페이먼츠는 이러한 고민을 다섯 가지 핵심 요소로 정리했습니다.
Open API의 5가지 핵심 요소
이번 글에서는 이 중에서 ‘안정성’을 제외한 네 가지 요소, 인터페이스, 외부 생태계, 보안, 내부 생태계에 대해 이야기하려고 합니다. 토스페이먼츠가 Open API를 어떻게 바라보고, 어떤 방식으로 발전시켜 나가고 있는지를 함께 살펴보겠습니다.
1. 인터페이스
API(request-response): 리소스 중심 설계
서로 다른 시스템이 데이터를 주고받기 위해서는 인터페이스가 필요합니다. 가장 익숙한 방식은 요청(Request)과 응답(Response)을 주고받는 API 방식입니다. 토스페이먼츠는 이 API를 설계할 때 쉽고 간결한 디자인을 지향합니다. 개발자가 빠르게 이해하고 일관된 방식으로 사용할 수 있는 API가 결국 더 좋은 개발자 경험을 만든다고 믿기 때문이죠.
이를 위해 API를 구성하는 핵심 요소를 경로(Path), 요청(Request), 응답(Response) 세 부분으로 나누고 각 영역마다 일관된 가이드라인을 세웠습니다. 이 가이드라인은 ‘설명하지 않아도 이해되는 API’를 목표로 합니다.
경로: 일관성과 예측 가능성
가맹점이 URL만 보고도 어떤 인터페이스인지 유추할 수 있도록 토스페이먼츠는 path 규칙에 일관성을 부여했습니다. root path에는 버전이 명시되고, 그 다음에는 도메인(리소스의 이름)이 들어갑니다. 특정 리소스를 지정해야 하는 경우에는 그 리소스의 고유 ID를 path 파라미터로 표현합니다.
https://api.tosspayments.com/v1/payments/5EnNZRJGvaBX7zk2yd8ydw26XvwXkLrx9POLqKQjmAw4b0e1하지만 고유 ID가 아닌 값을 기준으로 구분해야 할 때는 path 대신 query 파라미터나 JSON 필드를 사용하도록 했습니다.
예를 들어 GET 요청은 query 파라미터로, POST 요청은 JSON body 필드로 구분하는 식입니다.
?startDate=2025-07-01&endDate=2025-07-02{
"startDate": "2025-07-01",
"endDate": "2025-07-02"
}이렇게 설계하면 API가 직관적이고, 불필요한 규칙을 외울 필요가 없습니다. URL만 봐도 요청을 이해할 수 있습니다.
요청과 응답: 구조화된 JSON
요청과 응답은 모두 JSON 포맷을 사용합니다. JSON은 계층 구조를 표현할 수 있기 때문에 서로 관련된 정보를 Nested Object 형태로 모듈화해 전달할 수 있습니다.
예를 들어 카드 정보와 현금영수증 정보는 여러 API에서 반복적으로 사용됩니다. 이를 각 응답마다 개별 필드로 두는 대신, 하나의 객체로 묶어 재사용합니다.
{
"paymentKey": "qXJxNkgDKz0EP59Ly",
"card": {
"company": "현대",
"number": "0000********000"
},
"cashReceipt": {
"number": "30200001",
"type": "소득공제"
}
}이 구조를 사용하면 중복을 줄일 수 있을 뿐 아니라 응답을 더 쉽게 인식하고 예측할 수 있습니다.
예를 들어 현금영수증이 발급되지 않았다면 cashReceipt 객체가 null로 내려가고, 발급되었다면 그 안에 세부 필드가 채워집니다. 이 방식은 null 체크가 간단하고, 응답의 의미도 명확하게 전달됩니다.
도메인별 객체 재사용
하나의 도메인과 관련된 API들은 가능한 한 동일한 객체를 재사용하도록 설계했습니다. 결제 승인, 결제 조회, 결제 취소 API의 응답 구조가 모두 동일한 이유도 여기에 있습니다.
이렇게 객체를 재사용하면 개발자가 새로운 API를 사용할 때 별도의 구조를 학습할 필요가 없습니다. 비슷한 API는 비슷한 형태로 응답하므로 사용자는 자연스럽게 응답을 예상할 수 있고, 가맹점 코드의 중복도 줄어듭니다.
결국 이런 구조적 일관성이 개발자의 인지를 높이고, 연동 진입 장벽을 낮추는 효과를 줍니다.
데이터 표현: 코드를 넘어서 이해하기 쉽게
API 설계에서 또 하나의 고민은 타입이나 코드 값 같은 Enumeration의 표현 방식입니다. 기존에는 SC0010 같은 코드나 숫자로 표현하는 방식이 많았습니다.
'SC0010' -> '카드'
'11' -> '하나'이 방식은 시스템 입장에서는 효율적일 수 있지만 사람이 보기에 직관적이지 않고, 코드 표를 따로 확인해야 한다는 불편이 있습니다.
토스페이먼츠는 이 문제를 해결하기 위해 응답 데이터를 한글로 표현하도록 했습니다. 예를 들어 카드사는 “현대”, “국민”, “신한”처럼 은행명이나 상태 값도 자연어로 표시됩니다. 하지만 해외 가맹점처럼 한국어를 사용하지 않는 고객도 존재하기 때문에 이 부분은 HTTP의 Accept-Language 헤더를 활용해 해결했습니다. 요청 헤더에 ko를 지정하면 한글 응답이, en을 지정하면 영어 응답이 내려갑니다.
이 방식은 단순한 번역 지원을 넘어, 응답 데이터의 Localization까지 자연스럽게 구현할 수 있게 해줍니다.
오류 처리: 투명하고 유연하게
요청 처리 결과는 HTTP status code를 통해 표현합니다. 200대 응답은 성공, 그 외에는 오류 상황을 의미합니다. 하지만 status code만으로는 어떤 오류가 발생했는지 구체적으로 알기 어렵습니다.
이를 보완하기 위해 토스페이먼츠는 status code가 200이 아닐 경우, 응답 body에 표준화된 오류 객체를 함께 내려줍니다.
{
"code": "INVALID_CARD_COMPANY",
"message": "유효하지 않은 카드사입니다."
}이 구조는 두 가지 상황을 모두 고려한 결과입니다. 어떤 가맹점은 오류 메시지를 바로 사용자에게 노출하고 싶어하고, 어떤 가맹점은 자체 메시지로 치환하길 원합니다. 그래서 오류 객체에는 code와 message를 함께 포함시켰습니다. 가맹점은 message를 그대로 노출하거나, code를 기준으로 자체 메시지를 보여줄 수 있습니다.
토스페이먼츠의 API는 기능 중심이 아닌 리소스 중심 설계(Resource-Oriented Design)를 따릅니다. 일관된 경로 구조, 예측 가능한 응답 형태, 그리고 개발자 친화적인 데이터 표현까지. 이 모든 기준은 개발자가 ‘생각하는 방식’에 맞춘 결과입니다.
웹훅: API만으로는 부족하다
결제 서비스에서는 모든 상황을 API 방식으로 처리할 수 있는 것은 아닙니다. 예를 들어, 비동기 결제에서는 클라이언트가 결제 요청을 하더라도 원천사로 부터 언제 처리될지 알 수 없습니다. 이때 서버가 응답을 반환할 때까지 클라이언트가 계속 기다려야 한다면 비효율적이겠죠.
이런 경우에는 클라이언트가 요청을 보내면 서버가 “요청을 정상적으로 받았다”는 응답만 먼저 내려주고, 실제 처리가 끝난 시점에 완료 알림을 따로 보내는 것이 더 효율적입니다. 클라이언트는 알림이 올 때까지 다른 작업을 진행할 수 있죠.
Client → POST /payments/confirm
Server → 200 OK (요청 수신 완료)
... (비동기 처리)
Server → Client이처럼 특정 이벤트가 발생했을 때 서버가 클라이언트로 알림을 보내는 방식을 웹훅(Webhook)이라고 합니다. 토스페이먼츠는 결제 서비스를 제공할 때 API와 웹훅, 두 가지 인터페이스를 함께 제공합니다. 즉시 응답이 필요한 작업은 API로, 비동기적으로 결과를 알려줘야 하는 작업은 웹훅으로 처리합니다. 웹훅 인터페이스를 제공할 때는 아래 요소들에 대한 고려가 필요합니다.
1️⃣ 기능 구분
웹훅은 기능에 따라 이벤트 타입을 정의하여 구분합니다. 예를 들어 토스페이먼츠는:
- 결제 상태 변경 이벤트 →
PAYMENT_STATUS_CHANGED - 취소 상태 변경 이벤트 →
CANCEL_STATUS_CHANGED
이렇게 이벤트 타입별로 데이터 객체가 달라집니다.
PAYMENT_STATUS_CHANGED→ Payment 객체CANCEL_STATUS_CHANGED→ Cancel 객체
2️⃣ 웹훅 Payload
앞서 소개한 것 처럼 토스페이먼츠의 API는 리소스 중심으로 설계되어 있습니다. 결제 결과, 취소 내역 등 모든 응답은 리소스 객체 형태로 내려갑니다. 웹훅도 동일한 리소스에 대한 처리 이벤트를 주는 것이므로 이 객체 구조를 그대로 사용합니다.
결제 승인 API 응답
{
"mId": "tosspayments",
"lastTransactionKey": "9C62B18EEF0DE3EB7F4422EB6D14BC6E",
"paymentKey": "5EnNZRJGvaBX7zk2yd8ydw26XvwXkLrx9POLqKQjmAw4b0e1",
"orderId": "a4CWyWY5m89PNh7xJwhk1",
"orderName": "토스 티셔츠 외 2건",
"taxExemptionAmount": 0,
"status": "DONE",
"requestedAt": "2024-02-13T12:17:57+09:00",
// ...
}
PAYMENT_STATUS_CHANGED 웹훅 페이로드
{
"eventType": "PAYMENT_STATUS_CHANGED",
"createdAt": "2022-01-01T00:00:00.000000",
"data": {
"mId": "tosspayments",
"lastTransactionKey": "9C62B18EEF0DE3EB7F4422EB6D14BC6E",
"paymentKey": "5EnNZRJGvaBX7zk2yd8ydw26XvwXkLrx9POLqKQjmAw4b0e1",
"orderId": "a4CWyWY5m89PNh7xJwhk1",
"orderName": "토스 티셔츠 외 2건",
"taxExemptionAmount": 0,
"status": "DONE",
"requestedAt": "2024-02-13T12:17:57+09:00",
// ...
}
//...
}
}이렇게 API와 같은 객체를 사용하게 되면, 사용자 인지 부하가 줄어들고 웹훅 전용 파싱 로직이 불필요해져 복잡도도 낮아집니다.
3️⃣ 웹훅 수신 엔드포인트(Endpoint) 설정
웹훅은 서버가 클라이언트로 보내는 것이기 때문에 클라이언트가 사전에 웹훅을 수신할 엔드포인트를 설정해두어야 합니다.
클라이언트가 웹훅 수신 엔드포인트를 등록할 때는 이벤트 타입별로 자유롭게 설정할 수 있어야 서로 다른 객체를 보내는 웹훅 이벤트를 쉽게 처리할 수 있습니다.
4️⃣ 안정적인 재전송
웹훅은 항상 성공하지 않습니다. 네트워크 이슈나 수신 서비스의 일시적인 장애 등으로 실패할 수 있죠. 이 때 전송에 실패하더라도 서버는 안정적인 재전송을 통해서 웹훅 시스템의 신뢰성을 보장해야 합니다.
하지만 수신 서비스의 장애 상황 같은 경우에는 단순히 즉시 재전송하면 오히려 장애를 악화시킬 수 있습니다. 그래서 웹훅 재전송에는 전략이 필요한데, 토스페이먼츠는 웹훅 수신 서비스가 회복할 수 있는 시간을 주고 불필요한 네트워크 호출을 줄이기 위해 Exponential Backoff 전략을 사용합니다.
더 나아가 토스페이먼츠는 개발자센터에서 웹훅 전송 내역 조회와 수동 재전송 기능을 제공하여 문제시 개발자가 직접 후속 처리할 수 있도록 지원합니다.
2. 외부 생태계: 개발자 경험이 최우선
개발자 경험이란?
개발자 경험(Developer Experience)은 개발자들이 특정 시스템, API, 프레임워크, 개발 도구를 사용할 때 느끼는 전반적인 경험을 의미합니다. 즉, 얼마나 쉽게 이해하고, 빠르게 연동하며, 효율적으로 개발할 수 있는가를 결정하는 요소입니다.
Open API는 단순히 기능을 제공하는 것으로 끝나지 않습니다. 아무리 강력한 기능을 담고 있어도, 개발자 경험이 좋지 않다면 결국 외면받게 됩니다. 결국 Open API의 품질은 기능이 아니라 경험의 완성도로 평가됩니다.
토스페이먼츠는 이 점에 주목해 Open API를 설계하고 운영할 때 “좋은 Open API”의 기준을 기능이 아니라 경험으로 정의하고, 개발자가 처음 연동을 시작하는 순간부터 운영 단계까지 전 과정을 돕는 다양한 도구와 지원 체계를 마련했습니다.
지금부터 토스페이먼츠가 어떻게 개발자 경험을 중심에 두고 외부 생태계를 구축해왔는지 살펴보겠습니다.
1️⃣ 연동 문서
Open API를 처음 연동할 때, 개발자가 가장 먼저 찾는 것은 연동 문서입니다. “이 API는 어떻게 동작하지?”, “요청 형식은 뭐지?” 같은 궁금증의 출발점이 바로 연동 문서죠.
하지만 수동으로 작성된 문서는 언제나 최신 상태를 유지하기 어렵습니다. API가 진화하고 새로운 기능이 추가될 때마다 문서를 직접 수정하다 보면 실제 서버와의 일관성을 유지하기가 어려워요. 일관성이 떨어진 문서는 연동하는 개발자를 혼란스럽게 합니다.
그래서 토스페이먼츠는 연동 문서를 항상 실제 서버의 API 스펙과 자동으로 동기화하기 위해 OpenAPI Specification(OAS) 기반의 문서 자동화 시스템을 구축했습니다.
서버가 springdoc 라이브러리를 통해 OAS를 자동 생성하면, 그 명세를 주기적으로 조회해 연동 문서를 자동으로 업데이트합니다. API의 요청·응답 구조, 인증 방식, 엔드포인트 등의 정보가 서버와 함께 관리되기 때문에 문서와 실제 서비스가 항상 같은 상태로 유지됩니다.
이 자동화된 문서 시스템 덕분에 개발자는 “현재 실제로 동작하는 API”를 기준으로 개발할 수 있습니다. 새로운 기능이 추가되거나 파라미터가 변경되더라도 문서가 즉시 반영되기 때문에, 문서와 서비스의 일관성이 항상 유지됩니다. 이 일관성은 결국 개발자가 API를 신뢰할 수 있는 큰 기반이 됩니다.
또한 토스페이먼츠는 연동 문서를 단순한 기술 매뉴얼이 아니라, 개발자가 서비스 전체를 이해할 수 있는 안내서라고 생각합니다. 문서에는 각 API의 역할과 동작 방식, 그리고 서비스 안에서 그 API가 어떤 위치를 차지하는지가 함께 담겨 있습니다. 이를 통해 개발자는 단순히 요청과 응답을 구현하는 데서 그치지 않고, 토스페이먼츠의 결제 시스템이 어떻게 구성되어 있는지를 자연스럽게 이해할 수 있습니다.
이런 완성도 높은 문서를 만들기 위해 토스페이먼츠에서는 Technical Writer가 개발자 관점에서 문서를 검토하고, 문서를 통해 서비스를 더 명확하게 전달할 방법을 고민하며 연동하는 개발자들이 보다 쉽게 서비스를 이해할 수 있도록 돕고 있습니다.
2️⃣ 샌드박스
아무리 문서가 잘 되어 있어도, 실제로 한 번도 호출해보지 않은 API를 완전히 이해하기는 쉽지 않습니다. 요청을 보내고, 응답을 받아보며, 그 안에 담긴 데이터가 어떤 의미를 가지는지 직접 확인해야 진짜 ‘감’이 잡히죠.
토스페이먼츠는 이런 개발자 경험을 위해 개발자센터 내에서 바로 실행해 볼 수 있는 샌드박스를 제공합니다. 별도의 개발 환경을 세팅하거나 키를 발급받지 않아도, 브라우저에서 즉시 연동을 시작할 수 있는 공간입니다.
샌드박스는 단순히 예제 코드를 보여주는 수준을 넘어, “보면서, 수정하면서, 실행할 수 있는” 완전한 개발 도구로 한 페이지의 왼쪽에는 실제 API 호출에 사용되는 예제 코드가, 오른쪽에는 코드 실행 결과와 함께 동작하는 UI가 함께 표시됩니다. 개발자는 코드를 직접 수정하고 실행해보면서 결과를 즉시 확인하며 API의 역할과 데이터의 흐름을 눈으로 직접 확인하며 학습할 수 있습니다.
이 샌드박스의 장점은 ‘빠른 이해’에 있습니다.
별도의 서버 설정이나 인증 과정 없이 브라우저에서 결제를 발생시켜볼 수 있기 때문에, 처음 연동하는 개발자도 전체 결제 프로세스를 손쉽게 이해할 수 있습니다. 테스트를 위해 임시 서버를 세팅하거나 콘솔을 띄우는 시간을 아낄 수 있다는 것도 큰 장점이죠. 개발자는 API 문서를 읽고 머릿속으로 시뮬레이션하는 대신, 직접 코드를 만지고, 눈으로 결과를 확인하면서 배울 수 있습니다.
결국 샌드박스는 토스페이먼츠가 추구하는 “경험 중심의 Open API”를 가장 직관적으로 보여주는 공간입니다. 문서로는 전달하기 어려운 서비스의 흐름과 사용 맥락을, 직접 체험을 통해 자연스럽게 이해하도록 돕는 것이죠.
3️⃣ 테스트 환경
연동 문서와 샌드박스를 통해 개발을 마쳤다면, 이제 자신의 서비스 안에서 연동한 기능이 올바르게 동작하는지 테스트해야 합니다.
단순 조회 API라면 크게 부담이 없겠지만, 토스페이먼츠의 Open API는 결제 API로 실제 금전의 이동이 발생하기 때문에 개발자가 마음 놓고 실험하기 어렵습니다.
이처럼 민감한 데이터를 다루는 API는 개발자가 부담 없이 테스트할 수 있는 별도의 환경이 필요합니다. 토스페이먼츠는 이런 부담을 줄이기 위해 실제 운영 환경과 거의 똑같이 동작하지만, 결제는 발생하지 않는 테스트 환경을 제공합니다.
테스트 환경을 설계할 때 가장 중요하게 생각한 점은 라이브 환경과의 차이를 최소화하는 것이었습니다. 테스트 결과가 신뢰를 가지려면, 실제 서비스와 동일한 조건에서 실행되어야 하기 때문입니다.
토스페이먼츠는 동일한 코드 베이스로 라이브 환경과 테스트 환경을 구성하고 있습니다. Spring의 Profile 기능을 이용해 테스트 환경에서는 결제 승인 단계에서 외부 원천사 호출을 Mock으로 대체합니다. 내부 로직은 그대로 수행되지만 실제 결제만 일어나지 않기 때문에, 개발자는 라이브 환경과 거의 동일한 흐름으로 기능을 확인할 수 있습니다.
테스트 환경을 구성할 때 또 하나 중요한 점은 테스트 트래픽이 라이브 환경에 영향을 주지 않아야 한다는 것입니다. 토스페이먼츠는 환경별 서버를 완전히 분리하고, 가맹점의 API 키를 기준으로 게이트웨이에서 요청을 분기합니다. 이 구조를 통해 테스트 트래픽이 라이브 시스템에 간섭하지 않고, 라이브 환경의 안정성을 유지할 수 있습니다.
결론적으로 아래와 같은 구조로 구성되어 있습니다.

이렇게 구축된 테스트 환경에서 개발자는 부담 없이 여러 시나리오를 시도해볼 수 있습니다. 서비스를 출시하기 전 단계에서 충분히 안정성을 확보할 수 있죠. 토스페이먼츠는 개발자가 테스트조차 불안하지 않게 API를 실험하고 검증할 수 있는 환경을 만들고자 합니다.
4️⃣ 에러 재현 기능
API를 테스트할 때는 정상적인 동작만 확인해서는 충분하지 않습니다. 서비스를 운영하다 보면 예기치 못한 오류가 발생할 수 있고, 이때 시스템이 어떻게 반응하는지를 미리 검증하는 것이 중요합니다. 특히 특정 에러에 대한 별도 처리를 구현하는 경우, 에러 상황을 테스트하는 과정은 필수적입니다.
문제는 모든 에러를 직접 만들어내기 어렵다는 점입니다. API 명세를 보고 일부러 잘못된 요청을 보내볼 수도 있지만, 개발자가 API의 모든 에러 케이스를 알고 있을 수는 없습니다. 의도적으로 모든 상황을 재현하는 것은 현실적으로 불가능에 가깝습니다.
토스페이먼츠는 이런 문제를 해결하기 위해 테스트 환경에서 에러를 손쉽게 재현할 수 있는 기능을 제공합니다. 테스트 요청의 헤더에 TossPayments-Test-Code 값을 추가하고, 원하는 에러 코드를 지정하면 해당 상황에 맞는 응답이 반환됩니다.
예를 들어, 카드 번호 결제 API에서 유효기간이 잘못된 상황을 테스트하고 싶다면, INVALID_CARD_EXPIRATION 에러 코드를 지정해서 요청을 보내면 됩니다. 그럼 실제 결제를 시도하지 않아도 API는 그 오류가 발생한 것처럼 응답을 내려줍니다.
curl --request POST \
--url https://api.tosspayments.com/v1/payments/key-in \
--header 'Authorization: Basic dGVzdF9za196WExrS0V5cE5BcldtbzUwblgzbG1lYXhZRzVSOg==' \
--header 'Content-Type: application/json' \
--header 'TossPayments-Test-Code: INVALID_CARD_EXPIRATION'
이 기능을 통해 개발자는 다양한 에러 케이스를 빠르게 검증하고, 각 상황에서 애플리케이션이 제대로 대응하는지를 확인할 수 있습니다. 예외 처리가 필요한 로직을 사전에 점검할 수 있어, 서비스 운영 중 발생할 수 있는 문제를 미리 방지할 수 있습니다.
토스페이먼츠는 단순히 API를 제공하는 데 그치지 않고, 개발자가 더 쉽게, 더 안정적으로 테스트할 수 있는 환경을 만들고자 합니다. 에러 재현 기능은 단순한 편의 기능을 넘어, 문제 상황에서도 API가 신뢰할 수 있는 방식으로 동작하도록 만드는 기반이 됩니다.
5️⃣ API 로그 조회: 스스로 트러블슈팅하기
연동 개발을 하다 보면, 모든 것이 한 번에 완벽하게 작동하기는 어렵습니다. 테스트 중 예상치 못한 오류가 발생하거나, 응답이 기대와 다를 수도 있죠. 이럴 때마다 원인을 확인하기 위해 문의를 남기고 기다려야 한다면, 개발자는 자연스럽게 리듬을 잃게 됩니다.
좋은 개발자 경험은 단순히 문서가 잘 되어 있거나 테스트 환경이 완벽하다고 해서 완성되지 않습니다. 연동 과정에서 발생하는 이슈를 직접 파악하고 해결할 수 있는 경험, 즉 트러블슈팅의 경험이 함께 뒷받침되어야 합니다.
토스페이먼츠는 개발자가 스스로 문제를 해결할 수 있도록 개발자센터에서 API 로그 조회 기능을 제공하고 있습니다. 이 기능을 통해 토스페이먼츠 서버가 실제로 어떤 요청을 받았고, 어떤 응답을 내려보냈는지를 직접 확인할 수 있습니다.
Request body와 header, Response body와 header는 물론, 에러가 발생한 경우에는 해당 에러의 원인과 해결 방법까지 함께 표시됩니다. 즉, 단순히 “에러가 났다”는 수준이 아니라 “왜 났는지, 어떻게 해결할 수 있는지”를 한눈에 파악할 수 있는 구조입니다.
개발자는 이 로그를 통해 번거로운 문의 절차 없이 스스로 문제를 분석하고 해결할 수 있습니다. 테스트 단계뿐만 아니라 운영 중에도 동일한 방식으로 로그를 확인할 수 있어, 서비스에서 문제가 발생했을 때 원인과 영향 범위를 빠르게 파악할 수 있습니다.
토스페이먼츠는 API 로그 조회 기능을 통해 개발자가 스스로 문제를 찾아내고 해결할 수 있는 환경을 만드는 데 집중했습니다.
6️⃣ 전문 Technical Account Manager (TAM) 의 실시간 지원
연동 문서, 샌드박스, 테스트 환경, API 로그 조회 등 다양한 도구를 통해 대부분의 문제를 스스로 해결할 수 있지만, 연동 과정에서 예상치 못한 이슈가 생기거나 고민이 되는 부분이 발생할 때도 있습니다.
이럴 때 토스페이먼츠는 Technical Account Manager(TAM)이 실시간으로 소통하며, 가맹점의 상황에 맞는 솔루션을 제시하고 문제를 함께 해결하고 있습니다. 토스페이먼츠의 TAM은 단순히 결제 연동을 돕는 역할을 넘어, 가맹점의 비즈니스 문제를 함께 고민하고 해결책을 제시하며, 가맹점의 성장을 함께 이끄는 동반자의 역할을 수행합니다.
7️⃣ API 버저닝: 기존 연동에 영향 없이 진화하기
수많은 가맹점이 토스페이먼츠의 Open API를 연동해 서비스를 운영하고 있습니다. Open API를 제공하는 입장에서 가장 중요한 것은 API가 언제나 안정적으로 동작할 수 있도록 유지하는 일입니다.
하지만 서비스는 늘 새로운 가치를 제공하기 위해 변화합니다. 이 변화의 과정에서 Open API에도 기능이 추가되거나 스펙이 수정되어야 할 때가 있습니다.
문제는, 이런 변경이 기존에 이미 연동된 서비스에 영향을 줄 수 있다는 점입니다. 예를 들어 해외 결제 기능을 새롭게 도입하면서 결제 금액 필드의 타입이 변경되는 경우처럼, 작은 변경 하나가 연동된 서비스의 오류로 이어질 수 있습니다. 이런 상황을 방지하려면 기존 연동은 그대로 유지하면서도, 새로운 스펙을 함께 제공할 수 있는 구조가 필요합니다.
토스페이먼츠는 이를 위해 API 버저닝(API Versioning)을 적용하고 있습니다. API에 버전을 부여해, 각 버전을 완전히 독립된 API처럼 관리합니다. 서버는 요청에 포함된 버전에 따라 해당 버전에 맞는 요청 검증과 응답 생성을 수행합니다. 덕분에 기존 가맹점의 서비스는 안정적으로 유지되면서, 새로운 기능이나 데이터 구조는 새로운 버전을 통해 확장할 수 있습니다.
새로운 버전이 출시되면 어떤 변경이 있었는지, 이전 버전과 어떤 차이가 있는지를 릴리즈 노트를 통해 명확하게 안내합니다. 이를 통해 개발자는 불필요한 시행착오 없이 필요한 시점에 새로운 버전으로 전환할 수 있습니다.
토스페이먼츠는 API를 변화시키는 과정에서도 기존의 안정성과 신뢰를 지키는 것을 최우선으로 합니다. 버저닝은 그 철학을 지탱하는 가장 기본적인 원칙이며, API가 오래도록 안전하게 발전할 수 있는 기반이 되고 있습니다.
3. 보안: 신뢰할 수 있는 시스템 만들기
Open API를 제공한다는 것은 데이터와 시스템에 대한 접근 경로를 외부에 개방한다는 의미입니다. 누구나 접근할 수 있는 만큼, 보안에 대한 철저한 관리가 필요합니다.
권한이 없는 사용자가 민감한 데이터에 접근하지 못하도록 방지하고, 사용자가 언제나 안전하게 시스템을 이용할 수 있도록 보호해야 합니다. 토스페이먼츠는 이러한 원칙 아래, 여러 보안 계층을 통해 Open API 생태계를 지키고 있습니다.
1️⃣ 인증과 서명
인증(Authentication)은 API를 사용하는 사용자가 누구인지 식별하는 과정입니다. 인증을 통해 사용자의 권한을 검증하고, 요청이 신뢰할 수 있는 사용자로부터 온 것임을 보장합니다.
API: API Key
토스페이먼츠는 가맹점별로 고유한 API Key를 발급하고, API 요청 시 이를 사용해 요청 주체를 식별합니다. 이 인증 과정을 통해 토스페이먼츠는 요청이 어디서 왔는지 명확하게 판단할 수 있습니다.
Webhook: Webhook-Signature
웹훅(Webhook) 역시 동일한 원칙이 적용됩니다. 웹훅은 토스페이먼츠가 가맹점의 서버로 이벤트를 전송하는 구조이기 때문에, 가맹점 입장에서는 “이 요청이 정말 토스페이먼츠가 보낸 것인지”를 검증할 수 있어야 합니다.
이를 위해 토스페이먼츠는 웹훅 헤더로 webhook-signature를 제공합니다. 웹훅의 payload를 사전에 교환한 키로 서명한 뒤 헤더에 담아 전송하며, 가맹점은 이 값을 통해 실제 토스페이먼츠에서 보낸 요청인지, 또 데이터가 중간에서 변조되지 않았는지를 확인할 수 있습니다.
'tosspayments-webhook-signature: v1:TvgZ2rrdPJvzhDBOej8UMybv0SHufgwdiv6+OzANJd4=,v1:/CSvw0DpqBaCVxUAEbzG2Q/7O9V6epYWyKzwavm4MU4='토스페이먼츠는 API 제공자뿐 아니라 생태계 안에 있는 모든 참여자의 보안 수준이 함께 강화되어야 한다고 생각합니다. 그래서 웹훅을 수신하는 쪽의 보안 검증 절차까지 가이드하고 있습니다.
2️⃣ 안전한 통신 채널: TLS
보안의 기본은 안전한 통신 채널입니다. 인증 키나 민감한 데이터가 전송되는 과정에서 노출된다면 어떠한 인증 방식도 무용지물이 되기 때문입니다.
토스페이먼츠는 TLSv1.2를 지원할 뿐 아니라 가장 최신 보안 규격인 TLSv1.3을 전사 모든 네트워크 엔드포인트에 적용하고 있습니다. TLSv1.3은 더 강력한 암호화와 함께 왕복 지연(RTT)이 줄어들어 보안성과 성능을 동시에 향상시킵니다. 현재 토스페이먼츠 전체 트래픽의 80% 이상이 TLSv1.3을 통해 통신하고 있습니다.
이로써 데이터가 전송되는 과정에서 탈취되거나 변조될 가능성을 크게 줄였습니다. 하지만 HTTPS만으로는 완벽하지 않습니다. 중간자 공격(Man-in-the-Middle Attack)과 같은 위협을 완전히 차단하려면 애플리케이션 레이어에서도 추가적인 보안 조치가 필요합니다.
3️⃣ 애플리케이션 레이어 암호화: Encryption Mode
토스페이먼츠는 통신 채널 보안과는 별개로 요청과 응답 데이터를 인터페이스 레벨에서 암호화하는 Encryption Mode를 제공합니다. 이 기능을 사용하면 요청이나 응답이 중간에서 탈취되더라도 공격자는 그 안의 데이터를 읽을 수 없습니다.
Encryption Mode는 API 스펙을 그대로 유지하면서 요청과 응답의 데이터 부분만 추가로 암호화하는 방식으로 동작합니다.
curl --location 'https://api.tosspayments.com/v2/sellers' \
--header 'Authorization: Basic dGVzdF9za196WExrS0V5cE5BcldtbzUwblgzbG1lYXhZRzVSOg==' \
--header 'Content-Type: text/plain' \
--header 'TossPayments-api-security-mode: ENCRYPTION' \
--data 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiaWF0IjoiMjAyNC0wMS0wMVQwMDowMDowMCswOTowMCIsIm5vbmNlIjoiaGVsbG8ifQ..CO1e5UIHhQ7A8Ym4.cMFtE6M3VjSRKuBCF0O5oKg0yIW9-wkJqLMJaYz77aNgEwwDg2sur3AzD8rFNwb5N44a4b_RbyKqvSeAud_Pl5vmRWuaTs0gGzKTH_CXcvxbYVphqredwQrp1UCmrK602KjQ8cHsT_i3BKZiWA3p-6shRr8jZZ61j7RavkLD2gekCi_PM4jcbbMNTumM8VsgLMnaSQ8cUsONA9CPpPVBCgunU3BjzNduDWt-2a4ZCnktjoPHZtqug6o2TL4O-MdUDVbzbbinQdmd5uATi1V4Ne3DbmtpcRhTyQVfh0vkgeMwY9MdguKlyu6s8hONkNiGPVMNMD8INzGYg6sry04o0H9AdXuAcftqFNSqEW**ozwJTm1aonli4YA9V5rnj9jVU4-HRpDy8WI8Rh7NNVhlHakFz_vwqFdKhTP51hD6WmMnt96wFtg**PMDLK1DGGm4JvuAhvghBNkuBk7G67vJ5ZtPnuIXKSWwRPX-LUrlm5NAiIpaWZmlYTW9mk1-6QXOfFUPkkWxi2Mgvb7e_fx_XsFnJ7jJOY-I-BlUJOulDc46.8NsYbB4add3n1rNo0qhDQg'토스페이먼츠는 개발자 경험을 해치지 않기 위해 표준화된 방법이자 많은 언어에서 쉽게 사용할 수 있는 JWT 기반의 JWE(JSON Web Encryption) 방식을 선택했습니다.
암호화된 데이터의 헤더에는 암호화 알고리즘 정보(alg, enc)와 요청의 생성 시각(iat), 고유 식별자(nonce)가 포함됩니다. 서버는 이 값을 활용해 요청이 생성된 후 일정 시간 이내의 요청만 허용하고, 중복 요청은 거부합니다. 이를 통해 재전송 공격(Replay Attack)을 효과적으로 방지할 수 있습니다.
토스페이먼츠는 이 Encryption Mode를 통해 API의 중요도에 따라 다른 보안 정책을 적용하여 가맹점을 보호하고 있습니다.
4️⃣ Rate Limiting: 악의적 사용 방지
토스페이먼츠는 시스템의 자원이 악의적인 사용자에 의해 과도하게 사용되는 것도 방지하고 있습니다.
이를 위해 Rate Limiting 정책을 운영합니다.
특정 요청이 비정상적으로 많이 들어오거나 동일한 요청이 반복되는 경우에는 429 에러를 반환해 API의 남용을 차단합니다. 이를 통해 서비스 안정성을 유지하고, API 키가 유출되었을 때 악의적인 사용자가 대량의 결제나 취소를 수행하는 속도를 제한하여 사고 규모를 최소화할 수 있습니다.
Rate Limiting은 단순히 트래픽을 제어하는 기술이 아닙니다. 예상치 못한 트래픽 급증이나 공격 시도를 빠르게 감지하고, 서비스 전체의 안정성을 지키는 최후의 방어선 역할을 합니다.
4. 내부 생태계: 조직이 함께 만드는 API 품질
지금까지 Open API를 제공하기 위해 필요한 요소들을 살펴봤습니다. 인터페이스 설계, 외부 생태계 구축, 인증과 보안 등은 모두 필수적인 부분입니다.
하지만 또 한가지 중요한 요소가 있는데 바로 내부 조직의 생태계입니다. 내부 조직이 Open API를 얼마나 일관성 있고 효율적으로 개발하고 운영하느냐가 결국 외부로 제공되는 품질을 결정하기 때문입니다.
1️⃣ 공통 라이브러리로 일관성 유지
토스페이먼츠의 내부 시스템은 여러 도메인으로 나뉘어 있습니다. 결제, 취소, 정산 등 각 도메인마다 별도의 서버가 존재하고, 이 서버들이 각자의 역할에 맞는 Open API를 생산합니다.
하지만 가맹점의 입장에서 토스페이먼츠는 ‘하나의 결제 서비스’로 보입니다. 그렇기 때문에 어떤 도메인의 API를 사용하더라도 동일한 방식으로 인증이 이루어지고, 같은 규칙으로 문서화되며, 같은 형태의 응답을 받을 수 있어야 합니다.
이런 일관성을 각 서버가 개별적으로 맞추려면 운영 비용이 급격히 커지는 문제가 발생하는데, 토스페이먼츠는 이런 문제를 해결하기 위해 Open API와 관련된 공통 로직을 내부 라이브러리 형태로 제공하고 있습니다. 각 서버는 이 라이브러리를 통해 인증, 암호화, 에러 응답, 문서 자동화 등 공통된 규약을 쉽게 적용할 수 있습니다.
build.gradle.kts
implementation("com.tosspayments.tosspayments-openapi-common:bank-code:${property(propertyName = "tosspaymentsOpenapiCommonVersion")}")
implementation("com.tosspayments.tosspayments-openapi-common:api-doc:${property(propertyName = "tosspaymentsOpenapiCommonVersion")}")
implementation("com.tosspayments.tosspayments-openapi-common:api-version:${property(propertyName = "tosspaymentsOpenapiCommonVersion")}")
implementation("com.tosspayments.tosspayments-openapi-common:api-response:${property(propertyName = "tosspaymentsOpenapiCommonVersion")}")
implementation("com.tosspayments.tosspayments-openapi-common:api-entity-type:${property(propertyName = "tosspaymentsOpenapiCommonVersion")}")
implementation("com.tosspayments.tosspayments-openapi-common:context-header:${property(propertyName = "tosspaymentsOpenapiCommonVersion")}")
implementation("com.tosspayments.tosspayments-openapi-common:security:${property(propertyName = "tosspaymentsOpenapiCommonVersion")}")
implementation("com.tosspayments.tosspayments-openapi-common:security-endpoint-protection:${property(propertyName = "tosspaymentsOpenapiCommonVersion")}")Controller 예시
@GetMapping("/v1/test")
@OpenApiAuthenticated(types = [OpenApiAuthenticated.Type.SECRET])
@OpenApiSecurityMode(mode = OpenApiSecurityMode.SecurityMode.ENCRYPTION)
fun getTest(
@OpenApiAuthority apiKey: ApiKey,
): OpenApiResponseV2<TestRes> {
val test = testService.getTest()
return OpenApiResponseV2.success(
entityBody = TestResponse(test),
entityType = OpenApiEntityTypeV2.TEST,
version = apiKey.version,
)
}이를 통해 모든 도메인에서 동일한 품질의 API를 제공할 수 있게 되었고, 각 팀은 비즈니스 로직에 더 집중할 수 있게 되었습니다. 즉, 개발자는 인터페이스 구현에 신경 쓰기보다 고객에게 더 나은 가치를 제공하는 기능 개발에 집중할 수 있는 환경이 만들어졌습니다.
2️⃣ Open API Committee: 품질 기준 유지
내부 생태계의 또 다른 축은 Open API Committee입니다. 토스페이먼츠는 도메인별로 다양한 팀이 API를 개발하고 있기 때문에 조직 전체 차원에서의 기준과 조율이 필요했습니다.
Open API Committee는 이러한 표준화와 품질 관리를 담당합니다. Committee는 새로운 API가 개발될 때마다 설계 표준과 가이드라인을 검토하고, 보안 정책과 품질 기준을 준수하는지 함께 논의합니다.
하지만 Committee의 역할은 단순한 검토에 그치지 않습니다. 토스페이먼츠 전반에서 Open API가 더 잘 만들어질 수 있는 환경을 조성하고, 지속적인 품질 개선을 이끌어가는 중심 역할을 하고 있습니다. 예를 들어, API 명세 작성 방식이나 버저닝 정책, 테스트 기준과 릴리즈 절차 등도 Committee에서 논의되고 정립됩니다.
이를 통해 각 도메인이 독립적으로 일하더라도 결과물은 하나의 서비스처럼 일관된 품질을 유지할 수 있습니다.
마치며: 수십 년을 함께할 API
Open API를 제공한다고 하면 보통 “API를 잘 설계하고 문서만 공개하면 되지 않을까?” 라고 생각하기 쉽습니다. 하지만 실제로는 인터페이스부터 개발자 생태계, 보안, 내부 운영 프로세스까지 생각보다 훨씬 많은 요소들이 유기적으로 맞물려 있어야 합니다. API는 단순한 스펙의 나열이 아니라, 수많은 가맹점과 개발자가 오랜 기간 안정적으로 사용할 수 있는 하나의 서비스이기 때문입니다.
토스페이먼츠는 지금도 가맹점에게 더 쉽고, 더 편리하며, 더 믿을 수 있는 Open API를 제공하기 위해 계속해서 고민하고 있습니다. API 설계 기준을 다듬고, 개발자 경험을 개선하고, 보안과 품질을 높이는 과정은 지금 이 순간에도 이어지고 있습니다.
이 글을 읽고 계신 분들 중 토스페이먼츠 Open API를 이미 연동해 사용 중인 개발자분도 계실지 모르겠습니다. 앞으로도 여러분의 서비스가 안정적으로 성장할 수 있도록, 그리고 토스페이먼츠의 API가 그 여정의 든든한 기반이 될 수 있도록 오랫동안 함께하고 싶습니다.
✅ 이번 아티클은 아래 Toss Makers Conference 25의 세션을 바탕으로 재구성되었습니다.
