HMAC Authentication can be used for authentication through the coins.ph API using the developer's account.

If you are building a client side application, we recommend using OAuth2 instead. This is because HMAC requires you to use your API secret to sign requests, which you should store in a medium that you control, such as your own server.

You can get your API Key and secret by selecting your application and clicking "show" from the API Access Dashboard.

🚧

Account MFA Whitelist

When making API requests via HMAC authentication on endpoints like POST /v1/sellorder, make sure to request for the whitelisting of your account by emailing [email protected]. Otherwise, you will need to provide an OTP every time you try to send a request to such endpoints.

Signing a request

Each request made with HMAC authentication needs to be signed. To calculate a signature you will need:

  1. API key found in API Access Dashboard
  2. Construct a message according to the following pseudo-grammar: NONCE + URL + BODY
  3. Calculate an HMAC with the message string you just created, your API secret as the key, and SHA256 as the hash algorithm.

The code below demonstrates how to create a proper signature.

import time
import hashlib
import hmac
import requests

# Coins.ph base API url
# Replace with 'https://api.coins.asia' for production system
BASE_URL = 'https://api.coins.asia.stage.coins.systems'

# Coins.ph API key
API_KEY = ''
API_SECRET = ''

url = BASE_URL + '/v1/sellorder'
nonce = str(int(time.time() * 1e6))

# for GET requests body would be empty ''
body = '{"outlet_id": "test_outlet_1"}'

key = API_KEY
message = nonce + url + body
secret = API_SECRET

signature = hmac.new(
  secret.encode('ascii'),
  message.encode(),
  hashlib.sha256,
).hexdigest()

headers = {
    'Access-Signature': signature,
    'Access-Key': key,
    'Access-Nonce': nonce,
    'Content-Type': 'application/json',
    'Accept': 'application/json'
}

response = requests.post(url, headers=headers, data=body)
String nonce = String.valueOf(System.currentTimeMillis());
String message = nonce + url + (body != null ? body : "");

Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(API_SECRET.getBytes(), "HmacSHA256"));
String signature = new String(Hex.encodeHex(mac.doFinal(message.getBytes())));
request.setHeader("ACCESS_KEY", API_KEY);
request.setHeader("ACCESS_SIGNATURE", signature);
request.setHeader("ACCESS_NONCE", nonce);

For an example of how to use this function for an HMAC request, please see the Send funds to an email/phone number tutorial.

Troubleshooting

How to prepare the message?

The message is a result of concatenating the nonce, the URL, and the body. On the other hand, if the body is empty, the message is a result of the concatenation of the nonce and the URL.

# Given the following values:
url = 'https://api.coins.asia.stage.coins.systems/v3/partner-payout-outlet-fees'
nonce = '1591094811411138'
body = '{"outlet_id":"test_outlet_1"}'

# The message is as follows:
message = nonce + url + body

# Which results to:
# 1591094811411138https://api.coins.asia.stage.coins.systems/v3/partner-payout-outlet-fees{"outlet_id":"test_outlet_1"}

How to calculate a signature?

HMAC signature calculation should be available as a library in most popular languages. To do the calculation, it requires a secret, a message and a hash function (in Coins.ph, SHA256 is used).

# Given the following values:
secret = 'ivjtwoYrjPn9NDaSCntGtPfl5BpZ5qD9Mp4WSViDaam7SwU4wV'
message = '1591094811411138https://api.coins.asia.stage.coins.systems/v3/partner-payout-outlet-fees{"outlet_id":"test_outlet_1"}'

# When calculating the signature:
HMAC(message, secret, 'sha256')

# The expected signature should be:
# 89b2922a3aea58026fa4b97381ea8e29a4fb3594ecce6e4d02c98fee7a3066da

I'm still getting HTTP 401 Unauthorized with "Unable to match Access-Signature." error.

If you're signature is still not matching, please double check the following:

  1. Make sure the message is constructed properly.
  2. Make sure the signature is calculated correctly.
  3. Make sure HTTP request nonce that's used in the message is the same as in the headers.
  4. Make sure HTTP request body used in the message is the same as the body sent to Coins.ph API gateway.
  5. Make sure your using the correct pair of API_KEY and API_SECRET.

📘

Request Body Gotcha

Some libraries allows to specify the HTTP body as a raw string (or byte array) and also as an object. When an object is passed, it is then serialized into raw byte array and its serialization might differ from what was used during the signature calculation.

Making Requests

Each HMAC requests expect the following HTTP Headers:

Header NameDescription
ACCESS_KEYSelect show on your chosen application's API Access dashboard. This is the API Key as displayed on the dialog.
ACCESS_SIGNATUREAn HMAC-SHA256 hash of the nonce concatenated with the full URL and body of the HTTP request, signed using your API secret.
ACCESS_NONCEA number that can only be used once per user.

Additional headers may be required depending on the API call you are making. For instance, POST requests require the header Content-Type: application/json, while GET requests do not expect this header.

Use a Nonce

A nonce is used to prevent replay-attacks. Every API call requires a nonce. We expect the nonce to always increase for every request from the same user. The simplest form of nonce you can use is a Unix Epoch timestamp, but feel free to use other forms.

Nonces and Parallel Requests

Since our service is expecting the nonce to increase for every subsequent request, this limits the possibility of executing parallel requests with our API. For instance, consider two requests sent out simultaneously. One request has a higher nonce than the other. If that request is accepted before the one with a lower nonce, the request with the lower nonce will not be accepted. Until this issue is solved, we do not recommend sending parallel requests with HMAC.

Storing Credentials Securely

Always make sure your API Credentials are stored securely, Your api_key, api_secret, and access tokens may be used to access and perform actions in your coins account. In particular, you should avoid storing credentials in your code base and code repositories (like github).

Coins will never ask for your API secret. There is no need to include the API secret on a request.

If there's a need for you to store your secret in a device you don't control (say, a mobile device), it is completely your responsibility to protect the secret. We recommend using encryption and using obfuscation to protect your application from disassemblers and reverse-engineering. Please refer to your chosen platform's documentation for more information.