Markdown 원본 보기 ↗

REST API#

REST 요청 규칙#

서명 입력 예시 (query + body 결합):

timestamp=1719232467910symbol=btc_krw

Rate Limit#

응답 헤더로 잔여 quota를 추적합니다.

API 그룹 제한
공개 REST IP당 초당 50 요청
주문 신청 계정당 초당 30 요청
주문 취소 계정당 초당 30 요청
입출금 신청 계정당 초당 5 요청
그 외 비공개 REST 계정당 초당 50 요청

HTTP 429를 받으면 Retry-After 또는 Ratelimit reset 시점까지 기다린 뒤 재시도합니다.

Timestamp 검증 윈도우#

비공개 요청에는 다음을 포함합니다.

서버는 다음 조건을 만족할 때에만 요청을 수락합니다.

serverTime - timestamp <= recvWindow
timestamp < serverTime + 1000

클라이언트 시각이 어긋나면 EXCEED_TIME_WINDOW 오류가 반환됩니다. 이 윈도우는 비대칭입니다 — recvWindow는 과거 방향만 넓히고, 미래 경계는 recvWindow로 넓힐 수 없는 고정 +1000 ms입니다 — 따라서 시각이 서버보다 조금이라도 앞서면 모든 서명 요청이 실패하며 recvWindow를 키워도 소용이 없습니다. 원시 호스트 시각이 아니라 Korbit 서버 시각(GET /v2/time)을 기준으로 서명하세요. 복원력 recipe 6을 참고하세요.

HMAC-SHA256 헬퍼#

Node.js 예제. 실제로 전송할 URLSearchParams를 그대로 서명한 뒤 signature를 덧붙입니다.

import crypto from "node:crypto";

const BASE_URL = "https://api.korbit.co.kr";
const apiKey = process.env.KORBIT_API_KEY;
const apiSecret = process.env.KORBIT_API_SECRET;

function signHmac(encodedParams) {
  return crypto.createHmac("sha256", apiSecret).update(encodedParams, "utf8").digest("hex");
}

async function korbitPrivate(method, path, params = {}) {
  const clean = Object.fromEntries(
    Object.entries(params).filter(([, v]) => v !== undefined && v !== null && v !== "")
  );
  const p = new URLSearchParams({ ...clean, timestamp: String(Date.now()) });
  const signature = signHmac(p.toString());
  p.append("signature", signature);

  const headers = { "X-KAPI-KEY": apiKey };
  let url = `${BASE_URL}${path}`;
  const init = { method, headers };
  if (method === "GET" || method === "DELETE") {
    url += `?${p.toString()}`;
  } else {
    headers["Content-Type"] = "application/x-www-form-urlencoded";
    init.body = p.toString();
  }

  const res = await fetch(url, init);
  const json = await res.json().catch(() => ({}));
  if (!res.ok || json.success === false) {
    const err = new Error(`Korbit API error ${res.status}`);
    err.status = res.status;              // 숫자 HTTP 상태 코드
    err.code = json?.error?.message;      // 심볼릭 코드, 예: "DUPLICATE_CLIENT_ORDER_ID"
    err.body = json;
    throw err;
  }
  return json.data ?? json;
}

실패 시 Korbit은 { "success": false, "error": { "code": <httpStatus>, "message": "<symbolic code>" } }를 반환합니다. 분기 판단에 쓰는 심볼릭 코드(EXCEED_TIME_WINDOW, DUPLICATE_CLIENT_ORDER_ID, NO_BALANCE 등)는 error.message이며, error.code아닙니다error.code는 숫자 HTTP 상태 코드가 반복된 값입니다. 최상위에는 심볼릭 값이 없습니다. 위 헬퍼는 이 심볼릭 코드를 err.code로 노출하므로 호출부는 그 값으로 분기하면 됩니다.

ED25519 헬퍼#

개인키는 PEM 문자열로 소스 외부에 보관합니다.

import crypto from "node:crypto";

const apiKey = process.env.KORBIT_API_KEY;
const privateKeyPem = process.env.KORBIT_ED25519_PRIVATE_KEY;

function signEd25519(encodedParams) {
  const sig = crypto.sign(null, Buffer.from(encodedParams), privateKeyPem);
  return sig.toString("base64");
}

URLSearchParams에 Base64 서명을 append 하면 URL 인코딩이 자동으로 적용됩니다.

주문 넣기#

