AlgoLab Blog · 증권사 API 가이드 · 2026

토스증권 오픈API 자동매매 — 발급·주문·호출한도 정리

토스증권 · OpenAPI 2026-08-04 · 약 9분 읽기 · 알고랩 AlgoLab
한 줄 요약 토스증권 OpenAPI는 https://openapi.tossinvest.com 한 곳에서 국내(KRX)·미국 주식의 시세·계좌·주문·조건주문을 REST API로만 제공합니다. 인증은 OAuth 2.0 Client Credentials(POST /oauth2/token) 한 번이고, 계좌·주문 계열에는 계좌 식별 헤더 X-Tossinvest-Account를 함께 보냅니다. 자동매매로 붙일 때 실제로 걸리는 것은 세 가지 — ① 허용 IP를 등록하지 않으면 403실시간 WebSocket 채널이 없어 폴링호출 한도가 API 그룹별 초당 1~10회로 쪼개져 있고 오전 9시대에는 더 낮아집니다.

국내 개인 자동매매는 오랫동안 한국투자증권 KIS API·키움 REST API·LS증권·대신 네 곳으로 굳어 있었습니다. 여기에 토스증권이 개인 개발자용 OpenAPI를 열면서 선택지가 하나 늘었습니다. 이 글은 마케팅 문구가 아니라 토스증권이 공개한 OpenAPI 3.0 명세서와 공식 개요 문서를 그대로 읽고, 봇을 붙일 때 실제로 필요한 것만 정리한 것입니다. (본문 스펙은 2026-08-04 확인 기준이며, 정책·한도는 변경될 수 있으니 최종 확인은 공식 문서에서 하세요.)

다른 증권사와 성격을 비교하려면 증권사 API 비교 2026을, 이미 KIS로 만들다 온 상태라면 KIS API 발급 30분 완성과 나란히 두고 보면 차이가 빨리 잡힙니다.

이 글에서 다루는 것

  1. 기존 증권사 API와 결정적으로 다른 4가지
  2. 발급 4단계 — 허용 IP를 빼먹으면 403
  3. 첫 호출 — 토큰만 되는 것과 계좌 헤더가 필요한 것
  4. 주문 만들기 — 필드 8개와 미국 주식 소수점·LOC
  5. 조건주문 SINGLE·OCO·OTO
  6. 호출 한도 — 그룹별 TPS와 9시대 함정
  7. 붙이기 전 체크리스트 7개

기존 증권사 API와 결정적으로 다른 4가지

KIS나 키움을 만져 본 사람이 토스증권 OpenAPI에서 가장 먼저 체감하는 차이는 "업무 코드가 없다"는 점입니다. KIS API는 같은 주소에 tr_id를 바꿔 끼우며 업무를 구분하고(TTTC0802U는 국내주식 현금 매수), 키움 OpenAPI+는 32bit OCX를 거쳐야 했습니다. 토스증권은 URL이 곧 기능인 평범한 REST API입니다.

항목토스증권 OpenAPI한국투자증권 KIS API키움 REST API
인증OAuth 2.0 Client Credentials
client_id+client_secret
appkey+appsecret으로
access_token 발급
앱키·시크릿으로 토큰 발급
업무 구분없음 — 경로가 곧 기능tr_id 헤더api-id 헤더
계좌 지정X-Tossinvest-Account 헤더바디의 CANO·ACNT_PRDT_CD바디 파라미터
실시간REST 전용(스트리밍 채널 없음)WebSocket 제공WebSocket 제공
IP 제한허용 IP 등록 필수(미등록 403)기본 미적용기본 미적용
조건주문API로 SINGLE·OCO·OTO봇이 직접 감시조건검색식 별도

실무적으로 가장 큰 갈림길은 실시간입니다. 공식 개요 문서는 "토스증권 Open API 는 현재 REST API 만 제공합니다"라고 못 박고 있습니다. 초 단위로 호가 변화에 반응해야 하는 전략이라면 폴링 간격이 곧 전략의 한계가 되므로, WebSocket 채널이 있는 KIS API·키움 REST API 쪽과 저울질해야 합니다. 반대로 하루 몇 번 규칙대로 사고파는 리밸런싱·분할매수형이라면 REST만으로 충분합니다.

발급 4단계 — 허용 IP를 빼먹으면 403

공용인증서 절차 없이 웹에서 끝납니다. 순서는 이렇습니다.

  1. 클라이언트 등록 — 토스증권 WTS(PC 웹) 로그인 → 설정 → Open API → client_id·client_secret 발급
  2. 허용 IP 등록 — 같은 메뉴 하단 허용 IP 관리에서 봇이 돌 서버의 공인 IP 등록
  3. 액세스 토큰 발급POST /oauth2/token
  4. 호출Authorization: Bearer (+ 계좌 계열은 X-Tossinvest-Account)

