Call Your First Authenticated API

With the Access Key and Secret Key from your issued API Key, you can call authenticated APIs.

Introduction

Once you have issued your API Key, you are ready to generate an authentication token and call the Exchange API. This guide explains how to generate an authentication token using a Shell script and how to call an authenticated API using cURL.

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

Understanding the Authentication Method

Refer to the Authentication documentation for details on the structure and creation of authentication tokens used in Upbit’s REST API and WebSocket. Reviewing the structure and process of token generation in advance will help you proceed smoothly with this guide.


Shell Script for Generating an Authentication Token

While cURL is a powerful HTTP tool, it does not natively support generating tokens or handling hashes and parameters required for Upbit authentication. To address this, this guide shows how to use a Shell script to generate authentication tokens in terminal environments (macOS/Linux shell or Windows cmd/PowerShell).

On Windows, you can’t run shell scripts directly in PowerShell or CMD. Install a Bash environment—such as Git Bash or WSL (Windows Subsystem for Linux)—and run the scripts there. Please refer to one of the setup guides below to configure your Bash environment.

Download and install Git from the official Git for Windows page. Once the installation is complete, a program called Git Bash will be added to your Start menu.
Run PowerShell as an administrator and execute the command below to install WSL.
wsl --install

Once your Bash environment is set up, you can run shell scripts using Bash commands as shown below.

bash auth_curl.sh "curl --request GET --url 'https://{region}-api.upbit.com/v1/accounts' --header 'accept: application/json'"

Before writing and running the Shell script, make sure that both jq and OpenSSL (for cryptography) are installed on your computer. Refer to the OS-specific installation guides below to check your environment.

On most macOS systems, jq and openssl are pre-installed. You can check if they are available by running the following commands in your terminal:

jq --versionopenssl --version
If the version information appears, the utilities are properly installed and ready to use. The version numbers may vary depending on your environment.
If either utility is not installed, you can install it via Homebrew with the following commands:
brew install jqbrew install openssl
In Windows cmd or PowerShell, check if the utilities are installed by running:

jq --versionopenssl --version
If version information is displayed, they are correctly installed and ready for use. Version numbers may differ by environment.
If not installed, follow these steps to set them up:

Install jq
  1. Download the Windows jq binary from https://stedolan.github.io/jq/download/
  2. Save it to a desired folder and add that folder to your system PATH environment variable.
Install openssl
  1. Download the Windows OpenSSL installer from https://slproweb.com/products/Win32OpenSSL.html
  2. After installation, add the directory (e.g., C:Program FilesOpenSSL-Win64in) to your PATH environment variable.
Alternatively, when using a WSL environment, you can install both jq and openssl at once with the following command.
sudo apt updatesudo apt install jq openssl

Copy the Shell script below and save it as a file, such as auth_curl.sh. Be sure to replace ACCESS_KEY and SECRET_KEY with your issued API Key values before saving the file. This script generates an Upbit authentication token and:

  • Accepts a cURL command as an input argument and generates the required authentication header using the API Key and request parameters.
  • Outputs a cURL command with the authentication header included. Copy and execute this command to call the authenticated API.
Secret Key Security
Since your API Key must be stored and managed securely, never share any text or scripts containing the Secret Key with others or upload them online. Make sure to use it only in your local environment for testing purposes.
#!/bin/bash

ACCESS_KEY="YOUR_ACCESS_KEY"
SECRET_KEY="YOUR_SECRET_KEY"

INPUT_CURL=$1

METHOD=$(echo "$INPUT_CURL" | sed -n "s/.*-X \([A-Z]*\).*/\1/p")
URL=$(echo "$INPUT_CURL" | sed -n "s/.*--url '\([^']*\)'.*/\1/p")

BODY=$(echo "$INPUT_CURL" | sed -n "s/.*--data '\([^']*\)'.*/\1/p")

if [[ "$METHOD" == "POST" ]]; then
  QUERY_STRING=$(echo "$BODY" | tr -d '{}' | sed 's/\"//g' | tr ',' '&' | tr ':' '=' | sed 's/ //g')
elif [[ "$METHOD" == "GET" || "$METHOD" == "DELETE" ]]; then
  QUERY_STRING=$(echo "$URL" | awk -F '?' '{print $2}')
fi

if [ -z "$QUERY_STRING" ]; then
  QUERY_HASH=""
else
  QUERY_HASH=$(echo -n "$QUERY_STRING" | openssl dgst -sha512 | sed 's/^.* //')
fi

NONCE=$(uuidgen)
HEADER='{"alg":"HS512","typ":"JWT"}'
PAYLOAD=$(jq -n --arg ak "$ACCESS_KEY" --arg n "$NONCE" --arg qh "$QUERY_HASH" --arg alg "SHA512" \
  '{access_key: $ak, nonce: $n, query_hash: $qh, query_hash_alg: $alg}')

HEADER_BASE64=$(echo -n "$HEADER" | openssl base64 -A | tr '+/' '-_' | tr -d '=')
PAYLOAD_BASE64=$(echo -n "$PAYLOAD" | openssl base64 -A | tr '+/' '-_' | tr -d '=')

SIGNATURE=$(echo -n "$HEADER_BASE64.$PAYLOAD_BASE64" | \
  openssl dgst -sha512 -hmac "$SECRET_KEY" -binary | \
  openssl base64 -A | tr '+/' '-_' | tr -d '=')

JWT="$HEADER_BASE64.$PAYLOAD_BASE64.$SIGNATURE"

CLEANED_CURL=$(echo "$INPUT_CURL" | sed "s/-H 'Authorization: Bearer [^']*'//g")

