[DevLog] Python으로 토스증권 Open API 연동하기: 400 에러 삽질부터 포트폴리오 대시보드 완성까지
최근 토스증권에서 Open API를 공개했다는 소식을 듣고, 내 계좌의 자산 현황과 보유 종목을 한눈에 볼 수 있는 나만의 파이썬(Python) 대시보드 스크립트를 만들어 보기로 했다. 단순한 API 호출인 줄 알았으나, 헤더 설정과 계좌 번호 매핑 과정에서 예상치 못한 400 에러들을 만나며 삽질했던 과정을 기록으로 남겨본다.
1. 1단계: OAuth 2.0 인증 토큰(Access Token) 발급
토스증권 개발자 센터에서 발급받은 CLIENT_ID와 CLIENT_SECRET을 이용해 가장 먼저 인증 토큰을 받아와야 한다. 토스증권 API는 x-www-form-urlencoded 형태로 요청을 처리한다. 이 단계는 공식 문서대로 진행하니 무난하게 통과했다.
# OAuth 2.0 Client Credentials 방식 토큰 요청
url = "https://openapi.tossinvest.com/oauth2/token"
payload = {
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(url, data=payload, headers=headers)
2. 첫 번째 난관: account-header-required 에러 (400)
발급받은 토큰을 들고 의기양양하게 보유 종목 조회 엔드포인트(/api/v1/holdings)를 호출했으나, 첫 번째 에러 메시지를 마주했다.
“code”:”account-header-required”, “message”:”x-tossinvest-account 헤더가 필요합니다.”
보유 종목을 조회하려면 내가 어떤 계좌를 조회할 것인지 헤더에 명시해 주어야 했다. X-Tossinvest-Account라는 커스텀 헤더 필드를 추가해야 한다는 사실을 알게 되었다.
3. 두 번째 난관: account-not-found 에러 (400)
토스 앱에서 확인한 실제 내 계좌번호를 헤더에 넣어보았지만, 이번엔 다른 에러가 발생했다.
“code”:”account-not-found”, “message”:”해당 계좌번호를 찾을 수 없습니다.”
원인 분석: 토스증권 API에서 요구하는 계좌 정보는 우리가 평소에 송금할 때 쓰는 계좌번호가 아니라, Open API 내부 시스템에서 식별하기 위해 각 계좌에 별도로 부여한 ‘계좌 일련번호(accountSeq)’였다.
이를 해결하기 위해 보유 종목을 조회하기 전, 계좌 목록 조회 API(/api/v1/accounts)를 먼저 호출하여 내 계좌의 accountSeq를 동적으로 알아내는 로직을 추가했다.
# 계좌 목록에서 accountSeq를 추출하는 로직
response = requests.get("https://openapi.tossinvest.com/api/v1/accounts", headers=headers)
accounts_data = response.json()
# 응답 데이터가 {'result': [{'accountNo': '...', 'accountSeq': 1, ...}]} 구조임을 확인
if 'result' in accounts_data:
account_seq = accounts_data['result'][0]['accountSeq'] # 자동으로 고유 일련번호 획득!
4. 데이터 파싱 및 가동성 테스트 성공!
동적으로 찾아낸 계좌 일련번호를 X-Tossinvest-Account 헤더에 주입하고 다시 호출하자, 마침내 기다리던 내 계좌의 보유 종목 JSON 데이터가 쏟아졌다! 국내 자산뿐만 아니라 해외 소수점 주식까지 아주 디테일하게 데이터가 내려오는 것을 확인할 수 있었다.
복잡한 JSON 데이터를 터미널에서 주식 앱 화면처럼 직관적으로 볼 수 있도록 포맷팅 함수를 거쳐 완성한 최종 대시보드 출력 결과는 다음과 같다. (보안을 위해 종목명과 코드는 가상의 텍스트로 대체했다.)
=================================================================
📊 토스증권 실시간 포트폴리오
=================================================================
💰 총 매수금액: 759,680 원
📈 총 평가금액: 817,650 원
✨ 총 평가손익: +57,970 원 (+4.06%)
📅 전일 대비 : -18,480 원 (-2.15%)
=================================================================
종목명 (단축코드) | 수량 | 평균단가 | 현재가 | 수익률
-----------------------------------------------------------------
국내 자산 A (XXXXXX) | 7 | ₩28,123.6 | ₩28,330.0 | +0.73%
국내 자산 B (XXXXXX) | 3 | ₩26,210.0 | ₩25,955.0 | -0.97%
국내 자산 C (XXXXXX) | 17 | ₩24,672.4 | ₩28,045.0 | +13.66%
국내 자산 D (XXXXXX) | 6 | ₩10,792.5 | ₩10,785.0 | -0.06%
해외 자산 A (XXXX) | 0.16 | $182.2 | $153.8 | -15.58%
해외 자산 B (XXXX) | 6 | $10.7 | $9.0 | -15.78%
=================================================================
💡 이번 작업을 통해 배운 점
- 증권사 Open API마다 계좌를 식별하는 방식이 다르므로, 실제 계좌번호 입력 시 에러가 난다면 계좌 목록 API를 먼저 찔러보자.
- 해외주식 소수점 투자의 경우 수량이 실수(Float) 형태로 들어오므로 파싱할 때
float()처리를 해주어야 데이터가 누락되거나 깨지지 않는다.
성공적으로 데이터를 받아오는 기초 뼈대를 만들었으니, 다음에는 이 스크립트를 활용해 특정 수익률 도달 시 카카오톡이나 텔레그램으로 알림을 보내는 봇을 연동해 볼 계획이다. 끝!