Authentication

This guide explains how to authenticate your requests when using Upbit’s REST API and WebSocket.

Exchange REST APIs and WebSocket subscription for trading and asset management require API Key-based authentication. This guide provides details on the authentication method and includes implementation examples in various programming languages.

Check the proper endpoint based on your region.
The examples in this page is written using Singapore fiat code(SGD). Set the quote currency to match your region. The base_url differs by country/region. Make sure to specify the correct region value for your environment.

- Singapore (sg): https://sg-api.upbit.com
- Indonesia (id): https://id-api.upbit.com
- Thailand (th): https://th-api.upbit.com

API Key

API Key Issuance

Before starting auth implementation, please refer to the API Key Issuance Guide to issue an API Key and register the caller’s IP addresses in the allowlist. Up to 10 IP addresses can be registered per API Key.

An API Key consists of an Access Key and a Secret Key pair. The Secret Key can only be viewed at the time of issuance. Make sure to keep your Secret Key safe and never expose it to external parties. When generating authentication tokens, you must use the Secret Key that corresponds to the Access Key.

API Key Permission Groups

Upbit API Keys can be configured with specific permissions based on your intended use. If you encounter a permission error while making API calls, please verify that the necessary permissions are assigned to your API Key. For details on each permission group and the supported features, click the box below or refer to the “API Key Permission” section at the bottom of each API Reference page.


Auth Token

An auth token is a string passed with your API requests to verify your identity and access permissions. Upbit APIs use JWT tokens for authentication. When calling auth required private APIs, you must generate a valid JWT token prior to sending the request and include the token in the request header.

Structure of a JWT Token

A JWT consists of three parts: the header, the payload, and the signature. Each part is separated by a dot (.); the header contains information about the algorithm used to generate the signature, the payload contains the body of the content to be verified, and the signature contains the signature value for the payload.

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9. eyJhY2Nlc3Nfa2V5IjoiYTdYZDkyTG1RVzN2QnRSellwTWo1Q3hOS2VUMUh1VnMwZkZnSmNBdyIsIm5vbmNlIjoiYjJmMWUzZjgtMmRjMS00ZDZmLWE4MzgtYzc0YzQ5YjBlMzlhIiwicXVlcnlfaGFzaCI6IjBiM2U4ODRkNDBjYzk5MmE4NTczMGNmNDcwYjRhMzI4NmYxM2Q5YzQ2MjA0Mjc5ZWYzMjE1M2JjZGNkNGVkYjdjMTI5MjVlNzI2NjYzNmU4NmE2ZDZhZTU4MDRhNmJiMzk0ZTYzMmU0ZGJhOWI0MDQ1YWQ0NzBjOTM3MjBlNWU2IiwicXVlcnlfaGFzaF9hbGciOiJTSEE1MTIifQ. jFOftW_qV7loHsaeZj_hrpkP2iEgdK62D9rwseXSGbwvlNaLG2-iJ-WBFUEG7c1tch0AA-jsHsonhEhezd8sTw
{"alg": "HS512", "typ": "JWT"}
{"access_key": "a7Xd92LmQW3vBtRzYpMj5CxNKeT1HuVs0fFgJcAw", "nonce": "b2f1e3f8-2dc1-4d6f-a838-c74c49b0e39a", "query_hash": "0b3e884d40cc992a85730cf470b4a3286f13d9c46204279ef32153bcdcd4edb7c12925e7266636e86a6d6ae5804a6bb394e632e4dba9b4045ad470c93720e5e6", "query_hash_alg": "SHA512"}
HMAC-SHA512(base64UrlEncode(header) + "." + base64UrlEncode(payload), Secret Key)

Header

The header uses a Base64-encoded JSON string with the following structure. The alg field must specify the algorithm used to create the token signature, and HS512(HMAC with SHA-512) is recommended.

{
  "alg": "HS512",
  "typ": "JWT"
}

Payload

The payload uses a Base64-encoded JSON string with the following structure.

Key Description Required / Optional
access_key The Access Key of the API Key. Used to specify the API Key. Required
nonce A random UUID string. To ensure the token value changes with each request even if the same request is repeated, a new value must be provided for every request. Required
query_hash The hash value of the query string from the request's query parameters or body. Required if the API request contains query parameters or a body
query_hash_alg The hash algorithm used to generate the query_hash. Not required if query_hash is not present. The default is SHA512, but if another algorithm was used, it must be specified. Optional
// Example Payload for generating an auth token for REST APIs with parameters or body
{
  "access_key": "a7Xd92LmQW3vBtRzYpMj5CxNKeT1HuVs0fFgJcAw",
  "nonce": "b2f1e3f8-2dc1-4d6f-a838-c74c49b0e39a",
  "query_hash": "0b3e884d40cc992a85730cf470b4a3286f13d9c46204279ef32153bcdcd4edb7c12925e7266636e86a6d6ae5804a6bb394e632e4dba9b4045ad470c93720e5e6",
  "query_hash_alg": "SHA512"
}