POST /v2/orderssymbol, side(buy/sell), orderType을 보냅니다. 주문 크기를 지정하는 필드는 주문 유형에 따라 다르며, 이 부분이 가장 흔한 실수 지점이므로 정확히 맞춰야 합니다:

orderType 필수 사이징 필드 생략
limit price qty amt
market / best 매수(buy) amt(상대자산 매수 금액 — quote currency, symbol의 두 번째 항목) price, qty
market / best 매도(sell) qty(기준자산 수량 — base currency, symbol의 첫 번째 항목) price, amt

즉, btc_krw를 50,000 KRW어치 시장가 매수할 때는 amt=50000을 보내고 qtyprice보내지 않습니다. amt는 해당 페어의 상대자산 단위입니다. 0.01 BTC 시장가 매도는 qty=0.01만 보내고 amt/price는 생략합니다. best(BBO) 주문은 추가로 timeInForcebestNth가 필요합니다.

clientOrderId([0-9a-zA-Z.:_-]{1,36} 형식)를 넣으면 멱등성이 보장됩니다. 같은 clientOrderId로 여러 번 요청해도 한 번만 처리되며, 이후 GET /v2/orders?clientOrderId=...로 조회할 수 있습니다. 주문이 성공하면 부여된 orderId가 반환되며, 주문의 나머지 상태는 후속 GET /v2/orders로 읽습니다(아래 참고). clientOrderId는 사실상 해제되지 않으므로, 서로 다른 주문에 같은 ID를 재사용하지 말고 신청마다 충돌에 강한 ID를 새로 발급해 영속화하세요 — 리질리언스 #1 참고.

주문 및 체결 읽기#

GET /v2/orders(orderId 또는 clientOrderId로 조회)는 체결 상태를 포함한 주문 정보를 반환합니다. 금액 필드는 문자열이므로 문자열/decimal로 유지하세요.

필드 의미 비고
qty 주문 수량 시장가 매수(=amt로 사이징)에서는 없음
amt 매수 금액(시장가 매수) 상대자산, 예: KRW
filledQty 체결된 수량 체결 전에는 "0"
filledAmt 체결된 상대자산 금액 예: 사용/수령한 KRW
avgPrice 평균 체결가 선택적 — 체결이 생기기 전에는 없음. 가드 없이 읽지 말 것
status 주문 상태 아래 주문 상태 참고(partiallyFilled 등)

체결을 안전하게 다루려면 avgPrice가 없을 수 있다고 보고(필요하고 없을 때는 filledAmt / filledQty를 decimal로 계산해 도출하며, "미체결"은 평균가 없음으로 처리 — 절대 NaN이 되지 않게), 미체결 잔량은 qty - filledQty로 계산하되 음수가 되지 않게 합니다. partiallyFilled 주문은 filledQtyqty보다 작으므로, 후속 동작은 원래 요청 수량이 아니라 filledQty/filledAmt 기준으로 사이징하세요.

잔고#

GET /v2/balance(선택적으로 currencies=btc,eth)는 자산별 객체 배열을 반환합니다. 모든 수량은 문자열입니다:

필드 의미
currency 자산명, 예: krw, btc
balance 총합 = available + tradeInUse + withdrawalInUse
available 지금 즉시 거래/출금 가능한 수량
tradeInUse 미체결 주문에 묶인 수량
withdrawalInUse 출금 대기에 묶인 수량
avgPrice 평균 매수가(선택적)

신규 주문은 balance가 아니라 available 기준으로 사이징하세요 — 그 차이는 이미 미체결 주문이나 출금에 묶여 있습니다.

REST 엔드포인트#

아래 표는 YAML 스펙의 그룹 순서대로 정리되어 있습니다. 각 엔드포인트의 필수 파라미터와 응답 스키마는 본 문서 하단에 링크된 그룹별 레퍼런스 파일에서 확인하세요.

시세#

Method 경로 권한 용도
GET /v2/tickers (공개) 하나 또는 여러 거래쌍의 현재가(Ticker) 정보를 조회합니다.
GET /v2/orderbook (공개) 단일 거래쌍의 호가 정보를 조회합니다.
GET /v2/trades (공개) 최근 체결 내역을 조회합니다.
GET /v2/candles (공개) 시세 캔들스틱 정보를 조회합니다.
GET /v2/currencyPairs (공개) 거래지원 거래쌍 목록을 각 거래쌍의 통화 구성 및 주문금액 한도와 함께 조회합니다.
GET /v2/tickSizePolicy (공개) 지정한 거래쌍의 호가 정책 및 오더북 모아보기 단위를 조회합니다.