2번을 건너뛰면 코드가 아무리 맞아도 403입니다. 집 PC에서 테스트하다가 VPS로 옮기면 IP가 바뀌므로 또 막힙니다. 클라우드로 옮길 계획이라면 처음부터 고정 IP를 잡아 두세요.

WTS 설정 client_id / secret 허용 IP 등록 미등록 = 403 POST /oauth2/token grant_type=client_credentials access_token 시세 · 종목 · 환율 · 랭킹 Authorization: Bearer 만 /api/v1/prices · /orderbook /candles · /exchange-rate 계좌 · 자산 · 주문 · 조건주문 + X-Tossinvest-Account /api/v1/holdings · /orders /conditional-orders
토스증권 OpenAPI — 토큰만으로 되는 영역과 계좌 헤더가 필요한 영역

첫 호출 — 토큰만 되는 것과 계좌 헤더가 필요한 것

토큰 발급은 폼 인코딩입니다. JSON으로 보내면 막힙니다.

# 1) 액세스 토큰
curl -s -X POST 'https://openapi.tossinvest.com/oauth2/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=client_credentials' \
  -d 'client_id=xxx' -d 'client_secret=yyy'

# 응답
{"access_token":"eyJraWQiOiIyMDI2LTA0LTAxLWtleSI...",
 "token_type":"Bearer","expires_in":86400}

expires_in86400초(24시간)입니다. KIS와 마찬가지로 매 호출마다 토큰을 새로 받으면 AUTH 그룹 한도(초당 5회)에 금방 부딪히므로, 토큰은 캐시하고 만료 전에만 갱신하는 구조로 짜야 합니다.

import os, time, requests

BASE = "https://openapi.tossinvest.com"
_tok = {"v": None, "exp": 0}

def token():
    if _tok["v"] and time.time() < _tok["exp"] - 300:   # 5분 여유
        return _tok["v"]
    r = requests.post(f"{BASE}/oauth2/token",
        data={"grant_type": "client_credentials",
              "client_id": os.environ["TOSS_CLIENT_ID"],
              "client_secret": os.environ["TOSS_CLIENT_SECRET"]},
        timeout=5)
    r.raise_for_status()
    d = r.json()
    _tok["v"], _tok["exp"] = d["access_token"], time.time() + d["expires_in"]
    return _tok["v"]

def headers(account=None):
    h = {"Authorization": f"Bearer {token()}"}
    if account:                       # 계좌·자산·주문·조건주문 계열
        h["X-Tossinvest-Account"] = str(account)
    return h

# 시세 — 토큰만
requests.get(f"{BASE}/api/v1/prices", params={"symbols": "005930"},
             headers=headers(), timeout=5)

# 보유 주식 — 계좌 헤더 필요
requests.get(f"{BASE}/api/v1/holdings", headers=headers(1), timeout=5)

client_secret은 절대 코드에 박지 마세요. 환경변수나 시크릿 매니저로 빼고, 저장소에 올라가지 않게 .gitignore부터 확인하는 게 순서입니다 → API 키 보안과 계좌 보호.

응답은 성공이면 {"result": ...} 봉투로, 실패면 {"error": {...}} 봉투로 옵니다. 이 봉투 구조와 에러 코드별 대응은 토스증권 오픈API 에러코드 12가지에서 따로 다뤘습니다.

주문 만들기 — 필드 8개와 미국 주식 소수점·LOC

주문 생성은 POST /api/v1/orders 하나이고, 바디에 쓰는 필드는 실질적으로 8개입니다.

필드메모
symbolKRX 6자리 숫자 / US 티커005930, AAPL
sideBUY · SELL소문자로 보내면 invalid-request
orderTypeLIMIT · MARKET지정가 / 시장가
timeInForceDAY · CLSLIMIT+CLS = 종가 지정가(LOC)
quantity수량 문자열미국 주식은 "0.5" 같은 소수점 가능
orderAmount금액 문자열quantity택일. 미국 정규장만
price지정가MARKET이면 생략
clientOrderId최대 36자멱등키. ^[a-zA-Z0-9\-_]+$, 10분 유효
// 국내주식 지정가 매수
{"clientOrderId":"my-order-001","symbol":"005930",
 "side":"BUY","orderType":"LIMIT","quantity":"10","price":"70000"}

// 미국주식 금액 기준 시장가 매수 (정규장만)
{"symbol":"AAPL","side":"BUY","orderType":"MARKET","orderAmount":"100.5"}

