# BTX External API REST: https://api.btxpro.co.kr WebSocket: wss://api-ws.btxpro.co.kr OpenAPI: /api-docs/openapi.json # BTX 외부 API BTX 외부 API로 공개 시세와 Feed를 조회하고, API 키를 사용해 계정·잔고·주문·체결을 연동할 수 있습니다. REST와 WebSocket은 아래의 서로 다른 운영 도메인을 사용합니다.
REST API

https://api.btxpro.co.kr

조회, 주문 생성, 취소, 체결 이력

WebSocket API

wss://api-ws.btxpro.co.kr

실시간 시세, 개인 이벤트, 주문 명령

| 용도 | 운영 주소 | 인증 | | --- | --- | --- | | REST | `https://api.btxpro.co.kr/v1/...` | 공개 API 또는 HMAC 서명 | | 공개 시세 WS | `wss://api-ws.btxpro.co.kr/v1/market/stream` | 불필요 | | 개인 이벤트·주문 WS | `wss://api-ws.btxpro.co.kr/v1/user/stream` | 연결 시 read, 주문 명령은 trade 추가 | 공개·개인 WS 모두 `api-ws.btxpro.co.kr`의 위 경로를 사용합니다. 고객 웹 화면의 로그인 세션과 외부 API 키는 별개입니다. ## 시작하기 1. [빠른 시작](/api-docs/guide/quickstart.md)에서 공개 시세와 계정 정보를 조회합니다. 2. [인증](/api-docs/guide/authentication.md)에서 API 키 권한과 HMAC 서명 규칙을 확인합니다. 3. [REST 전체 목록](/api-docs/generated/rest.md) 또는 [API 레퍼런스](/api-docs/reference.md)에서 요청·응답 필드를 확인합니다. 4. [WebSocket 가이드](/api-docs/websocket/overview.md)에서 실시간 연결과 재연결 절차를 구현합니다. ## 현재 지원 범위 | 기능 | 지원 내용 | | --- | --- | | 공개 정보 | 통화, 마켓, 시세, 호가, 체결, 캔들, Feed | | 계정 | API 키 권한, 지갑, 잔고 | | 주문 | 지정가 `limit`, `GTC`, 매수·매도, 단건·일괄 취소 | | 실시간 시세 | `ticker` 구독·해제, 전체 마켓 구독 | | 개인 실시간 | 초기 스냅샷, 주문·체결·잔고 이벤트, 주문 생성·취소 | 시장가, IOC/FOK, post-only, quote 수량 주문과 원자적 주문 정정은 현재 지원하지 않습니다. WS `order.amend`는 `AMEND_NOT_SUPPORTED`를 반환합니다. 주문용 고객 ID와 멱등성 키는 제공하지 않습니다. 타임아웃 또는 연결 종료로 결과를 받지 못한 주문은 [복구 절차](/api-docs/websocket/recovery.md)에 따라 상태를 확인한 뒤 처리하세요. ## 명세 다운로드 - [OpenAPI 3.1 JSON](/api-docs/openapi.json) - [요청·응답 모델](/api-docs/generated/schemas.md) - [WebSocket 메시지 모델](/api-docs/generated/websocket.md) - [문서 인덱스 llms.txt](/api-docs/llms.txt) - [전체 문서 텍스트](/api-docs/llms-full.txt) 운영 도메인은 API 연동에 사용할 기준 주소입니다. 문서의 주소 표기가 DNS·TLS·로드밸런서의 배포 완료를 의미하지는 않습니다. --- # 빠른 시작 먼저 키 없이 공개 API를 호출한 뒤, API 키로 계정과 잔고를 확인합니다. 모든 예제의 마켓·지갑·주문 ID는 설명용 값이며 실제 조회 결과로 바꿔 사용하세요. ## 1. 서버 시간과 마켓 확인 ```sh curl 'https://api.btxpro.co.kr/v1/time' curl 'https://api.btxpro.co.kr/v1/markets' curl 'https://api.btxpro.co.kr/v1/market/ticker?symbol=BTC-USDT' ``` 성공 응답은 `data`, `requestId`, `serverTime`으로 구성됩니다. `/health`는 예외로 본문 없는 HTTP 200을 반환합니다. ## 2. API 키 발급 BTX 웹의 **마이페이지 → API**(`/my-page/api`)에서 발급합니다. OTP 활성화와 발급 시 OTP 확인이 필요합니다. - 잔고·주문 조회와 개인 WS: `read` - 주문 생성·취소: `trade` 추가 - 공개 시세·Feed와 공개 WS: API 키 불필요 Secret Key는 발급 결과에 한 번만 표시됩니다. 서버의 비밀 관리 도구에 저장하고, 브라우저 프런트엔드에 넣지 마세요. 키는 계정에서 볼 수 있는 전체 지갑에 적용되며 지갑별 제한은 제공하지 않습니다. ## 3. 서명된 조회 실행 키를 비밀 관리 도구 또는 현재 프로세스 환경에 주입한 상태에서 실행합니다. 문서 예제는 주문을 생성하지 않고 `GET /v1/account`만 호출합니다. ```sh node signed-request.mjs python signed_request.py ``` [예제 다운로드와 실행 방법](/api-docs/guide/examples.md)을 확인하세요. 자체 클라이언트를 만들 경우 [HMAC 인증 규칙](/api-docs/guide/authentication.md)을 따라야 합니다. 저장소에서 기존 Go 예제 클라이언트를 사용하는 경우 `backend-base`에서: ```sh go run ./cmd/etc/externalapiclient -base-url https://api.btxpro.co.kr -command verify-key go run ./cmd/etc/externalapiclient -base-url https://api.btxpro.co.kr -command wallets ``` `verify-key`는 계정·지갑·개인 스트림의 초기 스냅샷을 확인한 뒤 종료합니다. 주문을 전송하지 않습니다. ## 4. 공개 WebSocket 구독 키가 필요 없는 공개 연결은 브라우저에서도 사용할 수 있습니다. ```js const socket = new WebSocket('wss://api-ws.btxpro.co.kr/v1/market/stream') socket.onopen = () => socket.send(JSON.stringify({ id: 'sub-1', op: 'subscribe', args: [{ channel: 'ticker', symbol: 'BTC-USDT' }], })) socket.onmessage = ({ data }) => console.log(JSON.parse(data)) ``` `subscribed` 응답 다음에 현재 캐시된 시세와 실시간 이벤트가 전달됩니다. 개인 WS는 연결 요청에 인증 헤더가 필요하므로 서버용 WS 클라이언트를 사용합니다. --- # API 키와 HMAC 인증 개인 REST API와 개인 WS 연결은 동일한 HMAC-SHA256 인증을 사용합니다. 키는 BTX 웹의 마이페이지 API 메뉴에서 생성·폐기합니다. `GET /v1/account`로 현재 키의 권한을 확인할 수 있습니다. ## 허용 IP와 인증 캐시 키를 만들 때 개별 IPv4·IPv6 주소를 **최대 5개** 등록할 수 있습니다. 한 줄에 하나씩 입력합니다. 비워 두면 모든 IP에서 사용할 수 있고, 하나라도 등록하면 목록에 있는 IP에서만 REST 요청과 개인 WS 연결을 사용할 수 있습니다. CIDR 대역·도메인·포트는 지원하지 않으며, IPv4-mapped IPv6는 IPv4로 정규화합니다. 거절 시 HTTP 403 `IP_NOT_ALLOWED`를 반환하며 위반 점수는 추가하지 않습니다. 목록을 변경하려면 기존 키를 폐기하고 새 키를 발급합니다. 키 상태와 권한·IP 정책은 게이트웨이의 메모리 캐시를 공유합니다. 캐시를 사용하는 요청마다 보관 시간을 **5분** 연장하며, 사용하지 않은 채 5분이 지나면 제거합니다. 보관 시간과 별도로 **30초마다 캐시에 남은 키만 일괄 조회**해 권한·IP 제한·비활성화·삭제를 반영합니다. 폴링 자체는 보관 시간을 연장하지 않습니다. 키 변경 시 같은 프로세스의 해당 키를 무효화하고, 다른 프로세스에는 NATS 변경 신호를 전달해 바로 갱신하도록 합니다. 신호 누락은 주기적인 폴링이 보완합니다. 갱신이 실패하면 해당 캐시를 비웁니다. 요청이 계속 들어와도 마지막 DB 검증 이후 60초가 지난 정보는 그대로 사용하지 않으며, 원본 DB 확인도 실패하면 인증을 거절합니다. ## 인증 헤더 | 헤더 | 필수 | 값 | | --- | --- | --- | | `BTX-API-KEY` | 예 | Public Key | | `BTX-TIMESTAMP` | 예 | 현재 Unix 밀리초의 양의 정수 | | `BTX-SIGNATURE` | 예 | 서명의 소문자 16진수 문자열 | | `BTX-RECV-WINDOW` | 권장 | 허용 시간 차이(ms), 기본 5000, 최대 60000 | | `BTX-NONCE` | 아니요 | 폐기 예정 레거시 메타데이터. 새 클라이언트에서는 생략 | 서버 시간과 요청 timestamp의 절대 차이가 수신 시간 범위 안이어야 합니다. 호스트 시간을 동기화하고 `GET /v1/time`으로 시간 차이를 확인하세요. 헤더를 생략해도 서명에는 기본 receive window인 `5000`이 들어갑니다. ## 서명할 문자열 다음 **7개 항목을 줄바꿈 `\n`으로 연결한 UTF-8 바이트**를 서명합니다. ```text UPPERCASE_HTTP_METHOD ESCAPED_PATH SORTED_URL_ENCODED_QUERY LOWERCASE_SHA256_HEX_OF_EXACT_BODY_BYTES BTX-TIMESTAMP BTX-RECV-WINDOW BTX-NONCE_OR_EMPTY ``` ```text signature = lowercase_hex(HMAC_SHA256(secretKey, canonical)) ``` - 메서드는 `GET`, `POST`, `DELETE`처럼 대문자로 씁니다. - 경로는 `/v1/account`처럼 `/v1`을 포함합니다. 별도의 프록시 경로 접두사가 있으면 포함하고, percent-escape된 경로를 그대로 서명합니다. 호스트는 서명에 포함하지 않습니다. - 쿼리는 Go `url.Values.Encode` 규칙입니다. 키를 정렬하고 공백은 `+`, 값의 `/`는 `%2F`로 인코딩합니다. 반복 값의 순서는 유지됩니다. 실제 API 쿼리는 중복 키와 빈 값을 거절합니다. - 본문은 **실제 전송하는 바이트 그대로** SHA-256 해시합니다. JSON을 다시 직렬화하면 바이트가 달라질 수 있습니다. - 빈 본문 해시는 `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`입니다. - 새 클라이언트는 nonce를 생략하고 **7번째 항목을 빈 문자열**로 둡니다. 따라서 최종 바이트는 receive window 뒤의 `\n`으로 끝납니다. 그 뒤에 줄바꿈을 더 붙이지 마세요. ## 검증용 고정 벡터 아래 Secret은 테스트용 공개 문자열입니다. timestamp도 고정된 과거 값이므로 운영 API를 호출하는 용도가 아닙니다. ```text secretKey: secret method: POST path: /v1/orders query: (empty) timestamp: 1783420800000 recvWindow: 5000 nonce: (empty) body: {"symbol":"BTC-USDT","walletId":21,"side":"buy","type":"limit","timeInForce":"GTC","quantity":"0.100000000","price":"65000.000000000"} bodySha256: f2f86635e268cfe58437fc6dc62a7e109e2b62337b41fbfd8caa66c92311c284 signature: ec5dcede7caa7214fca3f4f632cea4219a9b5c5e053ea088169bb0bed8e846e0 ``` [Node.js·Python 예제](/api-docs/guide/examples.md)는 이 벡터를 검증하는 `--self-test` 옵션을 제공합니다. ## 개인 WebSocket 인증 {#websocket-authentication} 다음 GET 업그레이드 요청에 같은 규칙으로 서명합니다. ```text GET wss://api-ws.btxpro.co.kr/v1/user/stream 서명 경로: /v1/user/stream 쿼리: 빈 문자열 본문: 빈 바이트 ``` 인증 헤더를 HTTP 업그레이드 요청에 보내야 합니다. 연결 뒤 인증 메시지를 보내는 방식이 아닙니다. 브라우저 표준 `WebSocket` 생성자는 임의 인증 헤더를 설정하지 못하므로 Go SDK 또는 서버용 WS 라이브러리를 사용합니다. 연결 시 `read`, 주문 명령 시 `trade`를 확인합니다. 서버는 주문 명령마다 키를 재검증하고, 유휴 연결도 60초마다 `read` 권한을 재검증합니다. ## 키 교체와 요청 중복 새 키 발급 → 서명된 조회와 개인 스트림 확인 → 클라이언트 교체 → 기존 키 폐기 순서로 교체합니다. timestamp는 요청이 최근 생성됐는지 확인합니다. 요청을 유일하게 만들지는 않습니다. 같은 유효 요청을 다시 보내면 주문이 중복 실행될 수 있습니다. nonce나 WS 명령 `id`도 완료 후 재시도를 막는 멱등성 키가 아닙니다. --- # 응답과 공통 규칙 ## 주소와 경로 REST는 `https://api.btxpro.co.kr`, WS는 `wss://api-ws.btxpro.co.kr`입니다. 대부분의 REST 경로는 `/v1`으로 시작하며 `/health`, `/ready`만 예외입니다. WS 연결 경로는 `/v1/market/stream`, `/v1/user/stream`입니다. ## REST 응답 {#rest-responses} 일반적인 성공 응답: ```json { "data": {}, "requestId": "req_1783420800123456789", "serverTime": 1783420800123 } ``` 오류 응답: ```json { "error": { "code": "INVALID_REQUEST", "message": "Request is invalid." }, "requestId": "req_1783420800123456789", "serverTime": 1783420800123 } ``` `GET /health`는 본문 없는 HTTP 200, WS 업그레이드는 HTTP 101이므로 이 JSON envelope를 사용하지 않습니다. JSON 응답에는 `Cache-Control: no-store`가 설정됩니다. ## 요청 추적 `X-Request-Id`가 응답 헤더와 JSON의 `requestId`에 포함됩니다. 클라이언트가 이 헤더를 지정할 경우 80자 이내의 영문·숫자·`-_.:`로 구성합니다. 장애 문의나 로그 연계에 사용하며, 주문의 중복 처리를 방지하는 값은 아닙니다. ## 숫자와 시각 - 가격·수량·금액·수수료·잔고는 십진수 **문자열**입니다. 부동소수점 변환 대신 decimal 연산을 사용합니다. - `orderId`와 같은 문자열 ID는 숫자로 변환하지 않고 보존합니다. - `serverTime`, 주문 조회의 `startTime`·`endTime`은 Unix 밀리초입니다. - Feed의 `publishedMicrotime`·`creationMicrotime`·`updateMicrotime` 및 WS 체결의 `microtime`은 Unix 마이크로초입니다. 개별 모델의 필드명을 확인하세요. - 마켓 식별자는 `BTC-USDT`와 같은 `symbol`입니다. 현재 지원 여부와 통화 ID는 마켓 목록에서 확인합니다. ## 쿼리와 목록 쿼리 키는 한 번만 보내고 빈 값을 보내지 마세요. 정확한 기본값·범위는 [전체 엔드포인트](/api-docs/generated/rest.md)에 표시됩니다. 거래 목록의 `limit` 최대값은 1000입니다. 주문·체결 이력은 기본적으로 요청 시점까지 최근 30일을 조회하며 `startTime`, `endTime`으로 범위를 지정할 수 있습니다. `hasMore`가 있는 응답은 추가 데이터가 있을 수 있음을 표시합니다. 거래 이력 API는 Feed의 `cursor` 페이지네이션을 제공하지 않습니다. Feed 일반 목록은 기본 20개, 최대 100개이며 `hasMore`와 `nextCursor`를 제공합니다. 다음 페이지에는 이전 응답의 `nextCursor`를 `cursor`로 전달합니다. cursor는 정렬 방식에 연결되므로 정렬을 바꾸면 초기화합니다. `q` 검색은 `sort`·`cursor`와 함께 사용할 수 없으며 결과 개수는 limit으로 제한됩니다. ## 권한 | 작업 | 권한 | | --- | --- | | 공개 REST·공개 WS | 없음 | | `GET /v1/account` | 유효한 서명된 키 | | 지갑·잔고·주문·체결 조회 | read | | 주문 생성·취소 | trade | | 개인 WS 연결 | read | | 개인 WS 주문 명령 | read로 연결한 뒤 trade 추가 확인 | 현재 키의 접근 범위는 계정에서 볼 수 있는 전체 지갑입니다. 외부 API에는 지갑별 키 범위 설정이 없습니다. --- # REST API 전체 엔드포인트 기본 주소는 `https://api.btxpro.co.kr`입니다. 현재 HTTP API **25개 작업**을 제공합니다. 경로에 표시된 `/v1`을 포함해 요청하세요. `/health`와 `/ready`는 버전 경로 밖에 있습니다. [API 레퍼런스](/api-docs/reference.md)에서 전체 요청·응답 모델을 볼 수 있습니다. [WebSocket 연결과 메시지](/api-docs/websocket/overview.md)는 별도 가이드를 확인하세요. ## 시스템 | 메서드 | 경로 | 인증 | 설명 | | --- | --- | --- | --- | | GET | [`/health`](#health) | 공개 | 서비스 상태 | | GET | [`/ready`](#readiness) | 공개 | 서비스 준비 상태 | | GET | [`/v1/time`](#gettime) | 공개 | 서버 시간 | ### 서비스 상태 {#health} `GET https://api.btxpro.co.kr/health` 인증: **공개** 파라미터가 없습니다. | HTTP | 응답 | | --- | --- | | 200 | Service is alive | ### 서비스 준비 상태 {#readiness} `GET https://api.btxpro.co.kr/ready` 인증: **공개** Checks database access plus the Core and engine connector wiring required by the external trading API. 파라미터가 없습니다. | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | | 503 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | ### 서버 시간 {#gettime} `GET https://api.btxpro.co.kr/v1/time` 인증: **공개** 파라미터가 없습니다. | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | ## 공개 시세 | 메서드 | 경로 | 인증 | 설명 | | --- | --- | --- | --- | | GET | [`/v1/currencies`](#listcurrencies) | 공개 | 통화 목록 | | GET | [`/v1/markets`](#listmarkets) | 공개 | 마켓 목록 | | GET | [`/v1/markets/{symbol}`](#getmarket) | 공개 | 마켓 상세 | | GET | [`/v1/market/ticker`](#getticker) | 공개 | 현재 시세 | | GET | [`/v1/market/orderbook`](#getorderbook) | 공개 | 호가 | | GET | [`/v1/market/trades`](#gettrades) | 공개 | 최근 체결 | | GET | [`/v1/market/candles`](#getcandles) | 공개 | 캔들 | ### 통화 목록 {#listcurrencies} `GET https://api.btxpro.co.kr/v1/currencies` 인증: **공개** 파라미터가 없습니다. | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | ### 마켓 목록 {#listmarkets} `GET https://api.btxpro.co.kr/v1/markets` 인증: **공개** 파라미터가 없습니다. | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | ### 마켓 상세 {#getmarket} `GET https://api.btxpro.co.kr/v1/markets/{symbol}` 인증: **공개** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `symbol` | path | 예 | string | | | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | ### 현재 시세 {#getticker} `GET https://api.btxpro.co.kr/v1/market/ticker` 인증: **공개** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `symbol` | query | 아니요 | string | | | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | ### 호가 {#getorderbook} `GET https://api.btxpro.co.kr/v1/market/orderbook` 인증: **공개** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `symbol` | query | 예 | string | | | `tick` | query | 아니요 | integer | default: 0; minimum: 0; maximum: 4 | | `limit` | query | 아니요 | integer | default: 100; minimum: 1; maximum: 1000 | | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | ### 최근 체결 {#gettrades} `GET https://api.btxpro.co.kr/v1/market/trades` 인증: **공개** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `symbol` | query | 예 | string | | | `limit` | query | 아니요 | integer | default: 100; minimum: 1; maximum: 1000 | | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | ### 캔들 {#getcandles} `GET https://api.btxpro.co.kr/v1/market/candles` 인증: **공개** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `symbol` | query | 예 | string | | | `interval` | query | 아니요 | string | 허용값: "1m", "5m", "10m", "15m", "30m", "1h", "4h", "1d", "1w"; default: "1h" | | `limit` | query | 아니요 | integer | default: 500; minimum: 1; maximum: 1000 | | `startTime` | query | 아니요 | integer | minimum: 0; format: "int64" | | `endTime` | query | 아니요 | integer | minimum: 1; format: "int64" | | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | ## Feed | 메서드 | 경로 | 인증 | 설명 | | --- | --- | --- | --- | | GET | [`/v1/feed/home`](#getfeedhome) | 공개 | Feed 홈 | | GET | [`/v1/feed/categories`](#listfeedcategories) | 공개 | Feed 카테고리 목록 | | GET | [`/v1/feed/articles`](#listfeedarticles) | 공개 | Feed 글 목록과 검색 | | GET | [`/v1/feed/articles/{feedArticleId}`](#getfeedarticle) | 공개 | Feed 글 상세 | | POST | [`/v1/feed/articles/{feedArticleId}/view`](#incrementfeedarticleview) | 공개 | Feed 조회수 증가 | ### Feed 홈 {#getfeedhome} `GET https://api.btxpro.co.kr/v1/feed/home` 인증: **공개** 파라미터가 없습니다. | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | | 500 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | | 503 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | ### Feed 카테고리 목록 {#listfeedcategories} `GET https://api.btxpro.co.kr/v1/feed/categories` 인증: **공개** 파라미터가 없습니다. | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | | 500 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | | 503 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | ### Feed 글 목록과 검색 {#listfeedarticles} `GET https://api.btxpro.co.kr/v1/feed/articles` 인증: **공개** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `categoryId` | query | 아니요 | string | pattern: "^[1-9][0-9]*$" | | `authorName` | query | 아니요 | string | minLength: 1; maxLength: 80 | | `q` | query | 아니요 | string | Search title, summary, and Markdown body. Whitespace is normalized and each term is matched as a substring; an article must contain every term. Terms shorter than 2 characters and boolean operator characters (+-><()~*"@) are ignored, and a query left with no searchable term is rejected. Search results are globally limited and ordered by title match, summary-only match, then body-only match; sort and cursor cannot be combined with q. minLength: 2; maxLength: 80 | | `sort` | query | 아니요 | string | Cannot be combined with q. 허용값: "latest", "popular"; default: "latest" | | `limit` | query | 아니요 | integer | default: 20; minimum: 1; maximum: 100 | | `cursor` | query | 아니요 | string | Opaque keyset cursor returned as nextCursor. A cursor is bound to its latest or popular sort and cannot be combined with q. minLength: 1; maxLength: 512 | | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | | 400 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | | 500 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | | 503 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | ### Feed 글 상세 {#getfeedarticle} `GET https://api.btxpro.co.kr/v1/feed/articles/{feedArticleId}` 인증: **공개** The response supplies canonicalKey and canonicalPath. The slug is presentation metadata and is not used for database lookup. | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `feedArticleId` | path | 예 | string | pattern: "^[1-9][0-9]*$" | | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | | 400 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | | 404 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | | 500 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | | 503 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | ### Feed 조회수 증가 {#incrementfeedarticleview} `POST https://api.btxpro.co.kr/v1/feed/articles/{feedArticleId}/view` 인증: **공개** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `feedArticleId` | path | 예 | string | pattern: "^[1-9][0-9]*$" | | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | | 400 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | | 404 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | | 500 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | | 503 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | ## 계정과 지갑 | 메서드 | 경로 | 인증 | 설명 | | --- | --- | --- | --- | | GET | [`/v1/account`](#getaccount) | 서명된 키 | 계정과 API 키 권한 | | GET | [`/v1/wallets`](#listwallets) | 서명 + read | 지갑 목록 | | GET | [`/v1/balances`](#listbalances) | 서명 + read | 잔고 목록 | ### 계정과 API 키 권한 {#getaccount} `GET https://api.btxpro.co.kr/v1/account` 인증: **서명된 키** 파라미터가 없습니다. | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | ### 지갑 목록 {#listwallets} `GET https://api.btxpro.co.kr/v1/wallets` 인증: **서명 + read** 파라미터가 없습니다. | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | ### 잔고 목록 {#listbalances} `GET https://api.btxpro.co.kr/v1/balances` 인증: **서명 + read** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `walletId` | query | 아니요 | integer | minimum: 1; maximum: 255 | | `currency` | query | 아니요 | string | | | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | ## 주문과 체결 | 메서드 | 경로 | 인증 | 설명 | | --- | --- | --- | --- | | POST | [`/v1/orders`](#createorder) | 서명 + trade | 지정가 주문 생성 | | DELETE | [`/v1/orders`](#cancelorders) | 서명 + trade | 지갑의 주문 일괄 취소 | | GET | [`/v1/orders/open`](#listopenorders) | 서명 + read | 미체결 주문 목록 | | GET | [`/v1/orders/history`](#listorderhistory) | 서명 + read | 주문 이력 | | GET | [`/v1/orders/{orderId}`](#getorder) | 서명 + read | 주문 상세 | | DELETE | [`/v1/orders/{orderId}`](#cancelorder) | 서명 + trade | 주문 취소 | | GET | [`/v1/fills`](#listfills) | 서명 + read | 체결 이력 | ### 지정가 주문 생성 {#createorder} `POST https://api.btxpro.co.kr/v1/orders` 인증: **서명 + trade** The gateway correlates the engine result through a shared in-memory dispatcher and waits up to 10 seconds for this REST request. Market orders, post-only, quote quantity, and non-GTC time-in-force values are reserved for future support. 파라미터가 없습니다. 요청 본문: [CreateOrderRequest](/api-docs/generated/schemas.md#schema-createorderrequest) | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `symbol` | 예 | string | | | `walletId` | 예 | integer | Required account-local visible spot-trading wallet ID from GET /v1/wallets; not a blockchain address or walletNumber. The server never chooses a default wallet. minimum: 21; maximum: 39 | | `side` | 예 | string | 허용값: "buy", "sell" | | `type` | 예 | string | 허용값: "limit" | | `timeInForce` | 아니요 | string | 허용값: "GTC"; default: "GTC" | | `quantity` | 예 | string | | | `quoteQuantity` | 아니요 | string | Reserved for future support. | | `price` | 예 | string | | | `postOnly` | 아니요 | boolean | Reserved for future support. | | HTTP | 응답 | | --- | --- | | 200 | [OrderEnvelope](/api-docs/generated/schemas.md#schema-orderenvelope) | | 422 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | | 504 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | ### 지갑의 주문 일괄 취소 {#cancelorders} `DELETE https://api.btxpro.co.kr/v1/orders` 인증: **서명 + trade** Matching cancels run with up to 16 concurrent engine commands, preserve selection order in the response, and share one 10-second deadline. | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `walletId` | query | 예 | integer | minimum: 1; maximum: 255 | | `symbol` | query | 아니요 | string | | | `limit` | query | 아니요 | integer | default: 100; minimum: 1; maximum: 1000 | | HTTP | 응답 | | --- | --- | | 200 | [CancelOrderListEnvelope](/api-docs/generated/schemas.md#schema-cancelorderlistenvelope) | | 504 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | ### 미체결 주문 목록 {#listopenorders} `GET https://api.btxpro.co.kr/v1/orders/open` 인증: **서명 + read** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `walletId` | query | 아니요 | integer | minimum: 1; maximum: 255 | | `symbol` | query | 아니요 | string | | | `limit` | query | 아니요 | integer | default: 100; minimum: 1; maximum: 1000 | | HTTP | 응답 | | --- | --- | | 200 | [OrderListEnvelope](/api-docs/generated/schemas.md#schema-orderlistenvelope) | ### 주문 이력 {#listorderhistory} `GET https://api.btxpro.co.kr/v1/orders/history` 인증: **서명 + read** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `walletId` | query | 아니요 | integer | minimum: 1; maximum: 255 | | `symbol` | query | 아니요 | string | | | `limit` | query | 아니요 | integer | default: 100; minimum: 1; maximum: 1000 | | `startTime` | query | 아니요 | integer | minimum: 0; format: "int64" | | `endTime` | query | 아니요 | integer | minimum: 1; format: "int64" | | HTTP | 응답 | | --- | --- | | 200 | [OrderListEnvelope](/api-docs/generated/schemas.md#schema-orderlistenvelope) | ### 주문 상세 {#getorder} `GET https://api.btxpro.co.kr/v1/orders/{orderId}` 인증: **서명 + read** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `orderId` | path | 예 | string | pattern: "^[1-9][0-9]*$" | | HTTP | 응답 | | --- | --- | | 200 | [OrderEnvelope](/api-docs/generated/schemas.md#schema-orderenvelope) | ### 주문 취소 {#cancelorder} `DELETE https://api.btxpro.co.kr/v1/orders/{orderId}` 인증: **서명 + trade** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `orderId` | path | 예 | string | pattern: "^[1-9][0-9]*$" | | `walletId` | query | 아니요 | integer | minimum: 1; maximum: 255 | | `symbol` | query | 아니요 | string | | | HTTP | 응답 | | --- | --- | | 200 | [OrderEnvelope](/api-docs/generated/schemas.md#schema-orderenvelope) | | 422 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | | 504 | [ErrorEnvelope](/api-docs/generated/schemas.md#schema-errorenvelope) | ### 체결 이력 {#listfills} `GET https://api.btxpro.co.kr/v1/fills` 인증: **서명 + read** | 이름 | 위치 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | --- | | `walletId` | query | 아니요 | integer | minimum: 1; maximum: 255 | | `symbol` | query | 아니요 | string | | | `limit` | query | 아니요 | integer | default: 100; minimum: 1; maximum: 1000 | | `startTime` | query | 아니요 | integer | minimum: 0; format: "int64" | | `endTime` | query | 아니요 | integer | minimum: 1; format: "int64" | | HTTP | 응답 | | --- | --- | | 200 | [Envelope](/api-docs/generated/schemas.md#schema-envelope) + object | --- # 요청과 응답 모델 JSON 필드명은 대소문자를 구분합니다. 가격·수량·잔고는 십진수 문자열로 처리하세요. ## Time {#schema-time} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `time` | 예 | integer | format: "int64" | ## Readiness {#schema-readiness} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `status` | 예 | string | | ## Currency {#schema-currency} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `currencyId` | 예 | integer | | | `symbol` | 예 | string | | | `status` | 예 | string | | | `major` | 예 | boolean | | | `maxPrecision` | 예 | integer | | | `depositEnabled` | 예 | boolean | | | `withdrawalEnabled` | 예 | boolean | | | `transferEnabled` | 예 | boolean | | | `tradeEnabled` | 예 | boolean | | ## CurrencyList {#schema-currencylist} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `items` | 예 | [Currency](/api-docs/generated/schemas.md#schema-currency)[] | | ## FeedCategory {#schema-feedcategory} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `id` | 예 | string | pattern: "^[0-9]+$" | | `slug` | 예 | string | | | `name` | 예 | string | | | `description` | 예 | string | | | `displayOrder` | 예 | integer | minimum: 0 | | `creationMicrotime` | 예 | integer | format: "int64" | | `updateMicrotime` | 예 | integer | format: "int64" | ## FeedCategoryList {#schema-feedcategorylist} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `items` | 예 | [FeedCategory](/api-docs/generated/schemas.md#schema-feedcategory)[] | | ## FeedArticleSummary {#schema-feedarticlesummary} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `id` | 예 | string | pattern: "^[1-9][0-9]*$" | | `canonicalKey` | 예 | string | {id}-{slug} | | `canonicalPath` | 예 | string | /feed/{id}-{slug} | | `categoryId` | 예 | string | pattern: "^[0-9]+$" | | `categorySlug` | 예 | string | | | `categoryName` | 예 | string | | | `lang` | 예 | string | | | `slug` | 예 | string | | | `title` | 예 | string | | | `summary` | 예 | string | | | `thumbnailUrl` | 예 | string | | | `readingMinutes` | 예 | integer | Estimated reading time in minutes, stored when the article is saved. minimum: 1 | | `authorName` | 예 | string | | | `viewCount` | 예 | integer | minimum: 0 | | `publishedMicrotime` | 예 | integer | format: "int64" | | `creationMicrotime` | 예 | integer | format: "int64" | | `updateMicrotime` | 예 | integer | format: "int64" | ## FeedArticleDetail {#schema-feedarticledetail} 상속: [FeedArticleSummary](/api-docs/generated/schemas.md#schema-feedarticlesummary) | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `contentMarkdown` | 예 | string | | [FeedArticleSummary](/api-docs/generated/schemas.md#schema-feedarticlesummary) + object ## FeedArticleList {#schema-feedarticlelist} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `items` | 예 | [FeedArticleSummary](/api-docs/generated/schemas.md#schema-feedarticlesummary)[] | | | `sort` | 예 | string | 허용값: "latest", "popular", "search" | | `hasMore` | 예 | boolean | | | `nextCursor` | 예 | string | Empty when hasMore is false. | ## FeedHome {#schema-feedhome} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `featured` | 예 | [FeedArticleSummary](/api-docs/generated/schemas.md#schema-feedarticlesummary) / null | | | `latest` | 예 | [FeedArticleSummary](/api-docs/generated/schemas.md#schema-feedarticlesummary)[] | | | `popular` | 예 | [FeedArticleSummary](/api-docs/generated/schemas.md#schema-feedarticlesummary)[] | | | `categories` | 예 | [FeedCategory](/api-docs/generated/schemas.md#schema-feedcategory)[] | | ## FeedViewCount {#schema-feedviewcount} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `id` | 예 | string | pattern: "^[1-9][0-9]*$" | | `viewCount` | 예 | integer | minimum: 1 | ## Market {#schema-market} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `symbol` | 예 | string | | | `baseCurrency` | 예 | string | | | `quoteCurrency` | 예 | string | | | `baseCurrencyId` | 예 | integer | | | `quoteCurrencyId` | 예 | integer | | | `status` | 예 | string | | | `pricePrecision` | 예 | integer | | | `quantityPrecision` | 예 | integer | | | `minQuantity` | 예 | string | | | `minNotional` | 예 | string | | ## MarketList {#schema-marketlist} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `items` | 예 | [Market](/api-docs/generated/schemas.md#schema-market)[] | | ## Ticker {#schema-ticker} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `symbol` | 예 | string | | | `baseCurrencyId` | 예 | integer | | | `quoteCurrencyId` | 예 | integer | | | `lastPrice` | 예 | string | | | `priceChange` | 예 | string | | | `priceChangeRate` | 예 | string | | | `high` | 예 | string | | | `low` | 예 | string | | | `volume` | 예 | string | | | `quoteVolume` | 예 | string | | | `time` | 예 | integer | format: "int64" | ## TickerList {#schema-tickerlist} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `items` | 예 | [Ticker](/api-docs/generated/schemas.md#schema-ticker)[] | | ## TickerData {#schema-tickerdata} [Ticker](/api-docs/generated/schemas.md#schema-ticker) / [TickerList](/api-docs/generated/schemas.md#schema-tickerlist) ## MarketStreamArg {#schema-marketstreamarg} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `channel` | 예 | string | 허용값: "ticker" | | `symbol` | 예 | string / string | | ## MarketStreamCommand {#schema-marketstreamcommand} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `id` | 예 | string | minLength: 1; maxLength: 64; pattern: "^[A-Za-z0-9._:-]+$" | | `op` | 예 | string | 허용값: "subscribe", "unsubscribe" | | `args` | 예 | [MarketStreamArg](/api-docs/generated/schemas.md#schema-marketstreamarg)[] | minItems: 1; maxItems: 100 | ## MarketStreamSubscriptionAck {#schema-marketstreamsubscriptionack} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `event` | 예 | string | 허용값: "subscribed", "unsubscribed" | | `id` | 예 | string | | | `args` | 예 | [MarketStreamArg](/api-docs/generated/schemas.md#schema-marketstreamarg)[] | | | `serverTime` | 예 | integer | format: "int64" | ## MarketStreamTickerEvent {#schema-marketstreamtickerevent} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `event` | 예 | string | | | `sequence` | 예 | integer | Contiguous sequence across all data channels on this connection. minimum: 1; format: "uint64" | | `arg` | 예 | [MarketStreamArg](/api-docs/generated/schemas.md#schema-marketstreamarg) | | | `data` | 예 | [Ticker](/api-docs/generated/schemas.md#schema-ticker) | | | `serverTime` | 예 | integer | format: "int64" | ## MarketStreamErrorEvent {#schema-marketstreamerrorevent} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `event` | 예 | string | | | `id` | 아니요 | string | Command id when it could be parsed safely. | | `error` | 예 | [Error](/api-docs/generated/schemas.md#schema-error) | | | `serverTime` | 예 | integer | format: "int64" | ## OrderBookLevel {#schema-orderbooklevel} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `price` | 예 | string | | | `quantity` | 예 | string | | ## OrderBook {#schema-orderbook} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `symbol` | 예 | string | | | `tick` | 예 | integer | minimum: 0; maximum: 4 | | `bids` | 예 | [OrderBookLevel](/api-docs/generated/schemas.md#schema-orderbooklevel)[] | | | `asks` | 예 | [OrderBookLevel](/api-docs/generated/schemas.md#schema-orderbooklevel)[] | | | `time` | 예 | integer | format: "int64" | ## Trade {#schema-trade} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `tradeId` | 예 | string | | | `symbol` | 예 | string | | | `side` | 예 | string | 허용값: "buy", "sell", "unknown" | | `price` | 예 | string | | | `quantity` | 예 | string | | | `time` | 예 | integer | format: "int64" | | `microtime` | 예 | integer | format: "int64" | ## TradeList {#schema-tradelist} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `items` | 예 | [Trade](/api-docs/generated/schemas.md#schema-trade)[] | | ## Candle {#schema-candle} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `openTime` | 예 | integer | format: "int64" | | `closeTime` | 예 | integer | format: "int64" | | `open` | 예 | string | | | `high` | 예 | string | | | `low` | 예 | string | | | `close` | 예 | string | | | `volume` | 예 | string | | | `quoteVolume` | 예 | string | | ## CandleList {#schema-candlelist} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `symbol` | 예 | string | | | `interval` | 예 | string | | | `items` | 예 | [Candle](/api-docs/generated/schemas.md#schema-candle)[] | | | `hasMore` | 예 | boolean | | ## AccountPermissions {#schema-accountpermissions} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `read` | 예 | boolean | | | `trade` | 예 | boolean | | | `withdraw` | 예 | boolean | | | `write` | 예 | boolean | | ## Account {#schema-account} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `accountId` | 예 | integer | format: "uint64" | | `apiKeyId` | 예 | integer | format: "uint64" | | `publicKey` | 예 | string | | | `permissions` | 예 | [AccountPermissions](/api-docs/generated/schemas.md#schema-accountpermissions) | | | `createdAt` | 예 | integer | format: "int64" | ## Wallet {#schema-wallet} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `walletId` | 예 | integer | | | `type` | 예 | string | 허용값: "general", "spotTrade", "unknown" | | `name` | 예 | string | | | `favorite` | 예 | boolean | | | `criteriaCurrency` | 아니요 | string | | | `criteriaCurrencyId` | 예 | integer | | | `incoming` | 예 | integer | | | `outgoing` | 예 | integer | | | `createdAt` | 예 | integer | format: "int64" | | `updatedAt` | 예 | integer | format: "int64" | ## WalletList {#schema-walletlist} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `wallets` | 예 | [Wallet](/api-docs/generated/schemas.md#schema-wallet)[] | | ## Balance {#schema-balance} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `walletId` | 예 | integer | | | `currency` | 예 | string | | | `currencyId` | 예 | integer | | | `available` | 예 | string | | | `inUse` | 예 | string | | | `total` | 예 | string | | | `updatedAt` | 예 | integer | format: "int64" | ## BalanceList {#schema-balancelist} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `balances` | 예 | [Balance](/api-docs/generated/schemas.md#schema-balance)[] | | ## Fill {#schema-fill} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `fillId` | 예 | string | | | `orderId` | 예 | string | | | `symbol` | 아니요 | string | | | `walletId` | 예 | integer | | | `side` | 예 | string | 허용값: "buy", "sell", "unknown" | | `type` | 예 | string | 허용값: "limit", "unknown" | | `liquidity` | 예 | string | 허용값: "maker", "taker" | | `price` | 예 | string | | | `quantity` | 예 | string | | | `quoteQuantity` | 예 | string | | | `baseCurrencyId` | 예 | integer | | | `quoteCurrencyId` | 예 | integer | | | `time` | 예 | integer | format: "int64" | | `microtime` | 예 | integer | format: "int64" | ## FillList {#schema-filllist} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `items` | 예 | [Fill](/api-docs/generated/schemas.md#schema-fill)[] | | | `hasMore` | 예 | boolean | | ## UserStreamSnapshot {#schema-userstreamsnapshot} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `orders` | 예 | [Order](/api-docs/generated/schemas.md#schema-order)[] | Open spot orders visible to the API key. | | `ordersHasMore` | 예 | boolean | True when more than 1000 open orders were visible at snapshot time. | | `balances` | 예 | [Balance](/api-docs/generated/schemas.md#schema-balance)[] | Current balances for every wallet visible to the API key. | ## UserStreamSnapshotEvent {#schema-userstreamsnapshotevent} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `event` | 예 | string | | | `sequence` | 예 | integer | A snapshot always starts a new connection at sequence 0. format: "uint64" | | `data` | 예 | [UserStreamSnapshot](/api-docs/generated/schemas.md#schema-userstreamsnapshot) | | | `serverTime` | 예 | integer | format: "int64" | ## UserStreamOrderEvent {#schema-userstreamorderevent} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `event` | 예 | string | | | `updateType` | 예 | string | The absolute lifecycle state represented by this update. 허용값: "open", "partiallyFilled", "filled", "canceled", "unknown" | | `sequence` | 예 | integer | Contiguous sequence scoped to this WebSocket connection. minimum: 1; format: "uint64" | | `data` | 예 | [Order](/api-docs/generated/schemas.md#schema-order) | | | `serverTime` | 예 | integer | format: "int64" | ## UserStreamFill {#schema-userstreamfill} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `executionId` | 예 | string | Opaque realtime deduplication id derived from order id and cumulative filled quantity. It is not the REST fillId. | | `orderId` | 예 | string | | | `symbol` | 아니요 | string | | | `walletId` | 예 | integer | | | `side` | 예 | string | 허용값: "buy", "sell", "unknown" | | `type` | 예 | string | 허용값: "limit", "unknown" | | `liquidity` | 예 | string | 허용값: "maker", "taker" | | `price` | 예 | string | Execution price, or the weighted-average price when aggregated is true. | | `quantity` | 예 | string | | | `quoteQuantity` | 예 | string | | | `cumulativeQuantity` | 예 | string | | | `cumulativeQuoteQuantity` | 예 | string | | | `cumulativeFee` | 예 | string | Order-level cumulative fee, not the fee delta for this event. | | `aggregated` | 예 | boolean | True when this realtime event can represent more than one underlying match. | | `baseCurrencyId` | 예 | integer | | | `quoteCurrencyId` | 예 | integer | | | `time` | 예 | integer | format: "int64" | | `microtime` | 예 | integer | format: "int64" | ## UserStreamFillEvent {#schema-userstreamfillevent} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `event` | 예 | string | | | `sequence` | 예 | integer | Contiguous sequence scoped to this WebSocket connection. minimum: 1; format: "uint64" | | `data` | 예 | [UserStreamFill](/api-docs/generated/schemas.md#schema-userstreamfill) | | | `serverTime` | 예 | integer | format: "int64" | ## UserStreamBalanceEvent {#schema-userstreambalanceevent} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `event` | 예 | string | | | `sequence` | 예 | integer | Contiguous sequence scoped to this WebSocket connection. minimum: 1; format: "uint64" | | `data` | 예 | [Balance](/api-docs/generated/schemas.md#schema-balance) | | | `serverTime` | 예 | integer | format: "int64" | ## UserStreamCommandId {#schema-userstreamcommandid} Client correlation id. It is not an order idempotency key. string — minLength: 1; maxLength: 64; pattern: "^[A-Za-z0-9._:-]+$" ## UserStreamCreateOrderCommand {#schema-userstreamcreateordercommand} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `id` | 예 | [UserStreamCommandId](/api-docs/generated/schemas.md#schema-userstreamcommandid) | | | `op` | 예 | string | | | `args` | 예 | [CreateOrderRequest](/api-docs/generated/schemas.md#schema-createorderrequest) | | ## UserStreamCancelOrderArgs {#schema-userstreamcancelorderargs} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `orderId` | 예 | string | pattern: "^[1-9][0-9]*$" | ## UserStreamCancelOrderCommand {#schema-userstreamcancelordercommand} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `id` | 예 | [UserStreamCommandId](/api-docs/generated/schemas.md#schema-userstreamcommandid) | | | `op` | 예 | string | | | `args` | 예 | [UserStreamCancelOrderArgs](/api-docs/generated/schemas.md#schema-userstreamcancelorderargs) | | ## UserStreamAmendOrderArgs {#schema-userstreamamendorderargs} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `orderId` | 예 | string | pattern: "^[1-9][0-9]*$" | | `quantity` | 아니요 | string | | | `price` | 아니요 | string | | ## UserStreamAmendOrderCommand {#schema-userstreamamendordercommand} Reserved native amend command. Current servers return AMEND_NOT_SUPPORTED without canceling the original order. | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `id` | 예 | [UserStreamCommandId](/api-docs/generated/schemas.md#schema-userstreamcommandid) | | | `op` | 예 | string | | | `args` | 예 | [UserStreamAmendOrderArgs](/api-docs/generated/schemas.md#schema-userstreamamendorderargs) | | ## UserStreamCommandResponse {#schema-userstreamcommandresponse} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `event` | 예 | string | | | `id` | 예 | [UserStreamCommandId](/api-docs/generated/schemas.md#schema-userstreamcommandid) | | | `op` | 예 | string | 허용값: "order.create", "order.cancel", "order.amend" | | `data` | 예 | [Order](/api-docs/generated/schemas.md#schema-order) | | | `serverTime` | 예 | integer | format: "int64" | ## UserStreamCommandError {#schema-userstreamcommanderror} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `event` | 예 | string | | | `id` | 예 | string | Echoed command ID when valid; empty when a malformed/throttled packet has no usable ID. pattern: "^[A-Za-z0-9._:-]{0,64}$" | | `op` | 아니요 | string | | | `error` | 예 | [Error](/api-docs/generated/schemas.md#schema-error) | | | `serverTime` | 예 | integer | format: "int64" | ## CreateOrderRequest {#schema-createorderrequest} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `symbol` | 예 | string | | | `walletId` | 예 | integer | Required account-local visible spot-trading wallet ID from GET /v1/wallets; not a blockchain address or walletNumber. The server never chooses a default wallet. minimum: 21; maximum: 39 | | `side` | 예 | string | 허용값: "buy", "sell" | | `type` | 예 | string | 허용값: "limit" | | `timeInForce` | 아니요 | string | 허용값: "GTC"; default: "GTC" | | `quantity` | 예 | string | | | `quoteQuantity` | 아니요 | string | Reserved for future support. | | `price` | 예 | string | | | `postOnly` | 아니요 | boolean | Reserved for future support. | ## Order {#schema-order} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `orderId` | 예 | string | pattern: "^[1-9][0-9]*$" | | `symbol` | 아니요 | string | | | `walletId` | 예 | integer | minimum: 1 | | `side` | 예 | string | 허용값: "buy", "sell", "unknown" | | `type` | 예 | string | 허용값: "limit", "unknown" | | `status` | 예 | string | 허용값: "open", "partiallyFilled", "filled", "canceled", "unknown" | | `price` | 예 | string | | | `quantity` | 예 | string | | | `filledQuantity` | 예 | string | | | `remainingQuantity` | 예 | string | | | `executedValue` | 예 | string | | | `fee` | 예 | string | | | `createdAt` | 예 | integer | format: "int64" | | `updatedAt` | 예 | integer | format: "int64" | | `baseCurrencyId` | 예 | integer | | | `quoteCurrencyId` | 예 | integer | | ## OrderList {#schema-orderlist} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `items` | 예 | [Order](/api-docs/generated/schemas.md#schema-order)[] | | | `hasMore` | 예 | boolean | | ## CancelOrderItem {#schema-cancelorderitem} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `orderId` | 예 | string | pattern: "^[1-9][0-9]*$" | | `status` | 예 | string | 허용값: "canceled", "rejected" | | `errorCode` | 아니요 | string | | | `symbol` | 아니요 | string | | | `walletId` | 아니요 | integer | minimum: 1 | ## CancelOrderList {#schema-cancelorderlist} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `items` | 예 | [CancelOrderItem](/api-docs/generated/schemas.md#schema-cancelorderitem)[] | | | `hasMore` | 예 | boolean | | ## Envelope {#schema-envelope} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `data` | 아니요 | object | | | `error` | 아니요 | [Error](/api-docs/generated/schemas.md#schema-error) | | | `requestId` | 예 | string | | | `serverTime` | 예 | integer | format: "int64" | ## Error {#schema-error} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `code` | 예 | string | | | `message` | 예 | string | | ## OrderEnvelope {#schema-orderenvelope} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `data` | 예 | [Order](/api-docs/generated/schemas.md#schema-order) | | | `requestId` | 예 | string | | | `serverTime` | 예 | integer | format: "int64" | ## OrderListEnvelope {#schema-orderlistenvelope} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `data` | 예 | [OrderList](/api-docs/generated/schemas.md#schema-orderlist) | | | `requestId` | 예 | string | | | `serverTime` | 예 | integer | format: "int64" | ## CancelOrderListEnvelope {#schema-cancelorderlistenvelope} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `data` | 예 | [CancelOrderList](/api-docs/generated/schemas.md#schema-cancelorderlist) | | | `requestId` | 예 | string | | | `serverTime` | 예 | integer | format: "int64" | ## ErrorEnvelope {#schema-errorenvelope} | 필드 | 필수 | 타입 | 설명과 제약 | | --- | --- | --- | --- | | `error` | 예 | [Error](/api-docs/generated/schemas.md#schema-error) | | | `requestId` | 예 | string | | | `serverTime` | 예 | integer | format: "int64" | --- # 공개 시세와 Feed 이 페이지의 API는 API 키가 필요 없습니다. 모든 REST 요청의 기본 주소는 `https://api.btxpro.co.kr`입니다. 상세 필드와 응답 모델은 [전체 엔드포인트](/api-docs/generated/rest.md)와 [레퍼런스](/api-docs/reference.md)를 확인하세요. ## 시스템과 마켓 | 메서드 | 경로 | 용도 | | --- | --- | --- | | GET | `/health` | 프로세스 liveness. 정상 시 본문 없는 200 | | GET | `/ready` | 의존성과 거래 서비스 준비 여부. 미준비 시 503 | | GET | `/v1/time` | 서버 시간과 서명 시간 차이 확인 | | GET | `/v1/currencies` | 통화 메타데이터 | | GET | `/v1/markets` | 마켓 목록 | | GET | `/v1/markets/{symbol}` | 마켓 상세 | `/health`가 정상이어도 거래 준비를 보장하지는 않습니다. 클라이언트는 실제 API의 오류 응답도 처리해야 합니다. ## 시세 조회 | 경로 | 주요 파라미터 | 설명 | | --- | --- | --- | | `/v1/market/ticker` | `symbol` 선택 | 생략하면 전체 마켓 시세 | | `/v1/market/orderbook` | `symbol` 필수, `tick`, `limit` | tick 0~4, 기본 0. 기본 100개, 최대 1000개 | | `/v1/market/trades` | `symbol` 필수, `limit` | 최근 체결. 기본 100개, 최대 1000개 | | `/v1/market/candles` | `symbol` 필수, `interval`, `limit`, `startTime`, `endTime` | interval 기본 1h, 기본 500개, 최대 1000개 | 모두 GET입니다. 캔들 조회의 시작 시각은 포함, 종료 시각은 미포함입니다. 허용되는 캔들 interval 값은 [파라미터 명세](/api-docs/generated/rest.md#getcandles)에서 확인합니다. ```sh curl 'https://api.btxpro.co.kr/v1/market/orderbook?symbol=BTC-USDT&tick=0&limit=20' curl 'https://api.btxpro.co.kr/v1/market/candles?symbol=BTC-USDT&interval=1h&limit=24' ``` 실시간으로 제공되는 공개 채널은 현재 **ticker 하나**입니다. 호가·체결·캔들의 실시간 WS 채널은 현재 제공하지 않으므로 위 REST API로 조회합니다. ## Feed | 메서드 | 경로 | 용도 | | --- | --- | --- | | GET | `/v1/feed/home` | 추천·최신·인기 등 Feed 홈 구성 | | GET | `/v1/feed/categories` | 활성 카테고리 목록 | | GET | `/v1/feed/articles` | 공개 글 목록·검색·정렬·cursor 조회 | | GET | `/v1/feed/articles/{feedArticleId}` | 글 상세와 Markdown 본문 | | POST | `/v1/feed/articles/{feedArticleId}/view` | 공개 글 조회수 증가 | ```sh curl 'https://api.btxpro.co.kr/v1/feed/categories' curl 'https://api.btxpro.co.kr/v1/feed/articles?limit=20' ``` 글 상세의 식별자는 `feedArticleId`입니다. URL slug를 ID 대신 전달하지 마세요. 글 목록의 `q` 검색어는 2~80자 범위이며 `sort`·`cursor`와 함께 보낼 수 없습니다. 검색은 모든 유효 검색어를 포함하는 글을 찾고, 제목 → 요약 → 본문 일치 순으로 정렬합니다. 조회수 증가 요청은 공개 API지만 데이터를 변경합니다. 단순 목록 조회를 위해 호출하지 마세요. --- # 계정과 지갑 모든 요청에 [HMAC 인증](/api-docs/guide/authentication.md)이 필요합니다. REST 기본 주소는 `https://api.btxpro.co.kr`입니다. | 메서드 | 경로 | 권한 | 용도 | | --- | --- | --- | --- | | GET | `/v1/account` | 서명된 키 | 계정 ID, 키 ID, Public Key, 권한 | | GET | `/v1/wallets` | read | 계정에서 볼 수 있는 일반·현물 거래 지갑 | | GET | `/v1/balances` | read | 지갑별 통화 잔고 | ## 계정과 권한 확인 `GET /v1/account`의 `data` 예시: ```json { "accountId": 123, "apiKeyId": 7, "publicKey": "public", "permissions": { "read": true, "trade": true, "withdraw": false, "write": false }, "createdAt": 1783420800123 } ``` Secret Key는 반환하지 않습니다. 주문 클라이언트는 시작할 때 read·trade 권한을 확인하는 것이 좋습니다. ## 지갑과 잔고 조회 순서 1. `/v1/wallets`로 접근 가능한 지갑을 확인합니다. 2. `/v1/balances?walletId=21`로 필요한 지갑만 조회합니다. 3. 통화 제한이 필요하면 `currency`를 추가합니다. 정확한 타입은 [잔고 명세](/api-docs/generated/rest.md#listbalances)를 확인하세요. 4. 주문에는 조회 결과의 현물 거래 지갑 `walletId`를 전달합니다. `walletId`, `currency`는 잔고 조회에서 선택 파라미터입니다. 개인 키가 있다고 해서 계정 밖의 지갑을 조회하거나 거래할 수 있는 것은 아닙니다. 실시간 잔고가 필요하면 [개인 WS](/api-docs/websocket/user.md)를 연결합니다. 잔고 이벤트는 차감·가산량이 아닌 **절대 잔고**이므로 지갑·통화 단위로 로컬 값을 교체합니다. --- # 주문과 체결 REST 기본 주소는 `https://api.btxpro.co.kr`입니다. 모든 요청은 서명하며, 조회는 read, 생성·취소는 trade 권한이 필요합니다. ## 지원하는 주문 현재는 `type: "limit"`, `timeInForce: "GTC"`인 지정가 주문만 지원합니다. `side`는 `buy` 또는 `sell`입니다. 시장가, post-only, IOC/FOK, quote 수량 주문은 지원하지 않습니다. ## 주문 생성 ```http POST https://api.btxpro.co.kr/v1/orders Content-Type: application/json ``` ```json { "symbol": "BTC-USDT", "walletId": 21, "side": "buy", "type": "limit", "timeInForce": "GTC", "quantity": "0.100000000", "price": "65000.000000000" } ``` 위 JSON은 서명 전 본문의 예시입니다. 전송할 JSON 바이트로 서명한 뒤 인증 헤더를 붙여 요청합니다. 응답은 엔진 결과를 최대 10초 기다린 후 반환하며, 성공 시 `data.orderId`와 주문 상태를 확인합니다. 성공·실패 모델의 전체 필드는 [주문 모델](/api-docs/generated/schemas.md#schema-order)을 확인하세요. ## 조회와 취소 | 메서드 | 경로 | 주요 파라미터 | | --- | --- | --- | | GET | `/v1/orders/open` | `walletId`, `symbol`, `limit` 선택 | | GET | `/v1/orders/history` | `walletId`, `symbol`, `limit`, `startTime`, `endTime` 선택 | | GET | `/v1/orders/{orderId}` | orderId 필수 | | DELETE | `/v1/orders/{orderId}` | orderId 필수, `walletId`, `symbol`은 일치 여부 확인용 | | DELETE | `/v1/orders` | `walletId` 필수, `symbol`, `limit` 선택 | | GET | `/v1/fills` | `walletId`, `symbol`, `limit`, `startTime`, `endTime` 선택 | 단건 취소 예시 경로: ```text DELETE /v1/orders/987654?walletId=21&symbol=BTC-USDT ``` 서명할 쿼리는 정렬된 `symbol=BTC-USDT&walletId=21`입니다. 서명 예제가 전송 쿼리도 같은 방식으로 생성합니다. 일괄 취소는 지정한 지갑의 대상 주문을 선택합니다. 최대 16개 엔진 명령을 동시에 처리하고, 배치 전체가 하나의 10초 제한을 공유합니다. 결과의 `items`와 `hasMore`를 확인하세요. 개별 취소 실패도 항목별로 확인해야 하며 HTTP 성공만으로 전체 주문의 취소를 판단하면 안 됩니다. ## 주문 타임아웃과 재시도 {#timeouts-and-retries} `ENGINE_TIMEOUT`은 주문이 실패했다는 확정 응답이 아닙니다. 엔진에서 처리됐지만 응답을 받지 못했을 수 있습니다. 1. 같은 생성·취소 요청을 자동으로 다시 보내지 않습니다. 2. 미체결 주문, 주문 이력, 체결 이력을 조회합니다. 3. 개인 WS를 사용한다면 재연결 후 새 스냅샷도 반영합니다. 4. 결과를 식별하지 못하면 중복 주문 위험을 감수하는 자동 재전송 대신 운영 확인 절차로 전환합니다. 고객 주문 ID, 멱등성 키, 요청 상태 조회 엔드포인트는 현재 없습니다. `requestId`와 WS 명령 `id`는 요청·응답을 연결하는 값입니다. --- # WebSocket 연결과 공통 규칙 외부 WebSocket은 운영 환경에서 **`wss://api-ws.btxpro.co.kr`** 호스트를 사용합니다. REST의 `api.btxpro.co.kr`와 구분해서 사용합니다. | 스트림 | 전체 연결 주소 | 용도 | | --- | --- | --- | | 공개 | `wss://api-ws.btxpro.co.kr/v1/market/stream` | ticker 구독·해제 | | 개인 | `wss://api-ws.btxpro.co.kr/v1/user/stream` | 주문·체결·잔고 수신과 주문 명령 | 공개·개인 스트림은 별도 연결입니다. 개인 주문 명령은 개인 이벤트를 수신하는 **동일 연결**로 전송합니다. 별도 거래용 호스트나 경로는 없습니다. ## 연결 방법 - 공개 스트림은 키 없이 HTTP GET을 WebSocket으로 업그레이드합니다. 쿼리 파라미터는 받지 않습니다. - 개인 스트림은 GET 업그레이드 요청에 [인증 헤더](/api-docs/guide/authentication.md#websocket-authentication)를 포함합니다. - 연결 후에는 UTF-8 JSON 텍스트 프레임을 사용합니다. - 공개 스트림은 `subscribe`를 보내야 시세를 받습니다. 개인 스트림은 연결 직후 `snapshot`을 받으며 별도 subscribe가 없습니다. ## heartbeat와 제한 {#heartbeat-and-limits} | 항목 | 제한 | | --- | --- | | 서버 ping | 30초마다 WebSocket 제어 프레임 | | pong 제한 | 75초 | | 공개 명령 크기 | 8 KiB | | 개인 명령 크기 | 16 KiB | | 명령 ID | `[A-Za-z0-9._:-]+`, 최대 64자 | | 공개 구독 | 개별 symbol 최대 100개 또는 wildcard 하나 | | 개인 명령 대기열 | 연결당 32개 | | 공개·개인 이벤트 큐 | 각각 256개 / 128개 | | 개인 키·권한 재확인 | 명령마다, 유휴 연결은 60초마다 | 라이브러리의 ping/pong 처리를 사용하세요. JSON `{"op":"ping"}` 명령은 프로토콜에 없습니다. 서버가 이벤트를 보내는 속도를 따라가지 못하면 `1013 / EVENT_BUFFER_OVERFLOW`로 종료됩니다. ## sequence와 명령 ID 공개 데이터 이벤트는 연결마다 `sequence: 1`부터 연속 증가합니다. 개인 연결은 초기 `snapshot`이 0, 이후 `order`·`fill`·`balance`가 공통 sequence로 1부터 연속 증가합니다. 구독 확인이나 개인 명령의 `response`·`error`는 데이터 sequence를 사용하지 않습니다. 개인 주문 이벤트가 명령 성공 응답보다 먼저 도착할 수도 있습니다. 명령 `id`와 데이터 `sequence`를 별도로 추적하세요. ## 다음 가이드 - [공개 시세: subscribe, unsubscribe, ticker](/api-docs/websocket/market.md) - [개인 이벤트: snapshot, order, fill, balance](/api-docs/websocket/user.md) - [주문 명령: create, cancel, amend](/api-docs/websocket/commands.md) - [재연결과 상태 복구](/api-docs/websocket/recovery.md) - [모든 메시지 스키마](/api-docs/generated/websocket.md) --- # 공개 시세 스트림 ```text wss://api-ws.btxpro.co.kr/v1/market/stream ``` API 키 없이 연결합니다. 현재 공개 채널은 `ticker`이며, [REST 시세](/api-docs/generated/rest.md#getticker)와 같은 시세 객체를 전달합니다. ## 구독 ```json { "id": "sub-1", "op": "subscribe", "args": [ { "channel": "ticker", "symbol": "BTC-USDT" }, { "channel": "ticker", "symbol": "ETH-USDT" } ] } ``` 서버는 정규화된 구독 확인을 먼저 보냅니다. ```json { "event": "subscribed", "id": "sub-1", "args": [ { "channel": "ticker", "symbol": "BTC-USDT" }, { "channel": "ticker", "symbol": "ETH-USDT" } ], "serverTime": 1783420800123 } ``` 캐시된 ticker가 있으면 확인 메시지 직후 현재 값을 보냅니다. 이후의 이벤트 예시: ```json { "event": "ticker", "sequence": 1, "arg": { "channel": "ticker", "symbol": "BTC-USDT" }, "data": { "symbol": "BTC-USDT", "baseCurrencyId": 1002, "quoteCurrencyId": 1001, "lastPrice": "65000.000000000", "priceChange": "1000.000000000", "priceChangeRate": "0.015600000", "high": "66000.000000000", "low": "63000.000000000", "volume": "12.500000000", "quoteVolume": "810000.000000000", "time": 1783420800123 }, "serverTime": 1783420800123 } ``` 가격과 수량은 문자열입니다. `sequence`는 symbol별이 아니라 연결 전체에서 증가합니다. ## 구독 해제와 전체 구독 ```json { "id": "unsub-1", "op": "unsubscribe", "args": [{ "channel": "ticker", "symbol": "BTC-USDT" }] } ``` 해제 확인의 `event`는 `unsubscribed`입니다. | 동작 | args의 symbol | | --- | --- | | 전체 활성 마켓 구독 | subscribe에서 `*` | | 전체 구독 중 한 마켓 제외 | unsubscribe에서 해당 symbol | | 제외한 마켓 다시 포함 | subscribe에서 해당 symbol | | 모든 구독 해제 | unsubscribe에서 `*` | 일반 구독은 최대 100개 symbol입니다. wildcard는 하나로 계산됩니다. `trades`, `orderbook`, `candles`는 현재 지원 채널이 아닙니다. ## 오류와 재연결 오류 이벤트의 정확한 필드는 [MarketStreamErrorEvent](/api-docs/generated/schemas.md#schema-marketstreamerrorevent)를 확인하세요. 연결이 끊어지거나 sequence가 건너뛰면 새 연결에서 구독을 다시 설정합니다. 이전 연결의 데이터는 재전송하지 않습니다. --- # 개인 이벤트 스트림 ```text wss://api-ws.btxpro.co.kr/v1/user/stream ``` `read` 권한으로 [서명된 업그레이드](/api-docs/guide/authentication.md#websocket-authentication)를 수행합니다. 구독 명령 없이 초기 상태와 후속 이벤트를 받습니다. 같은 연결에서 `trade` 권한으로 [주문 명령](/api-docs/websocket/commands.md)을 보낼 수 있습니다. ## 초기 snapshot 첫 JSON 프레임은 항상 sequence 0인 snapshot입니다. ```json { "event": "snapshot", "sequence": 0, "data": { "orders": [], "ordersHasMore": false, "balances": [] }, "serverTime": 1783420800123 } ``` 현재 볼 수 있는 지갑 잔고와 최대 1000개의 현물 미체결 주문을 포함합니다. `ordersHasMore: true`면 주문 목록이 잘린 것이므로 스냅샷만으로 전체 미체결 주문 상태를 확정하지 마세요. REST 조회를 병행하고 필요하면 지갑·마켓별로 상태 범위를 나눕니다. 전체 상태를 확보하지 못한 자동매매는 운영 확인이 필요합니다. 스냅샷을 만드는 동안 대기한 이벤트는 이후에 순서대로 전달됩니다. 이미 snapshot의 누적 체결 수량에 포함된 체결은 같은 연결에서 중복 발행하지 않습니다. ## 이벤트 종류 | event | sequence | 처리 방법 | | --- | --- | --- | | snapshot | 0 | 주문·잔고의 초기 상태 구성 | | order | 연속 증가 | 해당 주문의 절대 상태로 교체 | | fill | 연속 증가 | 체결 증가분 처리와 누적 상태 확인 | | balance | 연속 증가 | 지갑·통화의 절대 잔고로 교체 | | response | 없음 | id로 보낸 명령과 연결 | | error | 없음 | id로 보낸 명령의 오류 처리 | `order`, `fill`, `balance`가 하나의 sequence를 공유합니다. 모든 이벤트를 순서대로 수신한 뒤 필요한 유형을 분배해야 합니다. ## 주문 이벤트 `updateType`은 `open`, `partiallyFilled`, `filled`, `canceled`, `unknown` 중 하나입니다. 아래는 핵심 필드만 보인 예시이며 전체 주문 필드는 [UserStreamOrderEvent](/api-docs/generated/schemas.md#schema-userstreamorderevent)에 있습니다. ```json { "event": "order", "updateType": "partiallyFilled", "sequence": 7, "data": { "orderId": "987654", "status": "partiallyFilled", "filledQuantity": "0.040000000", "remainingQuantity": "0.060000000" }, "serverTime": 1783420800123 } ``` 수량·체결 금액·수수료는 누적값입니다. 이벤트의 절대 주문 상태로 기존 값을 교체합니다. ## 체결 이벤트 ```json { "event": "fill", "sequence": 8, "data": { "executionId": "987654:0.040000000", "orderId": "987654", "symbol": "BTC-USDT", "walletId": 21, "side": "buy", "type": "limit", "liquidity": "maker", "price": "65000.000000000", "quantity": "0.010000000", "quoteQuantity": "650.000000000", "cumulativeQuantity": "0.040000000", "cumulativeQuoteQuantity": "2600.000000000", "cumulativeFee": "0.001000000", "aggregated": false, "baseCurrencyId": 1002, "quoteCurrencyId": 1001, "time": 1783420800123, "microtime": 1783420800123456 }, "serverTime": 1783420800123 } ``` - `executionId`는 실시간 중복 확인용 불투명 ID입니다. REST `/v1/fills`의 `fillId`와 다릅니다. - `quantity`와 `quoteQuantity`는 이번 이벤트의 체결 증가분입니다. - `cumulativeQuantity`, `cumulativeQuoteQuantity`, `cumulativeFee`는 주문 전체의 누적값입니다. - maker는 보통 한 번의 체결이며 `aggregated: false`입니다. taker가 여러 주문을 체결한 결과나 복구된 누적 차이는 `aggregated: true`일 수 있습니다. 이때 `price`는 해당 결과의 가중평균입니다. - snapshot은 체결을 재생하지 않습니다. 연결이 끊긴 구간의 정확한 체결은 REST로 대조합니다. ## 잔고 이벤트와 순서 주문 엔진의 체결 업데이트는 `order` → `fill` → 관련 기준·결제 통화의 `balance` 순서로 전달됩니다. 이체에 따른 잔고 변경도 balance 이벤트로 전달됩니다. 잔고 필드는 [Balance](/api-docs/generated/schemas.md#schema-balance)를 확인하세요. 잔고 이벤트를 기존 값에 더하지 말고, 지갑과 통화별 상태를 대체합니다. 연결 종료·sequence 누락·권한 변경 시에는 [복구 절차](/api-docs/websocket/recovery.md)를 따릅니다. --- # 개인 WebSocket 주문 명령 `wss://api-ws.btxpro.co.kr/v1/user/stream`에 연결한 뒤 초기 snapshot을 소비하고 명령을 보냅니다. 연결 시 read, 모든 주문 명령에는 trade 권한이 필요합니다. 서버는 실행 직전에 키와 권한을 다시 확인합니다. ## 공통 형식 ```json { "id": "bot-7:create:1042", "op": "order.create", "args": {} } ``` `id`는 `[A-Za-z0-9._:-]+`에 맞는 최대 64자 문자열입니다. 같은 연결에서 처리 중인 ID를 재사용하면 `DUPLICATE_COMMAND_ID`입니다. 완료되거나 재연결한 뒤의 재전송을 막아주는 값은 아닙니다. 서버는 한 연결의 명령을 수신 순서대로 실행합니다. 이벤트 수신과 명령 응답 수신은 동시에 처리해야 합니다. ## order.create ```json { "id": "bot-7:create:1042", "op": "order.create", "args": { "symbol": "BTC-USDT", "walletId": 21, "side": "buy", "type": "limit", "timeInForce": "GTC", "quantity": "0.100000000", "price": "65000.000000000" } } ``` 주문 필드는 REST의 [CreateOrderRequest](/api-docs/generated/schemas.md#schema-createorderrequest)와 같습니다. 현재 지정가 GTC만 지원합니다. ## order.cancel ```json { "id": "bot-7:cancel:1043", "op": "order.cancel", "args": { "orderId": "987654" } } ``` 이 명령의 args에는 `orderId`만 전달합니다. `walletId`, `symbol`은 REST 단건 취소에서만 선택적으로 사용합니다. 일괄 취소는 REST `DELETE /v1/orders`를 사용합니다. ## order.amend ```json { "id": "bot-7:amend:1044", "op": "order.amend", "args": { "orderId": "987654", "price": "66000.000000000" } } ``` 현재 원자적 정정을 지원하지 않습니다. [정정 요청 모델](/api-docs/generated/schemas.md#schema-userstreamamendorderargs)의 필드로 요청해도 `AMEND_NOT_SUPPORTED`를 반환하며 원래 주문을 변경·취소하지 않습니다. 취소 후 새 주문 생성은 별개 작업이며 중간 체결 위험이 있습니다. ## 성공·오류 응답 아래 성공 응답의 `data`는 핵심 필드만 표시했습니다. 전체 응답은 [UserStreamCommandResponse](/api-docs/generated/schemas.md#schema-userstreamcommandresponse)를 확인하세요. ```json { "event": "response", "id": "bot-7:create:1042", "op": "order.create", "data": { "orderId": "987654", "status": "open" }, "serverTime": 1783420800123 } ``` ```json { "event": "error", "id": "bot-7:amend:1044", "op": "order.amend", "error": { "code": "AMEND_NOT_SUPPORTED", "message": "The trading engine does not support atomic order amendment." }, "serverTime": 1783420800123 } ``` `response`·`error`에는 이벤트 sequence가 없습니다. `id`로 명령을 찾아 완료 처리합니다. 주문 이벤트는 response보다 먼저 도착할 수도 있습니다. 결과를 받지 못하고 연결이 끊기면 생성·취소 명령을 자동 재전송하지 마세요. [새 snapshot과 REST 조회로 상태를 대조](/api-docs/websocket/recovery.md)합니다. --- # 재연결과 상태 복구 외부 WS는 연결별 sequence를 제공합니다. 과거 이벤트를 다시 받는 영구 replay cursor는 제공하지 않습니다. 재연결은 이전 연결의 연장이 아니라 새로운 상태 동기화입니다. ## 공개 스트림 1. 연결 종료 또는 데이터 sequence 누락을 감지합니다. 2. 지수 백오프와 jitter를 적용해 새로 연결합니다. 3. 사용 중이던 ticker 구독을 다시 보냅니다. 4. 구독 확인 후 도착하는 현재 ticker부터 상태를 새로 구성합니다. 구독 확인에는 sequence가 없고, 데이터 sequence는 새 연결에서 1부터 시작합니다. ## 개인 스트림 1. 아직 결과를 받지 못한 생성·취소 명령을 **결과 불명** 상태로 기록합니다. 2. 새로운 timestamp와 HMAC 서명으로 개인 스트림에 다시 연결합니다. 3. 첫 프레임이 `snapshot`, `sequence: 0`인지 확인합니다. 4. snapshot으로 주문·잔고 상태를 구성하고, 이후 모든 sequence를 연속 처리합니다. 5. 끊긴 시각을 포함하도록 REST `/v1/fills`를 조회해 누락 체결을 대조합니다. 실시간 `executionId`와 REST `fillId`가 다르므로 두 값을 같은 ID로 조인하지 마세요. 6. 결과 불명 주문은 미체결·주문 이력·체결 이력으로 확인한 후 후속 행동을 결정합니다. 복구 중 발생하는 새 이벤트도 계속 수신·반영해야 합니다. REST 조회가 반환됐다는 이유로 더 최신 WS 상태를 오래된 값으로 덮어쓰지 마세요. snapshot의 `ordersHasMore`가 true이면 잘린 주문 집합을 전체 상태로 간주하지 않습니다. ## 재접속해도 해결되지 않는 오류 | 상황 | 다음 행동 | | --- | --- | | INVALID_API_KEY, NO_PERMISSION, close 1008 | 키·권한 확인 후 필요하면 재발급 | | INVALID_SIGNATURE | 서명할 경로·쿼리·본문 바이트 확인 | | TIMESTAMP_OUT_OF_RANGE | 호스트 시간 동기화와 receive window 확인 | | 업그레이드 HTTP 404 | 외부 호스트 `api-ws.btxpro.co.kr`와 스트림 경로 확인 | | close 1013 / EVENT_BUFFER_OVERFLOW | 수신 처리 속도 개선 후 새 snapshot 구성 | | 명령 ENGINE_TIMEOUT | 주문 결과 대조. 동일 명령 자동 재전송 금지 | 인증 오류를 무한 재접속으로 처리하지 마세요. HTTP 업그레이드와 WS 명령 모두 IP 기준 예산을 소비합니다. ## Go SDK의 차이 `StreamTickers`·`StreamUser`의 `Reconnect: true`는 연결·sequence 오류에 백오프 재연결을 수행합니다. 개인 스트림은 새 snapshot을 받습니다. 인증·콜백 오류는 종료됩니다. 양방향 `OpenUserStream` 세션은 자동으로 재연결하거나 주문 명령을 다시 보내지 않습니다. 호출자가 새 세션을 열고 상태를 대조해야 합니다. --- # WebSocket 메시지 모델 메시지의 필드와 허용값은 REST와 같은 명세에서 생성됩니다. 연결 주소는 `wss://api-ws.btxpro.co.kr`입니다. ## 공개 시세 WebSocket 연결 `/v1/market/stream` ### 클라이언트 → 서버 | 메시지 | 스키마 | | --- | --- | | `subscribe` | [MarketStreamCommand](/api-docs/generated/schemas.md#schema-marketstreamcommand) | | `unsubscribe` | [MarketStreamCommand](/api-docs/generated/schemas.md#schema-marketstreamcommand) | ### 서버 → 클라이언트 | 메시지 | 스키마 | | --- | --- | | `subscribed` | [MarketStreamSubscriptionAck](/api-docs/generated/schemas.md#schema-marketstreamsubscriptionack) | | `unsubscribed` | [MarketStreamSubscriptionAck](/api-docs/generated/schemas.md#schema-marketstreamsubscriptionack) | | `ticker` | [MarketStreamTickerEvent](/api-docs/generated/schemas.md#schema-marketstreamtickerevent) | | `error` | [MarketStreamErrorEvent](/api-docs/generated/schemas.md#schema-marketstreamerrorevent) | ## 개인 WebSocket 연결 `/v1/user/stream` ### 클라이언트 → 서버 | 메시지 | 스키마 | | --- | --- | | `order.create` | [UserStreamCreateOrderCommand](/api-docs/generated/schemas.md#schema-userstreamcreateordercommand) | | `order.cancel` | [UserStreamCancelOrderCommand](/api-docs/generated/schemas.md#schema-userstreamcancelordercommand) | | `order.amend` | [UserStreamAmendOrderCommand](/api-docs/generated/schemas.md#schema-userstreamamendordercommand) | ### 서버 → 클라이언트 | 메시지 | 스키마 | | --- | --- | | `snapshot` | [UserStreamSnapshotEvent](/api-docs/generated/schemas.md#schema-userstreamsnapshotevent) | | `order` | [UserStreamOrderEvent](/api-docs/generated/schemas.md#schema-userstreamorderevent) | | `fill` | [UserStreamFillEvent](/api-docs/generated/schemas.md#schema-userstreamfillevent) | | `balance` | [UserStreamBalanceEvent](/api-docs/generated/schemas.md#schema-userstreambalanceevent) | | `response` | [UserStreamCommandResponse](/api-docs/generated/schemas.md#schema-userstreamcommandresponse) | | `error` | [UserStreamCommandError](/api-docs/generated/schemas.md#schema-userstreamcommanderror) | --- # SDK와 실행 예제 예제의 기본 REST 주소는 `https://api.btxpro.co.kr`입니다. 외부 WS 주소는 `wss://api-ws.btxpro.co.kr`이며, 현재 Go SDK는 운영 REST 주소에서 두 WS 경로를 자동으로 선택합니다. ## Go SDK 현재 SDK는 BTX 저장소의 `backend-base/sdk/btx` 패키지로 제공됩니다. 별도 공개 모듈로 배포된 상태는 아니므로 저장소 접근 권한이 필요하며, 사용할 backend-base 모듈 커밋을 고정해야 합니다. ```go package main import ( "context" "log" "os" btx "git.svc.childlycorp.com/childlycorp/btx-main.git/backend-base/sdk/btx" ) func main() { client, err := btx.NewClient(btx.Config{ BaseURL: "https://api.btxpro.co.kr", APIKey: os.Getenv("BTX_API_KEY"), SecretKey: os.Getenv("BTX_SECRET_KEY"), }) if err != nil { log.Fatal(err) } account, err := client.GetAccount(context.Background()) if err != nil { log.Fatal(err) } log.Printf("account=%d", account.Data.AccountID) } ``` SDK가 REST 요청과 개인 WS 연결에 timestamp·서명을 붙입니다. 별도 nonce 카운터를 운영하지 않습니다. 공개 조회만 사용할 때는 키를 생략할 수 있습니다. | 기능 | 메서드 | | --- | --- | | 시스템·통화·마켓 | CheckHealth, GetReadiness, GetTime, ListCurrencies, ListMarkets, GetMarket | | 시세 | GetTicker, ListTickers, GetOrderBook, ListTrades, ListCandles | | 계정·지갑 | GetAccount, ListWallets, ListBalances | | 주문·체결 | CreateOrder, GetOrder, ListOpenOrders, ListOrderHistory, CancelOrder, CancelOrders, ListFills | | 공개 스트림 | StreamTickers | | 개인 이벤트 | StreamUser | | 양방향 개인 세션 | OpenUserStream → Snapshot, Events, CreateOrder, CancelOrder | Feed API는 REST로 직접 호출합니다. 현재 Go SDK에는 Feed 전용 메서드가 없습니다. ## Node.js와 Python 아래 예제는 표준 라이브러리만 사용하며 기본 동작은 서명된 계정 조회입니다. Node.js 22.12 이상 또는 Python 3.9 이상을 사용하세요. - [Node.js 서명·조회 예제](/api-docs/examples/signed-request.mjs) - [Python 서명·조회 예제](/api-docs/examples/signed_request.py) 먼저 키 없이 서명 구현을 검증합니다. ```sh node signed-request.mjs --self-test python signed_request.py --self-test ``` 비밀 관리 도구가 프로세스에 `BTX_API_KEY`, `BTX_SECRET_KEY`를 주입한 뒤 실행합니다. ```sh node signed-request.mjs python signed_request.py ``` 로컬 서버를 사용할 때는 주소만 변경합니다. ```sh node signed-request.mjs --base-url http://localhost:10005 python signed_request.py --base-url http://localhost:10005 ``` 다른 API에 적용하려면 메서드·경로·쿼리·실제 본문 바이트를 `signRequest` 또는 `sign_request`에 전달하고, 그 값으로 요청을 보냅니다. 두 예제는 운영 주문을 생성하거나 자동 재시도하지 않습니다. ## 개인 WS와 Go 세션 ```go session, err := client.OpenUserStream(ctx) if err != nil { return err } defer session.Close() snapshot := session.Snapshot() // snapshot을 반영한 뒤 session.Events()의 이벤트를 계속 소비합니다. _ = snapshot ``` 주문 전송은 [WS 명령](/api-docs/websocket/commands.md)을 확인하세요. `OpenUserStream`은 결과가 불명확한 주문을 자동으로 재전송하지 않습니다. ## 레퍼런스의 생성 예제 Scalar의 일반 HTTP 예제는 요청 형식을 보여줍니다. 개인 API는 그 요청에 BTX HMAC 서명을 추가해야 합니다. 문서 사이트는 키를 입력받지 않으며 요청 실행 버튼을 제공하지 않습니다. 위 SDK와 로컬 예제로 실제 요청을 검증합니다. --- # 에러와 호출 제한 REST 오류는 HTTP 상태 코드와 `error.code`를 함께 확인합니다. WS 명령 오류는 `event: "error"`의 `error.code`와 명령 `id`를 확인합니다. [오류 응답 형식](/api-docs/guide/conventions.md#rest-responses)을 참고하세요. ## 오류 코드 | HTTP | 코드 | 다음 행동 | | --- | --- | --- | | 400 | INVALID_REQUEST, WALLET_REQUIRED, UNSUPPORTED_OPERATION | 파라미터·walletId·명령 확인 | | 401 | MISSING_AUTH, INVALID_API_KEY | 인증 헤더와 키 상태 확인 | | 401 | INVALID_SIGNATURE | 실제 경로·정렬 쿼리·본문 바이트로 다시 서명 | | 401 | TIMESTAMP_OUT_OF_RANGE | 시간 동기화와 수신 시간 범위 확인 | | 403 | NO_PERMISSION, ORDER_BLOCKED | 키·계정·거래 제한 확인 | | 404 | ENDPOINT_NOT_FOUND, WALLET_NOT_FOUND, MARKET_NOT_FOUND, ORDER_NOT_FOUND | 경로·ID·접근 범위 확인 | | 405 | METHOD_NOT_ALLOWED | 응답 Allow 헤더와 요청 메서드 확인 | | 409 | INVALID_NONCE | 레거시 nonce 형식 확인. 새 구현은 생략 | | 409 | DUPLICATE_COMMAND_ID | 같은 연결에서 처리 중인 명령 ID 확인 | | 413 | PAYLOAD_TOO_LARGE | 본문 크기 축소 | | 422 | MARKET_NOT_TRADING, ORDER_ALREADY_CLOSED, INSUFFICIENT_BALANCE, UNSUPPORTED_ORDER_OPTION | 마켓·주문 상태, 잔고, 주문 옵션 확인 | | 422 | ENGINE_REJECTED_{status} | 엔진 거절 결과 확인. 같은 요청 무조건 재시도 금지 | | 429 | RATE_LIMITED | 읽기는 Retry-After와 백오프 적용 | | 500 | INTERNAL_ERROR | requestId 기록. 읽기만 제한적으로 재시도 | | 501 | AMEND_NOT_SUPPORTED | 원자적 주문 정정 미지원. 원래 주문은 유지 | | 503 | ENGINE_UNAVAILABLE, SERVICE_UNAVAILABLE | 의존성 복구 확인. 쓰기는 주문 상태도 대조 | | 504 | ENGINE_TIMEOUT | 처리 결과 불명. 주문·체결 조회 후 결정 | HTTP 코드와 함께 반환되는 세부 오류는 엔드포인트와 실행 시점에 따라 달라집니다. 검증·권한 오류는 요청을 수정하지 않은 채 반복하지 마세요. ## 호출 제한 현재 환경 설정의 요청 예산은 IP당 **10초에 1000회**입니다. 메모리에서 게이트웨이 인스턴스별로 관리하며 전역 계정 할당량이 아닙니다. 운영 설정이 변경되면 실제 응답의 429와 `Retry-After`를 우선합니다. HTTP 업그레이드와 수신한 WS 명령도 IP 요청 예산을 소비합니다. 서버가 보내는 WS 이벤트는 소비하지 않습니다. 재접속이나 헤더 변경으로 IP 예산을 초기화할 수 없습니다. 일반 429는 IP ban을 의미하지 않으며 위반 점수도 추가하지 않습니다. 외부 API의 JSON·스키마 위반은 IP별로 REST·WS에 공유해 집계하며, 2분 집계 구간에 5회가 되면 10분 동안 차단합니다. 잘못된 WS 프레임·인코딩은 즉시 차단합니다. API 키의 허용 IP 목록에 없는 주소는 HTTP 403 `IP_NOT_ALLOWED`를 받습니다. 키를 발급한 IP 정책을 확인하세요. 이 거절은 위반 점수에 포함하지 않습니다. ## 크기와 시간 제한 | 항목 | 제한 | | --- | --- | | REST 요청 본문 | 1 MiB | | receive window | 기본 5초, 최대 60초 | | 거래 목록 limit | 최대 1000 | | Feed 목록 limit | 기본 20, 최대 100 | | 주문 엔진 응답 대기 | 10초 | | 일괄 취소 | 동시 최대 16개, 배치 전체 10초 | | 공개·개인 WS 명령 크기 | 각각 8 KiB / 16 KiB | WS의 ping/pong·구독·대기열 제한은 [연결 규칙](/api-docs/websocket/overview.md#heartbeat-and-limits)에 있습니다. ## 재시도 정책 읽기의 429는 Retry-After 이후, 일시적인 5xx는 제한된 지수 백오프와 jitter로 재시도합니다. 주문 생성·취소의 연결 종료·타임아웃은 [주문 결과 확인](/api-docs/rest/trading.md#timeouts-and-retries)을 먼저 수행합니다. timestamp 검증은 멱등성을 보장하지 않습니다. --- # 변경 이력 문서에서 사용하는 프로토콜 명세 버전은 **0.4.0**입니다. 주소와 문서 구성을 바꾼 것이 새로운 주문 기능의 추가를 의미하지는 않습니다. ## 2026년 10월 24일 - 외부 REST 운영 주소를 `https://api.btxpro.co.kr`로 정리했습니다. - 외부 공개·개인 WS 운영 주소를 `wss://api-ws.btxpro.co.kr`로 통일했습니다. - REST 전체 엔드포인트, 요청·응답 모델, WS 메시지 모델을 OpenAPI에서 생성하도록 구성했습니다. - 한국어 빠른 시작, HMAC 인증, WS 이벤트·주문·복구 가이드와 Node.js·Python 서명 예제를 추가했습니다. - 현재 Go SDK의 운영 도메인 자동 선택을 새 외부 WS 호스트에 맞췄습니다. 이미 배포한 구버전 SDK는 업데이트하거나 `MarketStreamURL`·`UserStreamURL`을 명시적으로 설정해야 합니다. 신규 도메인의 DNS·TLS·라우팅은 운영 배포 점검 대상입니다. 기존 고객 웹 WS 주소는 이 변경의 대상이 아닙니다. --- # API 레퍼런스 REST와 WebSocket의 전체 계약을 정적 문서로 제공합니다. - [전체 REST 요청과 응답](/api-docs/generated/rest.md) - [요청·응답 데이터 모델](/api-docs/generated/schemas.md) - [WebSocket 메시지 모델](/api-docs/generated/websocket.md) - [OpenAPI 3.1 JSON](/api-docs/openapi.json)