// Example Payload for generating an auth token for WebSocket and REST APIs without parameters or body
{
  "access_key": "a7Xd92LmQW3vBtRzYpMj5CxNKeT1HuVs0fFgJcAw",
  "nonce": "b2f1e3f8-2dc1-4d6f-a838-c74c49b0e39a"
}

Signature

The Secret Key of the API Key is used to sign the header and payload. When implementing this in code, it is recommended to use JWT libraries available for each programming language to generate the token.

The Secret Key is not Base64-encoded.
When generating the JWT token signature, there is no need to perform separate Base64 decoding of the key. Please refer to this detail when implementing with JWT libraries.

JWT Generation Guide – How to Generate the query_hash in the Payload

The query_hash value in the payload is a hash of the query string or the JSON body formatted as a query string. If the actual request content or the order of parameters differs from what is included in the authentication token, token validation will fail. Please review the following guidelines carefully:

GET or DELETE REST API Requests

  • The query_hash must be calculated from the actual query string included in the request, without changing the parameter order or re-sorting any elements.
  • When using multiple parameters for array-type query parameters whose names explicitly include [] (e.g., uuids[] or states[]), the query string must be constructed by repeating the key-value pairs, such as uuids[]=UUID1&uuids[]=UUID2...
  • For parameters that do not use brackets (e.g., pairs, quote_currencies) but support multiple values separated by commas, construct the query string as pairs=SGD-BTC,SGD-ETH...
  • The hash must be generated using the non-URL-encoded query string.