// 미국주식 소수점 시장가 매도
{"symbol":"AAPL","side":"SELL","orderType":"MARKET","quantity":"0.5"}

// 미국주식 종가 지정가 = LIMIT + CLS
{"symbol":"AAPL","side":"BUY","orderType":"LIMIT",
 "timeInForce":"CLS","quantity":"10","price":"185.5"}

자동매매 관점에서 진짜 중요한 필드는 clientOrderId입니다. 이 값을 넣어 두면 같은 값으로 재요청했을 때 이전 주문 결과를 그대로 돌려줍니다. 타임아웃이 났는데 주문이 들어갔는지 알 수 없는 상황 — 봇이 중복 주문을 내는 가장 흔한 사고 — 를 이 한 필드가 막습니다. 서버가 자동 생성해 주지 않으므로 봇이 직접 만들어 넣어야 하고, 유효 기간은 10분입니다.

주문 금액이 1억원 이상이면 confirmHighValueOrder: true가 없을 때 거부됩니다(confirm-high-value-required). 오타로 수량에 0이 하나 더 붙는 사고를 막아 주는 장치이니, 봇에서는 이 플래그를 기본 false로 두고 예외 경로에서만 켜세요. 킬 스위치·상한 설계는 킬 스위치와 서킷브레이커 참고.

조건주문 SINGLE · OCO · OTO

토스증권 OpenAPI에서 눈여겨볼 부분입니다. 보통 손절·익절은 봇이 시세를 계속 보다가 조건이 맞으면 주문을 던지는데, 여기서는 조건 자체를 서버에 등록할 수 있습니다. 봇이 죽어 있어도 감시는 살아 있다는 뜻이라, REST 전용이라는 약점을 일부 상쇄합니다.

// OCO — 익절 305, 손절 295 동시 대기 (first 감시가 > 현재가 > second 감시가)
POST /api/v1/conditional-orders
{"symbol":"005930","type":"OCO","quantity":"100","orderType":"LIMIT",
 "clientOrderId":"my-order-003","expireDate":"2026-09-10",
 "first": {"orderSide":"SELL","triggerPrice":"305","orderPrice":"305"},
 "second":{"orderSide":"SELL","triggerPrice":"295","orderPrice":"294.5"}}

// OTO — 290에 사고, 체결되면 320 매도 예약
{"symbol":"005930","type":"OTO","quantity":"100","orderType":"LIMIT",
 "clientOrderId":"my-order-004","expireDate":"2026-09-10",
 "first": {"orderSide":"BUY","triggerPrice":"290","orderPrice":"290"},
 "second":{"orderSide":"SELL","triggerPrice":"320","orderPrice":"320"}}

제약이 하나 있습니다. OCO와 OTO는 종목당 1개입니다(둘째를 등록하면 duplicate-conditional-order). SINGLE은 개수 제한이 없습니다. 그리고 이미 조건을 충족한 가격으로 등록하면 condition-already-met으로 거부되므로, 등록 직전에 현재가를 한 번 읽고 넣는 편이 안전합니다. 익절·손절 폭 자체를 어떻게 잡을지는 전략 설계의 문제라 API와는 별개입니다.

호출 한도 — 그룹별 TPS와 9시대 함정

한도가 계정 전체 하나로 묶여 있지 않고 클라이언트 × API 그룹으로 쪼개져 있습니다. 시세를 아무리 많이 읽어도 주문 한도를 갉아먹지 않는다는 뜻이라 설계가 편합니다. 공식 문서에 표기된 값은 이렇습니다(2026-08-04 확인, 사전 공지 없이 조정될 수 있음).

그룹초당 한도비고
MARKET_DATA10회현재가·호가·체결·상하한가
ORDER10회생성·정정·취소
ORDER_INFO6회09:00~09:10 KST에는 3회
ORDER_HISTORY5회주문 조회
AUTH5회토큰 발급
ASSET · STOCK5회보유 주식 · 종목 정보
MARKET_INFO3회환율·장 운영 시간
ACCOUNT1회계좌 목록 — 가장 빡빡함

함정이 둘 있습니다. 첫째, ACCOUNT가 초당 1회입니다. 계좌 목록은 시작할 때 한 번 읽고 캐시해야지, 루프 안에서 부르면 바로 막힙니다. 둘째, ORDER_INFO가 장 시작 10분간 절반으로 줄어듭니다. 매수 가능 금액을 매 주문마다 확인하는 구조라면 하필 가장 바쁜 시간에 429를 맞습니다.

// 429 응답 — 헤더를 보고 판단한다
X-RateLimit-Limit: 6
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1
Retry-After: 1

