Cash · Guides
Sign requests with HMAC
Authenticate every Cash API call with X-Client-Id, X-Signature and X-Timestamp.
Every Cash API request is authenticated with an HMAC-SHA256 signature. You get your api_key and api_secret from Monato’s customer success team when your client is created.
Headers
Send these three headers on every request:
| Header | Value |
|---|---|
X-Client-Id |
Your API key (32 hexadecimal characters) |
X-Signature |
HMAC-SHA256 signature of timestamp + "." + requestBody, using your api_secret, hex-encoded |
X-Timestamp |
Unix timestamp in seconds. It helps prevent replay attacks. |
Build the signature
- Take the current Unix timestamp in seconds, as a string.
- Serialize the request body to a JSON string.
- Join them with a dot:
timestamp + "." + requestBody. - Compute HMAC-SHA256 of that string with your
api_secretand hex-encode the result.
Formula
HMAC-SHA256(timestamp + "." + JSON.stringify(requestBody), api_secret)Note:
Sign the same body string that you send in the request.
Examples
These examples sign the body of a Create Webhook request.
const crypto = require('crypto');
const timestamp = Math.floor(Date.now() / 1000).toString();
const requestBody = JSON.stringify({
endpoint_url: "https://your-webhook-endpoint.com/webhooks"
});
const payload = `${timestamp}.${requestBody}`;
const apiSecret = "your_64_character_api_secret_here";
const signature = crypto
.createHmac('sha256', apiSecret)
.update(payload)
.digest('hex');import hmac
import hashlib
import json
import time
timestamp = str(int(time.time()))
request_body = json.dumps({
"endpoint_url": "https://your-webhook-endpoint.com/webhooks"
})
payload = f"{timestamp}.{request_body}"
api_secret = "your_64_character_api_secret_here"
signature = hmac.new(
api_secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()<?php
$timestamp = time();
$requestBody = json_encode([
'endpoint_url' => 'https://your-webhook-endpoint.com/webhooks'
]);
$payload = $timestamp . '.' . $requestBody;
$apiSecret = 'your_64_character_api_secret_here';
$signature = hash_hmac('sha256', $payload, $apiSecret);
?>require 'openssl'
require 'json'
require 'time'
timestamp = Time.now.to_i.to_s
request_body = {
endpoint_url: "https://your-webhook-endpoint.com/webhooks"
}.to_json
payload = "#{timestamp}.#{request_body}"
api_secret = "your_64_character_api_secret_here"
signature = OpenSSL::HMAC.hexdigest('SHA256', api_secret, payload)import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.time.Instant;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
long timestamp = Instant.now().getEpochSecond();
String requestBody = new ObjectMapper().writeValueAsString(
Map.of("endpoint_url", "https://your-webhook-endpoint.com/webhooks")
);
String payload = timestamp + "." + requestBody;
String apiSecret = "your_64_character_api_secret_here";
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(apiSecret.getBytes(), "HmacSHA256");
mac.init(secretKeySpec);
String signature = bytesToHex(mac.doFinal(payload.getBytes()));
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}using System;
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
string requestBody = JsonConvert.SerializeObject(new {
endpoint_url = "https://your-webhook-endpoint.com/webhooks"
});
string payload = $"{timestamp}.{requestBody}";
string apiSecret = "your_64_character_api_secret_here";
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(apiSecret)))
{
byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
string signature = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"time"
)
type RequestBody struct {
EndpointURL string `json:"endpoint_url"`
}
func main() {
timestamp := fmt.Sprintf("%d", time.Now().Unix())
requestBody := RequestBody{
EndpointURL: "https://your-webhook-endpoint.com/webhooks",
}
requestBodyJSON, _ := json.Marshal(requestBody)
payload := fmt.Sprintf("%s.%s", timestamp, string(requestBodyJSON))
apiSecret := "your_64_character_api_secret_here"
h := hmac.New(sha256.New, []byte(apiSecret))
h.Write([]byte(payload))
signature := hex.EncodeToString(h.Sum(nil))
_ = signature
}Send the request
Signed request
curl -X POST "https://dev-api.finco.lat/api/v1/cash/webhooks" \
-H "Content-Type: application/json" \
-H "X-Client-Id: 4a8a08f09d37b73795649038408b5f33" \
-H "X-Signature: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" \
-H "X-Timestamp: 1705312200" \
-d '{"endpoint_url":"https://your-webhook-endpoint.com/webhooks"}'If authentication fails
An invalid X-Client-Id or a signature that does not verify returns 401:
401 Unauthorized
{
"error": "Unauthorized"
}Webhooks that Monato sends you are signed too. See Webhook events.