Example — When calling the List Open Orders API

  • For a GET request to /v1/orders/open?market=SGD-BTC&limit=10, the query string is market=SGD-BTC&limit=10. The query_hash value is the hash of market=SGD-BTC&limit=10.

  • For a GET request to /v1/orders/open?market=SGD-BTC&states[]=wait&states[]=watch, the query string is market=SGD-BTC&states[]=wait&states[]=watch. The query_hash value is the hash of market=SGD-BTC&states[]=wait&states[]=watch.

  • POST REST API Requests

    • For JSON-formatted request bodies, convert all key-value pairs into a query string format by connecting keys and values with = and separating pairs with &.
    Example — When calling the Create Order API

    For the following request body:
    {
      "market":"SGD-BTC",
      "side":"bid",
      "volume":"0.01",
      "price":"100.0",
      "ord_type":"limit"
    }
    Generate the query string:
    market=SGD-BTC&side=bid&volume=0.01&price=100.0&ord_type=limit and then create the hash value from this string.

    How to Send a JWT Authentication Token

    The generated JWT authentication token must be included in the Authorization header of your request. This applies to both REST API calls and WebSocket connection requests. Use the Bearer token format as shown below:

    • Key: Authorization
    • Value: Bearer {Insert the generated JWT token after the space}

    JWT Token Generation Guide — Code Examples

    Below are example code snippets in various programming languages for generating a JWT token.

    REST API Request Example

    from urllib.parse import quote, unquote, urlencode
    from typing import Any, Dict
    import hashlib
    import uuid
    import jwt  # PyJWT
    import requests
    
    def _build_query_string(params: Dict[str, Any]) -> str:
        """
        Converts dictionary parameters into a query string format.
        """
        return unquote(urlencode(params, doseq=True))
    
    def _create_jwt(access_key: str, secret_key: str, query_string: str = "") -> str:
        """
        Generates a JWT token.
        """
        payload = {"access_key": access_key, "nonce": str(uuid.uuid4())}
    
        if query_string:
            query_hash = hashlib.sha512(query_string.encode("utf-8")).hexdigest()
            payload["query_hash"] = query_hash
            payload["query_hash_alg"] = "SHA512"
    
        token = jwt.encode(payload, secret_key, algorithm="HS512")
        return token if isinstance(token, str) else token.decode('utf-8')  
    
    if __name__ == "__main__":
        base_url = "https://sg-api.upbit.com"
        access_key = "YOUR_ACCESS_KEY"
        secret_key = "YOUR_SECRET_KEY"  # Make sure to load or inject this securely.
        
        # Example request without parameters
        jwt_token = _create_jwt(access_key, secret_key)
        headers = {"Authorization": f"Bearer {jwt_token}"}
                    
        response = requests.get(f"{base_url}/v1/accounts", headers=headers)
        print(response.json())
        
        # Example GET request with parameters
        params = {
            "market": "SGD-BTC",
            "states[]": ["wait", "watch"],
            "limit": 10
        }
        query_string = _build_query_string(params)
        jwt_token = _create_jwt(access_key, secret_key, query_string)
        headers = {"Authorization": f"Bearer {jwt_token}"}
            
        response = requests.get(f"{base_url}/v1/orders/open?{query_string}", headers=headers)
        print(response.json())    
        
        # Example POST request
        order_data = {
            "market": "SGD-BTC",
            "side": "bid",
            "volume": "0.001",
            "price": "5000000",
            "ord_type": "limit"
        }
            
        query_string = _build_query_string(order_data)
        jwt_token = _create_jwt(access_key, secret_key, query_string)
        headers = {
            "Authorization": f"Bearer {jwt_token}",
            "Content-Type": "application/json"
        }
        
        # Uncomment below to place an actual order; verify carefully before execution.
        # response = requests.post(f"{base_url}/v1/orders", json=order_data, headers=headers)
        # print(response.json())
    package com.upbit.openapi.test;
    
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.JWTCreator;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.google.gson.Gson;
    import java.io.IOException;
    import java.math.BigInteger;
    import java.net.URLEncoder;
    import java.nio.charset.StandardCharsets;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;
    import java.util.UUID;
    import okhttp3.MediaType;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.RequestBody;
    import okhttp3.Response;
    
    public class Auth {
    
        private static Gson gson = new Gson();
    
        /**
         * Generates SHA-512 hash of the input string.
         */
        public static String sha512(String input) throws NoSuchAlgorithmException {
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            md.update(input.getBytes(StandardCharsets.UTF_8));
            return HexFormat.of().formatHex(md.digest());
        }
    
        /**
         * Creates JWT token using Access Key, Secret Key, and optional Query String.
         */
        private static String createJwt(String accessKey, String secretKey, String queryString)
            throws NoSuchAlgorithmException {
    
            byte[] secretKeyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
            Algorithm algorithm;
            try {
                algorithm = Algorithm.HMAC512(secretKeyBytes);
            } finally {
                Arrays.fill(secretKeyBytes, (byte) 0);
            }
    
            JWTCreator.Builder builder = JWT.create()
                .withHeader(Collections.singletonMap("alg", "HS512"))
                .withClaim("access_key", accessKey)
                .withClaim("nonce", UUID.randomUUID().toString());
    
            if (queryString != null && !queryString.isEmpty()) {
                String queryHash = sha512(queryString);
                builder.withClaim("query_hash", queryHash);
                builder.withClaim("query_hash_alg", "SHA512");
            }
    
            return builder.sign(algorithm);
        }
    
        /**
         * Converts JSON-formatted request body to query string.
         */
        public static String jsonToQueryString(String jsonString) {
            if (jsonString == null || jsonString.isEmpty()) {
                return "";
            }
    
            Map<String, Object> bodyMap = gson.fromJson(jsonString, Map.class);
            if (bodyMap == null || bodyMap.isEmpty()) {
            }
            return "";
    
            List<String> queryElements = new ArrayList<>();
            for (Map.Entry<String, Object> entry : bodyMap.entrySet()) {
                if (entry.getValue() != null) {
                    try {
                        String encodedKey = URLEncoder.encode(entry.getKey(), "UTF-8")
                            .replace("%5B", "[").replace("%5D", "]");
                        String encodedValue = URLEncoder.encode(String.valueOf(entry.getValue()), "UTF-8");
                        queryElements.add(encodedKey + "=" + encodedValue);
                    } catch (Exception e) {
                        throw new RuntimeException("Encoding failed", e);
                    }
                }
            }
    
            return String.join("&", queryElements);
        }
    
        /**
         * Builds URL-encoded query string from Map<String, Object> parameters.
         */
        public static String buildQueryString(Map<String, Object> params) {
            if (params == null || params.isEmpty()) {
                return "";
            }
    
            List<String> components = new ArrayList<>();
    
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                if (value == null) {
                    continue;
                }
    
                List<Object> values;
                if (value instanceof List) {
                    values = (List<Object>) value;
                } else {
                    values = Collections.singletonList(value);
                }
    
                for (Object val : values) {
                    try {
                        String encodedKey = URLEncoder.encode(
                            key.endsWith("[]") ? key : key + "[]", StandardCharsets.UTF_8)
                            .replace("%5B", "[").replace("%5D", "]");
                        String encodedVal = URLEncoder.encode(String.valueOf(val), StandardCharsets.UTF_8);
                        components.add(encodedKey + "=" + encodedVal);
                    } catch (Exception e) {
                        throw new RuntimeException("Encoding failed", e);
                    }
                }
            }
    
            return String.join("&", components);
        }
    
    
        public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
            String baseUrl = "https://sg-api.upbit.com";
            String accessKey = "YOUR_ACCESS_KEY";
            String secretKey = "YOUR_SECRET_KEY"; // Load or inject securely in production
    
            OkHttpClient client = new OkHttpClient();
    
            // Example GET request with parameters
            Map<String, Object> queryParams = new HashMap<>();
            queryParams.put("states[]", Arrays.asList("wait", "watch"));
            queryParams.put("limit", 100);
    
            String queryString = buildQueryString(queryParams);
            String jwtTokenGet = createJwt(accessKey, secretKey, queryString);
    
            Request getRequest = new Request.Builder()
                .url(baseUrl + "/v1/orders/open?" + queryString)
                .get()
                .addHeader("Accept", "application/json")
                .addHeader("Authorization", "Bearer " + jwtTokenGet)
                .build();
    
            Response response = client.newCall(getRequest).execute();
            System.out.println(response.code());
            System.out.println(Objects.requireNonNull(response.body()).string());
    
            // Example POST request
            final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
            String jsonBody = "{\"market\":\"SGD-BTC\",\"side\":\"bid\",\"volume\":\"0.0001\",\"price\":\"500000\",\"ord_type\":\"limit\"}";
            String queryStringBody = jsonToQueryString(jsonBody);
            String jwtTokenPost = createJwt(accessKey, secretKey, queryStringBody);
    
            Request postRequest = new Request.Builder()
                .url(baseUrl + "/v1/orders")
                .post(RequestBody.create(jsonBody, JSON))
                .addHeader("Accept", "application/json")
                .addHeader("Authorization", "Bearer " + jwtTokenPost)
                .build();
    
            // Uncomment the following lines to place an actual order. Please verify before executing.
            response = client.newCall(postRequest).execute();
            System.out.println(response.code());
            System.out.println(Objects.requireNonNull(response.body()).string());
        }
    }
    const axios = require('axios');
    const crypto = require('crypto');
    const jwt = require('jsonwebtoken');
    const { v4: uuidv4 } = require('uuid');
    const qs = require('querystring');
    
    // Required credentials
    const ACCESS_KEY = 'YOUR_ACCESS_KEY';
    const SECRET_KEY = 'YOUR_SECRET_KEY'; // Manage securely
    const BASE_URL = 'https://sg-api.upbit.com';
    
    /**
     * SHA512 hash function
     */
    function sha512(text) {
      return crypto.createHash('sha512').update(text, 'utf8').digest('hex');
    }
    
    /**
     * JWT token creation
     */
    function createJwt(accessKey, secretKey, queryString = '') {
      const payload = {
        access_key: accessKey,
        nonce: uuidv4(),
      };
    
      if (queryString) {
        payload.query_hash = sha512(queryString);
        payload.query_hash_alg = 'SHA512';
      }
    
      return jwt.sign(payload, secretKey, { algorithm: 'HS512' });
    }
    
    /**
     * GET request example
     */
    async function getOpenOrders() {
      const query = {
        states: ['wait', 'watch'],
        page: 1,
        limit: 10,
      };
    
      const queryString = qs.stringify(query, '&', '=', {
        encodeURIComponent: (str) =>
          str.endsWith('[]') ? encodeURIComponent(str).replace('%5B%5D', '[]') : encodeURIComponent(str),
      });
    
      const token = createJwt(ACCESS_KEY, SECRET_KEY, queryString);
      const headers = {
        Authorization: `Bearer ${token}`,
        Accept: 'application/json',
      };
    
      try {
        const res = await axios.get(`${BASE_URL}/v1/orders/open?${queryString}`, { headers });
        console.log('[GET] Status:', res.status);
        console.log(res.data);
      } catch (err) {
        console.error('[GET] Error:', err.response?.data || err.message);
      }
    }
    
    /**
     * POST request example
     */
    async function placeOrder() {
      const body = {
        market: 'SGD-BTC',
        side: 'bid',
        volume: '0.001',
        price: '500000',
        ord_type: 'limit',
      };
    
      const queryString = qs.stringify(body);
      const token = createJwt(ACCESS_KEY, SECRET_KEY, queryString);
      const headers = {
        Authorization: `Bearer ${token}`,
        Accept: 'application/json',
        'Content-Type': 'application/json',
      };
    
      try {
        // Uncomment the following to place an actual order. Confirm carefully before running.
        // const res = await axios.post(`${BASE_URL}/v1/orders`, body, { headers });
        // console.log('[POST] Status:', res.status);
        // console.log(res.data);
        console.log('[POST] Request prepared but not sent (order disabled for safety).');
      } catch (err) {
        console.error('[POST] Error:', err.response?.data || err.message);
      }
    }
    
    // Main execution
    (async () => {
      await getOpenOrders();
      await placeOrder();
    })();

    Websocket Connection Request Example

    import jwt  # PyJWT
    import uuid
    import websocket  # websocket-client
    
    def on_message(ws, message):
        # do something
        data = message.decode('utf-8')
        print(data)
    
    
    def on_connect(ws):
        print("connected!")
        # Request after connection
        ws.send('[{"ticket":"test example"},{"type":"myOrder"}]')
    
    
    def on_error(ws, err):
        print(err)
    
    
    def on_close(ws, status_code, msg):
      print("closed!")
    
    payload = {
        'access_key': "YOUR_ACCESS_KEY",
        'nonce': str(uuid.uuid4()),
    }
    
    jwt_token = jwt.encode(payload, "YOUR_SECRET_KEY");
    authorization_token = 'Bearer {}'.format(jwt_token)
    headers = {"Authorization": authorization_token}
    
    ws_app = websocket.WebSocketApp("wss://sg-api.upbit.com/websocket/v1/private",
                                    header=headers,
                                    on_message=on_message,
                                    on_open=on_connect,
                                    on_error=on_error,
                                    on_close=on_close)
    ws_app.run_forever()
    package com.upbit.openapi.test;
    
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.algorithms.Algorithm;
    import java.util.UUID;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.Response;
    import okhttp3.WebSocket;
    import okhttp3.WebSocketListener;
    import okio.ByteString;
    import org.jetbrains.annotations.NotNull;
    
    public class AuthWebSocket {
    
        /**
         * Example method to create a JWT Token for WebSocket authentication.
         */
        private static String createJwt(String accessKey, String secretKey) {
            try {
                Algorithm algorithm = Algorithm.HMAC256(secretKey);
                return JWT.create()
                    .withClaim("access_key", accessKey)
                    .withClaim("nonce", UUID.randomUUID().toString()).sign(algorithm);
            } catch (Exception e) {
                throw new RuntimeException("JWT token generation failed", e);
            }
        }
    
        static WebSocketListener createWebSocketListener() {
            return new WebSocketListener() {
                @Override
                public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) {
                    // Implement onOpen event
                    // TODO: Send subscription or data request here
                }
    
                @Override
                public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) {
                    // Implement onMessage event - handle incoming data
                }
    
                @Override
                public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) {
                    // Implement onClosing event
                }
    
                @Override
                public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, Response response) {
                    // Implement onFailure event - handle errors
                }
            };
        }
    
        public static void main(String[] args) {
    
            String accessKey = "YOUR_ACCESS_KEY";
            String secretKey = "YOUR_SECRET_KEY"; // Load or inject securely in production
            OkHttpClient httpClient = new OkHttpClient();
    
            try {
                // Generate JWT token for authentication
                String jwtToken = createJwt(accessKey, secretKey);
    
                // Build WebSocket request with Authorization header
                Request request = new Request.Builder()
                    .url("wss://sg-api.upbit.com/websocket/v1/private")
                    .addHeader("Authorization", "Bearer " + jwtToken)
                    .build();
    
                // Open WebSocket connection
                WebSocket webSocket = httpClient.newWebSocket(request, createWebSocketListener());
    
                // Keep the program running or implement additional logic as needed
    
            } catch (Exception e) {
                throw new RuntimeException("Failed to connect to private WebSocket", e);
            }
        }
    }
    const jwt = require("jsonwebtoken");
    const { v4: uuidv4 } = require("uuid");
    const WebSocket = require("ws");
    
    const payload = {
      access_key: "YOUR_ACCESS_KEY",
      nonce: uuidv4(),
    };
    
    const jwtToken = jwt.sign(payload, "YOUR_SECRET_KEY");
    
    const ws = new WebSocket("wss://sg-api.upbit.com/websocket/v1/private", {
      headers: {
        authorization: `Bearer ${jwtToken}`
      },
    });
    
    ws.on("open", () => {
      console.log("connected!");
      // After connection, send subscription request
      ws.send('[{"ticket":"test example"},{"type":"myOrder"}]');
    });
    
    ws.on("error", console.error);
    
    ws.on("message", (data) => console.log(data.toString()));
    
    ws.on("close", () => console.log("closed!"));