{"error":{"requestId":"01HXYZABCDEFG123456789",
  "code":"rate-limit-exceeded","message":"요청이 너무 많습니다."}}

권장 대응도 문서에 적혀 있습니다 — Retry-After만큼 대기 후 재시도, 지수 백오프(1s → 2s → 4s)에 지터를 섞을 것, X-RateLimit-Remaining이 줄어들면 선제적으로 속도를 늦출 것. 전략을 여러 개 돌리면 호출량이 합산된다는 점까지 포함한 설계는 API 호출 제한 설계에 정리해 두었습니다. KIS의 EGW00201(초당 거래건수 초과)과 원인은 같고 이름만 다릅니다.

🛠️
토스증권 계좌로 자동매매를 붙이려는데 코드가 막막하다면

알고랩은 토큰 캐시·허용 IP·멱등키·백오프처럼 "봇이 죽지 않게 하는 배선"부터 잡고 전략을 얹습니다. 쓰던 증권사에서 옮겨 오는 경우도 그대로 가져오시면 됩니다.

상담 시작하기 →

붙이기 전 체크리스트 7개

  1. 봇이 돌 서버의 공인 IP를 허용 IP에 등록했는가 (VPS 이전 시 재등록)
  2. access_token캐시하고 만료 5분 전에만 갱신하는가
  3. 계좌 목록(ACCOUNT, 초당 1회)을 기동 시 1회만 읽는가
  4. 모든 주문에 clientOrderId 멱등키가 붙는가
  5. 429를 받았을 때 Retry-After + 지수 백오프로 재시도하는가
  6. 실시간이 없다는 전제로 폴링 주기가 전략과 맞는가
  7. 실패 응답의 coderequestId로그에 그대로 남는가 (CS 문의 시 requestId 첨부 권장)

모의투자 환경이 따로 보이지 않습니다. 2026-08-04 확인 기준 공식 문서의 서버 목록에는 openapi.tossinvest.com 한 곳만 있습니다. KIS처럼 모의→실전 전환으로 안전망을 두던 방식이 그대로 통하지 않으므로, 첫 주문은 최소 수량 왕복으로 확인하고 금액 상한을 먼저 거세요. 모의 환경 제공 여부는 정책에 따라 달라질 수 있으니 공식 안내를 확인하시기 바랍니다.

자주 묻는 질문

토스증권 OpenAPI 문서는 어디서 보나요?

개발자 포털의 인터랙티브 레퍼런스와 함께, 기계가 읽는 형식이 같이 공개돼 있는 것이 특징입니다. 사람이 읽는 개요 마크다운, LLM용 API 레퍼런스 마크다운, 그리고 OpenAPI 3.0 JSON 명세 세 가지가 있고, 문서 스스로 JSON을 최종 기준(source of truth)이라고 밝히고 있습니다. 스펙이 바뀌었는지 확인할 때는 이 JSON을 받아 비교하는 것이 가장 정확합니다.

KIS나 키움에서 만든 봇을 그대로 옮길 수 있나요?

전략 로직은 그대로 쓰지만 통신 계층은 새로 짜야 합니다. tr_id·appkey·custtype 같은 KIS 고유 헤더가 사라지고, 계좌 지정이 바디에서 X-Tossinvest-Account 헤더로 올라오며, 실시간 WebSocket 콜백이 폴링 루프로 바뀝니다. 증권사마다 통신 규격이 다르다는 점은 키움 OpenAPI+와 KIS API 사이에서도 똑같이 겪는 문제입니다.

API 이용료가 있나요?

공식 OpenAPI 명세에는 요금 항목이 없고, 대신 GET /api/v1/commissions매매 수수료를 시장별(KR·US)로 조회하는 엔드포인트가 있습니다. API 이용료·데이터 이용료 정책은 증권사마다 다르고 수시로 바뀌므로 숫자를 단정하지 않겠습니다 — 토스증권 공식 고지에서 확인하세요.

자동매매를 하면 수익이 나나요?

API가 열렸다는 것은 주문을 코드로 낼 수 있다는 뜻이지 수익과는 다른 이야기입니다. 과거 성과나 백테스트 결과가 미래 수익을 보장하지 않으며, 이 글의 어떤 내용도 특정 종목·방향에 대한 투자 권유가 아닙니다. API는 실행을 자동화할 뿐, 전략의 유효성은 별도로 검증해야 합니다.

토스증권 자동매매 봇 맞춤 제작

토큰 캐시·허용 IP·멱등키·조건주문 연동·429 백오프까지 — 알고랩이 통합 패키지로 제작합니다.
24시간 빠른 답변 가능합니다.

무료 상담 시작하기