Generate HMAC-SHA256 signatures to authenticate Neutron API requests. Includes code samples in Node.js, Python, Go, C#, and Java.
All Neutron API requests are authenticated using HMAC-SHA256 signatures. This page explains how to generate them and includes ready-to-use code in multiple languages.
How It Works
1. Construct the string to sign: "{apiKey}&payload={payload}"
2. Compute HMAC-SHA256 using your API secret as the key
3. Send the signature in the X-Api-Signature header
The payload is a JSON string — it can be any valid JSON (e.g., {"test":"auth"}). The same payload is sent in the request body.
Authentication Request
curl -X POST https://api.neutron.me/api/v2/authentication/token-signature \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "X-Api-Signature: YOUR_COMPUTED_SIGNATURE" \
-d '{"test":"auth"}'Headers
| Header | Value | Description |
|---|---|---|
Content-Type | application/json | Always required |
X-Api-Key | Your API key | Identifies your account |
X-Api-Signature | HMAC-SHA256 hex string | Proves you have the API secret |
Response
{
"accountId": "ne01-abc123def456",
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"expiresAt": 1770428400000
}Use the accessToken as a Bearer token for all subsequent API calls:
curl https://api.neutron.me/api/v2/account/YOUR_ACCOUNT_ID \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"Signature Formula
stringToSign = "{apiKey}&payload={payload}"
signature = HMAC-SHA256(secret, stringToSign) → hex
Example values:
- API Key:
nk_live_abc123 - API Secret:
ns_live_xyz789 - Payload:
{"test":"auth"} - String to sign:
nk_live_abc123&payload={"test":"auth"}
Code Examples
Node.js
const crypto = require('crypto');
function computeSignature(apiKey, apiSecret, payload) {
const stringToSign = `${apiKey}&payload=${payload}`;
return crypto
.createHmac('sha256', apiSecret)
.update(stringToSign)
.digest('hex');
}
// Usage
const apiKey = 'your-api-key';
const apiSecret = 'your-api-secret';
const payload = JSON.stringify({ test: 'auth' });
const signature = computeSignature(apiKey, apiSecret, payload);
// Make the authentication request
const response = await fetch('https://api.neutron.me/api/v2/authentication/token-signature', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': apiKey,
'X-Api-Signature': signature,
},
body: payload,
});
const { accessToken, accountId } = await response.json();Python
import hmac
import hashlib
import json
import requests
def compute_signature(api_key: str, api_secret: str, payload: str) -> str:
string_to_sign = f"{api_key}&payload={payload}"
return hmac.new(
api_secret.encode('utf-8'),
string_to_sign.encode('utf-8'),
hashlib.sha256
).hexdigest()
# Usage
api_key = 'your-api-key'
api_secret = 'your-api-secret'
payload = json.dumps({"test": "auth"})
signature = compute_signature(api_key, api_secret, payload)
response = requests.post(
'https://api.neutron.me/api/v2/authentication/token-signature',
headers={
'Content-Type': 'application/json',
'X-Api-Key': api_key,
'X-Api-Signature': signature,
},
data=payload,
)
data = response.json()
access_token = data['accessToken']Go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"net/http"
"strings"
)
func computeSignature(apiKey, apiSecret, payload string) string {
stringToSign := apiKey + "&payload=" + payload
h := hmac.New(sha256.New, []byte(apiSecret))
h.Write([]byte(stringToSign))
return hex.EncodeToString(h.Sum(nil))
}
func main() {
apiKey := "your-api-key"
apiSecret := "your-api-secret"
payload := `{"test":"auth"}`
signature := computeSignature(apiKey, apiSecret, payload)
req, _ := http.NewRequest("POST",
"https://api.neutron.me/api/v2/authentication/token-signature",
strings.NewReader(payload))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Api-Key", apiKey)
req.Header.Set("X-Api-Signature", signature)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}C#
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
class NeutronAuth
{
static string ComputeSignature(string apiKey, string apiSecret, string payload)
{
string stringToSign = $"{apiKey}&payload={payload}";
byte[] keyBytes = Encoding.UTF8.GetBytes(apiSecret);
byte[] messageBytes = Encoding.UTF8.GetBytes(stringToSign);
using var hmac = new HMACSHA256(keyBytes);
byte[] hash = hmac.ComputeHash(messageBytes);
return BitConverter.ToString(hash).Replace("-", "").ToLower();
}
static async Task Main()
{
string apiKey = "your-api-key";
string apiSecret = "your-api-secret";
string payload = "{\"test\":\"auth\"}";
string signature = ComputeSignature(apiKey, apiSecret, payload);
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post,
"https://api.neutron.me/api/v2/authentication/token-signature");
request.Headers.Add("X-Api-Key", apiKey);
request.Headers.Add("X-Api-Signature", signature);
request.Content = new StringContent(payload, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
public class NeutronAuth {
static String computeSignature(String apiKey, String apiSecret, String payload) throws Exception {
String stringToSign = apiKey + "&payload=" + payload;
Mac hmac = Mac.getInstance("HmacSHA256");
hmac.init(new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] hash = hmac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder();
for (byte b : hash) {
hex.append(String.format("%02x", b));
}
return hex.toString();
}
public static void main(String[] args) throws Exception {
String apiKey = "your-api-key";
String apiSecret = "your-api-secret";
String payload = "{\"test\":\"auth\"}";
String signature = computeSignature(apiKey, apiSecret, payload);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.neutron.me/api/v2/authentication/token-signature"))
.header("Content-Type", "application/json")
.header("X-Api-Key", apiKey)
.header("X-Api-Signature", signature)
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}Webhook Signature Verification
When Neutron sends webhook callbacks to your server, each request includes a signature header for verification. This uses the secret you provided when creating the webhook.
How It Works
1. Neutron computes: HMAC-SHA256(your_webhook_secret, request_body)
2. Sends it in the X-Neutronpay-Signature header
3. Your server recomputes and compares
Verification Example (Node.js)
const crypto = require('crypto');
function verifyWebhookSignature(requestBody, signatureHeader, webhookSecret) {
const expected = crypto
.createHmac('sha256', webhookSecret)
.update(requestBody) // raw request body string
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signatureHeader),
Buffer.from(expected)
);
}
// In your webhook handler
app.post('/webhook', (req, res) => {
const signature = req.headers['x-neutronpay-signature'];
const isValid = verifyWebhookSignature(
JSON.stringify(req.body),
signature,
'your-webhook-secret'
);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
res.status(200).send('OK');
// Process the event asynchronously...
});Verification Example (Python)
import hmac
import hashlib
def verify_webhook(body: str, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode('utf-8'),
body.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)Sample Webhook Payload
{
"txnId": "41866d80-a46a-4845-a205-5cffc881cad3",
"extRefId": "ordid-abc1234",
"txnState": "completed",
"msg": "",
"updatedAt": 1676030467492
}
Always use constant-time comparison (timingSafeEqual/compare_digest) to prevent timing attacks. Never use===or==for signature comparison.
Related
- Authentication endpoint — API reference
- Webhook Guide — Setting up webhooks
- Webhook Signature Recipe — Interactive code runner
