API Authentication
The Cycle payment platform validates API requests with an HMAC signature. Only requests with a correct signature are allowed to access system resources.
API Caller Credentials
You will receive these credentials when your merchant account is created. If you don’t have them, please contact your account manager.
| Name | Description |
|---|---|
| Merchant Account Name | Assigned by Cycle. The unique merchant account name. |
| Caller Name | Assigned by Cycle. The API caller ID. |
| Caller Password | Assigned by Cycle. The API caller password, used as the encrypted secret for the HMAC signature. |
Request Security Headers
These HTTP request header values are required for each API call to the Cycle platform. Without them, the request will be treated as unauthorised.
| Header Name | Description |
|---|---|
X-MerchantAccount | The Merchant Account name assigned to you. |
X-CallerName | The name of the API Caller making the request. |
X-HMAC-Timestamp | Unix timestamp (seconds from epoch). Signatures with timestamps more than 30 minutes old are rejected. |
X-HMAC-Signature | The generated HMAC signature. |
Generate the Signature
The signature can be generated as follows (pseudo-code):
var timestamp = seconds_from_epoch_utc
var message = string_concat(callerName, merchantAccountName, timestamp, request_path, request_body)
var signature = hmac_sha256_as_hexadecimal(api_secret, message)
Example
As a concrete example, suppose we have the following:
X-CallerName= "cycle-api-caller"X-MerchantAccount= "CycleDemo"X-HMAC-Timestamp= "1633767872"Caller's password= "YOUR_CALLER_PASSWORD"- Request URL = "https://sandbox.cyclepay.net/api/v3/healthcheck"
The message to be signed would be:
"cycle-api-callerCycleDemo1633767872/api/v3/healthcheck"
The final request would look like this:
curl --location --request GET 'https://sandbox.cyclepay.net/api/v3/healthcheck' \
--header 'X-MerchantAccount: CycleDemo' \
--header 'X-CallerName: cycle-api-caller' \
--header 'X-HMAC-Timestamp: 1633767872' \
--header 'X-HMAC-Signature: 2A5B9C3D...' \
--header 'Content-Type: application/json'
You will receive an HTTP 200 status with an empty response if your signature is correct. If the signature is wrong, you will see this error message:
{"requestId":"44d123b4-5cdc-4522-908b-3d5765addbf3","errorCode":"authentication_error","message":"HMAC Authentication failed. Invalid name or password"}
HMAC Signature Code Examples
Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;
/**
* @param requestPath, the request context path, e.g "/api/v3/charges"
* @param requestBody: the request body content
* @return The HMAC signature
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public String calculateHMAC(String requestPath, String requestBody) throws NoSuchAlgorithmException, InvalidKeyException {
// Use your configured values
String apiSecret = "YOUR_CALLER_PASSWORD";
String merchantAccount = "CycleDemo";
String callerName = "cycle-api-caller";
long timestamp = System.currentTimeMillis() / 1000;
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(apiSecret.getBytes(), "HmacSHA256");
mac.init(keySpec);
StringBuilder message = new StringBuilder().append(callerName).append(merchantAccount);
message.append(timestamp);
if (requestPath != null && requestPath.trim().length() > 0) {
message.append(requestPath);
}
if (requestBody != null && requestBody.trim().length() > 0) {
message.append(requestBody);
}
byte[] signatureBytes = mac.doFinal(message.toString().getBytes());
return org.apache.commons.codec.binary.Hex.encodeHexString(signatureBytes).toUpperCase(Locale.ROOT);
}
JavaScript
// message = X-CallerName + X-MerchantAccount + X-HMAC-Timestamp + path + body
var timestamp = Math.floor(new Date().getTime() / 1000);
var path = pm.request.url.getPath();
var message = environment['caller'] + environment['merchant'] + timestamp + path + (pm.request.body.raw || "");
var secret = environment['password'];
var signature = CryptoJS.HmacSHA256(message, secret).toString().toUpperCase();