주문#

Method 경로 권한 용도
GET /v2/orders readOrders 주문 ID(orderId) 또는 사용자 지정 주문 ID(clientOrderId)를 이용해 개별 주문 정보를 조회합니다.
GET /v2/openOrders readOrders 단일 거래쌍의 미체결 주문 목록을 조회합니다.
GET /v2/allOrders readOrders 단일 거래쌍의 최근 주문 목록을 조회합니다. 주문 생성 시각 기준으로 최근 36시간의 주문 내역만 조회 가능합니다.
GET /v2/myTrades readOrders 단일 거래쌍의 최근 체결 목록을 조회합니다. 최근 36시간의 체결 내역만 조회 가능합니다.
POST /v2/orders writeOrders 신규 주문을 생성합니다.
DELETE /v2/orders writeOrders 주문 취소 요청을 전송합니다.

자산#

Method 경로 권한 용도
GET /v2/balance readBalances 내가 가지고 있는 자산 목록을 조회합니다.

가상자산 입금#

Method 경로 권한 용도
GET /v2/coin/depositAddresses readDeposits 가상자산 입금 주소 목록을 조회합니다.
GET /v2/coin/depositAddress readDeposits 개별 가상자산의 입금 주소를 조회합니다.
POST /v2/coin/depositAddress writeDeposits 가상자산을 입금할 주소를 발급합니다. 입금 주소가 이미 존재한다면 신규 발급 없이 기존 입금 주소를 응답합니다.
GET /v2/coin/recentDeposits readDeposits 최근 가상자산 입금 내역을 조회합니다.
GET /v2/coin/deposit readDeposits 가상자산 입금 진행 상태를 조회합니다.

가상자산 출금#

Method 경로 권한 용도
GET /v2/coin/withdrawableAddresses readWithdrawals API 출금 가능 주소로 등록된 주소를 조회합니다.
GET /v2/coin/withdrawableAmount readWithdrawals 출금 가능 수량을 조회합니다.
POST /v2/coin/withdrawal writeWithdrawals 가상자산 출금을 요청합니다. 출금 API를 사용하기 위해서는, 코빗 개발자센터에서 API 출금 허용주소 등록이 필요합니다.
DELETE /v2/coin/withdrawal writeWithdrawals 가상자산 출금을 취소합니다.
GET /v2/coin/recentWithdrawals readWithdrawals 최근 가상자산 출금내역을 조회합니다.
GET /v2/coin/withdrawal readWithdrawals 요청한 출금의 진행 상황을 조회합니다.

원화 입출금#

Method 경로 권한 용도
POST /v2/krw/sendKrwDepositPush writeDeposits 코빗 모바일 앱으로 원화 입금 요청 알림을 전송합니다.
POST /v2/krw/sendKrwWithdrawalPush writeWithdrawals 코빗 모바일 앱으로 원화 출금 요청 알림을 전송합니다.
GET /v2/krw/recentDeposits readDeposits 최근 KRW 입금 내역을 조회합니다.
GET /v2/krw/recentWithdrawals readWithdrawals 최근 KRW 출금내역을 조회합니다.

기타#

Method 경로 권한 용도
GET /v2/currencies (공개) 가상자산 정보를 조회합니다.
GET /v2/time (공개) 서버 시각을 조회합니다.
GET /v2/tradingFeePolicy readOrders 현재 회원 계정에 적용되는 거래수수료율을 조회합니다.
GET /v2/currentKeyInfo 서명 (권한 무관) 현재 사용중인 API 키의 정보를 조회합니다.
GET /v2/notices (공개) 최근 공지사항 20건을 최신순으로 조회합니다.
GET /v2/marketAlerts (공개) 거래쌍별 시장경보제 발동현황을 조회합니다. 현재 경보가 발동된 거래쌍만 반환됩니다.

주문 상태#

설명
pending 주문 접수 대기 중. 잔고가 부족하거나 timeInForce 조건에 해당할 경우, 주문이 실패해 expired 상태로 될 수 있습니다.
open 전량 미체결
filled 체결 완료 후 주문 종료. 미체결 잔량이 오더북에 남지 않고 반환되는 주문(예: ioc 주문, 가격 보호(pp) 범위로 잔량이 잘린 주문)은 주문 수량보다 적게 체결된 경우에도 filled로 종료됩니다. 실제 체결 수량은 filledQty/filledAmt로 확인하세요.
canceled 전량 취소
partiallyFilled 부분 체결
partiallyFilledCanceled 부분 체결 후 잔량 취소
expired 주문 접수 실패 (잔고 부족 또는 timeInForce 조건 해당 시)