if echo "$CLEANED_CURL" | grep -q "Content-Type"; then
    FINAL_CURL=$(echo "$CLEANED_CURL" | sed "s/curl /curl -H 'Authorization: Bearer $JWT' /")
else
    FINAL_CURL=$(echo "$CLEANED_CURL" | sed "s/curl /curl -H 'Authorization: Bearer $JWT' -H 'Content-Type: application\/json' /")
fi

echo "[+] Signed curl command:"
echo "$FINAL_CURL"

Since utilities such as jq and openssl are used in the process of generating an authentication token, you need to grant execute permissions in macOS and other UNIX-based environments by running the following command.

chmod +x auth_curl.sh

Get Account Balance

As your first authenticated API call, let’s query your account balance using the Get Account Balances. Pass the cURL command for this API as an argument to the saved Shell script. You can get the example cURL request for this API in the Reference section.

% ./auth_curl.sh "curl --request GET --url https://{region}-api.upbit.com/v1/accounts --header 'accept: application/json'"

[+] Signed curl command:
curl -H 'Authorization: Bearer eyJhbGciO...TvcqiPUoNTg' --request GET --url https://{region}-api.upbit.com/v1/accounts --header 'accept: application/json'

The script outputs a cURL command with the authentication header. Copy and run the command in your terminal to see a response like the following:

[{"currency": "{fiat}","balance": "10000.0","locked": "0.0","avg_buy_price": "0","avg_buy_price_modified": false,"unit_currency": "{fiat}"},{"currency": "BTC","balance": "2.0","locked": "0.0","avg_buy_price": "1400000","avg_buy_price_modified": false,"unit_currency": "{fiat}"}]

Creating a Bid Order

Now let’s try a POST request to place a buy order. For example, you can place a limit buy order at a sufficiently low price in the {fiat}-BTC market. Pass the following cURL request (for Create Order) to the Shell script. You can get back a cURL with the authentication token included. (The JWT part is abbreviated as ...)

% ./auth_curl.sh "curl -X POST --url 'https://{region}-api.upbit.com/v1/orders' --header 'accept: application/json' --header 'content-type: application/json' --data '{\"market\":\"{fiat}-BTC\",\"side\":\"bid\",\"volume\":\"0.0001\",\"price\":\"500000\",\"ord_type\":\"limit\"}'"

[+] Signed curl command:
curl -H 'Authorization: Bearer eyJhbGciOi...a0uejONDLQ' -X POST --url 'https://{region}-api.upbit.com/v1/orders' --header 'accept: application/json' --header 'content-type: application/json' --data '{"market":"{fiat}-BTC","side":"bid","volume":"0.0001","price":"500000","ord_type":"limit"}'

Copy the generated cURL command, paste it in your terminal, and execute it to place the order in the {fiat}-BTC market.

Executing the above cURL request will place a real order.
Cryptocurrency prices are highly volatile, and the order could be filled. Run this test only if you intend to create an actual order. Any open orders can be canceled via the Upbit service or the Cancel Order API.

Understanding Authentication Token Generation

The following lines in the provided Shell script generate a JWT token:

if [ -z "$QUERY_STRING" ]; then
  QUERY_HASH=""
else
  QUERY_HASH=$(echo -n "$QUERY_STRING" | openssl dgst -sha512 | sed 's/^.* //')
fi

NONCE=$(uuidgen)
HEADER='{"alg":"HS512","typ":"JWT"}'
PAYLOAD=$(jq -n --arg ak "$ACCESS_KEY" --arg n "$NONCE" --arg qh "$QUERY_HASH" --arg alg "SHA512" \
  '{access_key: $ak, nonce: $n, query_hash: $qh, query_hash_alg: $alg}')

HEADER_BASE64=$(echo -n "$HEADER" | openssl base64 -A | tr '+/' '-_' | tr -d '=')
PAYLOAD_BASE64=$(echo -n "$PAYLOAD" | openssl base64 -A | tr '+/' '-_' | tr -d '=')

SIGNATURE=$(echo -n "$HEADER_BASE64.$PAYLOAD_BASE64" | \
  openssl dgst -sha512 -hmac "$SECRET_KEY" -binary | \
  openssl base64 -A | tr '+/' '-_' | tr -d '=')

JWT="$HEADER_BASE64.$PAYLOAD_BASE64.$SIGNATURE"

This code hashes the query string, then creates a JWT header, payload, and signature following Upbit’s authentication token format. You can see that the payload includes the fields access_key, nonce, query_hash, and query_hash_alg.

For POST requests with no query string, the script converts the JSON body into a query string, hashes it, and then creates the authentication token in the same way as for GET requests:

What is URL Encoding?
URL encoding is an encoding method that converts characters that cannot be included in a URL within a communication protocol into transmittable characters. Target characters, including special characters, are converted during encoding into a string consisting of a percent sign (%) followed by two hexadecimal digits.

(Example) : is encoded as %3A and + is encoded as %2B.

BODY=$(echo "$INPUT_CURL" | sed -n "s/.*--data '\([^']*\)'.*/\1/p")

if [[ "$METHOD" == "POST" ]]; then
  QUERY_STRING=$(echo "$BODY" | tr -d '{}' | sed 's/"//g' | tr ',' '&' | tr ':' '=' | sed 's/ //g')
elif [[ "$METHOD" == "GET" || "$METHOD" == "DELETE" ]]; then
  QUERY_STRING=$(echo "$URL" | awk -F '?' '{print $2}')
fi

Wrapping Up

We used cURL to make quick calls to the Upbit API. After you’ve tested enough to understand the API, set up a real development environment to implement your trading strategy. See the Development Environment Setup Guide to configure your language environment instead of cURL, or read REST API Integration Best Practices for more advanced integration patterns.