On this pageHMAC-SHA256 Signing ProcessStep 1: Generate Request MetadataStep 2: Build the Signing StringStep 3: Compute the SignatureStep 4: Set Request HeadersCode ExamplesAccess Sign (Body-Level Signing)Endpoint Authentication Methods

Authentication ​

HashNut uses HMAC-SHA256 signatures to authenticate API requests. Some endpoints use header-based signing, while others use an accessSign field in the request body.

HMAC-SHA256 Signing Process ​

The signing process consists of four steps:

Step 1: Generate Request Metadata ​

Generate a UUID and a Unix timestamp (seconds) for each request.

Step 2: Build the Signing String ​

Concatenate the three components without any separator:

signString = uuid + timestamp + requestBody

Where requestBody is the JSON string of the request body.

Step 3: Compute the Signature ​

Compute HMAC-SHA256 using your Secret Key, then Base64-encode the result:

signature = base64( hmac_sha256( secretKey, signString ) )

Step 4: Set Request Headers ​

Include the following headers in your HTTP request:

HeaderDescription
hashnut-request-uuidThe UUID generated in Step 1
hashnut-request-timestampThe Unix timestamp generated in Step 1
hashnut-request-signThe Base64-encoded HMAC-SHA256 signature
Content-TypeMust be application/json

Code Examples ​

java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.UUID;

public class HashNutSign {
    public static String[] sign(String secretKey, String body) throws Exception {
        String reqUUID = UUID.randomUUID().toString();
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);

        String signString = reqUUID + timestamp + body;

        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(secretKey.getBytes(), "HmacSHA256"));
        String signature = Base64.getEncoder().encodeToString(
                mac.doFinal(signString.getBytes()));

        return new String[]{reqUUID, timestamp, signature};
    }
}
go
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"time"

	"github.com/google/uuid"
)

func sign(secretKey, body string) (reqUUID, timestamp, signature string) {
	reqUUID = uuid.New().String()
	timestamp = fmt.Sprintf("%d", time.Now().Unix())

	signString := reqUUID + timestamp + body

	mac := hmac.New(sha256.New, []byte(secretKey))
	mac.Write([]byte(signString))
	signature = base64.StdEncoding.EncodeToString(mac.Sum(nil))

	return reqUUID, timestamp, signature
}
js
const crypto = require('crypto');
const { v4: uuidv4 } = require('uuid');

function sign(secretKey, body) {
  const reqUUID = uuidv4();
  const timestamp = Math.floor(Date.now() / 1000).toString();

  const signString = reqUUID + timestamp + body;

  const signature = crypto
    .createHmac('sha256', secretKey)
    .update(signString)
    .digest('base64');

  return { reqUUID, timestamp, signature };
}
python
import hmac
import hashlib
import base64
import uuid
import time

def sign(secret_key: str, body: str):
    req_uuid = str(uuid.uuid4())
    timestamp = str(int(time.time()))

    sign_string = req_uuid + timestamp + body

    signature = base64.b64encode(
        hmac.new(
            secret_key.encode(),
            sign_string.encode(),
            hashlib.sha256
        ).digest()
    ).decode()

    return req_uuid, timestamp, signature

Access Sign (Body-Level Signing) ​

Some endpoints (such as Query Order and Confirm Paid) use a simplified signing method where the signature is included in the request body as the accessSign field instead of in headers.

The accessSign is computed as:

accessSign = base64( hmac_sha256( secretKey, requestBodyWithoutAccessSign ) )

Where requestBodyWithoutAccessSign is the JSON string of the request body before the accessSign field is added.

Endpoint Authentication Methods ​

EndpointAuth MethodDescription
POST /v4.0.0/pay/orders/apiHeader signingCreate order
POST /v4.0.0/pay/orders/cancel/apiHeader signingCancel order
POST /v4.0.0/pay/orders/queryBody accessSignQuery order
POST /v4.0.0/pay/orders/confirmBody accessSignConfirm paid
POST /v4.0.0/pay/orders/supplementsBody accessSignQuery supplements
POST /v4.0.0/config/*NonePublic config endpoints

TIP

If you use the Go SDK, signing is handled automatically. You only need to provide your Access Key ID and Secret Key when initializing the client.