오류 코드#

오류 코드 발생 상황 경로
BAD_REQUEST 잘못된 입력입니다. POST /v2/orders
CANNOT_CANCEL_WITHDRAWAL 출금 취소가 불가능합니다. (출금 처리가 이미 시작된 경우 등) DELETE /v2/coin/withdrawal
DAILY_LIMIT_EXCEEDED 일일 출금 한도를 초과했습니다. POST /v2/coin/withdrawal
DUPLICATE_CLIENT_ORDER_ID 중복된 clientOrderId입니다. POST /v2/orders
FORBIDDEN_WITHDRAWAL_ADDRESS 코빗 정책에 따라 출금이 불가능한 주소입니다. POST /v2/coin/withdrawal
INVALID_CURRENCY 잘못된 가상자산 심볼입니다. POST /v2/coin/withdrawal
INVALID_CURRENCY_PAIR 잘못된 거래쌍입니다. POST /v2/orders
INVALID_USER_STATUS 거래가 제한된 계정입니다. 코빗 웹사이트 또는 고객센터를 통해 상태를 확인하세요. POST /v2/coin/withdrawal, POST /v2/orders
NOT_FOUND 출금 정보가 존재하지 않습니다. DELETE /v2/coin/withdrawal
NO_BALANCE 잔고가 부족합니다. POST /v2/coin/withdrawal, POST /v2/orders
ONLY_SELL_LIMIT_ORDERS_ALLOWED 거래지원 직후에는 지정가 매도 주문만 가능합니다. POST /v2/orders
ORDER_ALREADY_CANCELED 지정한 주문이 이미 취소되었습니다. DELETE /v2/orders
ORDER_ALREADY_EXPIRED 지정한 주문은 실패 처리된 주문입니다. DELETE /v2/orders
ORDER_ALREADY_FILLED 지정한 주문이 이미 전량 체결되었습니다. DELETE /v2/orders
ORDER_NOT_FOUND 지정한 주문 ID가 존재하지 않습니다. DELETE /v2/orders
ORDER_VALUE_TOO_LARGE 주문 최대 금액 초과입니다. 주문금액 한도는 마켓별로 정해지며 해당 거래쌍의 상대자산 단위입니다. GET /v2/currencyPairsmaxOrderValue, quoteCurrency를 참고하세요. 수량*가격(또는 amt)을 한도 이하로 변경해 주세요. POST /v2/orders
ORDER_VALUE_TOO_SMALL 주문 최소 금액 미달입니다. 주문금액 한도는 마켓별로 정해지며 해당 거래쌍의 상대자산 단위입니다. GET /v2/currencyPairsminOrderValue, quoteCurrency를 참고하세요. 수량*가격(또는 amt)을 한도 이상으로 변경해 주세요. POST /v2/orders
PRICE_OVER_UPPER_BOUND 거래지원 직후에는 특정한 가격 초과의 호가를 입력할 수 없습니다. POST /v2/orders
PRICE_TICK_SIZE_INVALID 지정가 입력 단위가 올바르지 않습니다. POST /v2/orders
PRICE_UNDER_LOWER_BOUND 거래지원 직후에는 특정한 가격 미만의 호가를 입력할 수 없습니다. POST /v2/orders
TOO_MANY_OPEN_ORDERS 미체결 주문 개수 제한을 초과했습니다. POST /v2/orders
TRY_AGAIN 주문 접수 처리중입니다. 잠시 후 다시 시도해 주세요. DELETE /v2/orders
UNREGISTERED_WITHDRAWAL_ADDRESS Open API 출금 허용 주소로 등록되어 있지 않은 주소입니다. POST /v2/coin/withdrawal
WITHDRAWAL_ALREADY_FINISHED 출금이 이미 완료되었습니다. DELETE /v2/coin/withdrawal
WITHDRAWAL_ALREADY_IN_PROGRESS 이미 출금 진행 중입니다. 다른 출금 건이 완료된 후 다시 시도해 주세요. POST /v2/coin/withdrawal
WITHDRAWAL_SUSPENDED 출금이 중단된 상태입니다. POST /v2/coin/withdrawal