Request signing
When your API client has "Require HMAC-signed write requests" enabled, every POST, PUT, PATCH and DELETE must carry a signature. GET requests never need one. Signing protects against tampering and replay: a captured request cannot be re-sent later.
You receive a signing secret (whsig_…) together with each API key. It is shown once.
Headers
| Header | Value |
|---|---|
X-Timestamp |
Current Unix time in seconds |
X-Signature |
Lowercase hex HMAC-SHA256 of the string below, keyed with your signing secret |
String to sign
<timestamp>\n<HTTP METHOD>\n<request path and query>\n<raw request body>
\nis a single newline character.- The path is exactly what you send, including the
/api/v1prefix and any query string, e.g./api/v1/bookings. - The body is the raw bytes you send (an empty string for requests with no body). Sign the same serialisation you transmit.
- The timestamp must be within 5 minutes of server time, otherwise
401.
Node.js
import crypto from "node:crypto";
async function signedPost(path, payload, apiKey, signingSecret) {
const body = JSON.stringify(payload);
const ts = Math.floor(Date.now() / 1000);
const signature = crypto
.createHmac("sha256", signingSecret)
.update(`${ts}\nPOST\n${path}\n${body}`)
.digest("hex");
return fetch(`https://searchurtrip.com${path}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
"X-Timestamp": String(ts),
"X-Signature": signature,
"Idempotency-Key": crypto.randomUUID(),
},
body,
});
}
Python
import hashlib, hmac, json, time, uuid, requests
def signed_post(path, payload, api_key, signing_secret):
body = json.dumps(payload, separators=(",", ":"))
ts = str(int(time.time()))
to_sign = f"{ts}\nPOST\n{path}\n{body}"
sig = hmac.new(signing_secret.encode(), to_sign.encode(), hashlib.sha256).hexdigest()
return requests.post(
"https://searchurtrip.com" + path,
data=body,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}",
"X-Timestamp": ts,
"X-Signature": sig,
"Idempotency-Key": str(uuid.uuid4()),
},
)
Failure modes
| Cause | Response |
|---|---|
Missing X-Timestamp / X-Signature |
401 unauthorized — "Signed requests require…" |
| Timestamp outside the 5-minute window | 401 unauthorized |
| Signature does not match | 401 unauthorized — "Invalid request signature" |
The most common mistake is signing a differently formatted body than the one sent (whitespace, key order). Serialise once and reuse the same string.