Authentication guide
The Spendstream API uses bearer tokens. You exchange a signed request for a token, then send that token with every other call. This page explains the signature, shows working examples and lists the common failures.
How it works
- Take your API key and the current UTC timestamp in the format
YYYY-MM-DD HH:MM:SS. - Join them with no separator:
api_key + time_stamp. - Compute an HMAC-SHA256 of that string, using your secret as the key, and encode it as lowercase hexadecimal. This is your
code. - Send
POST /getTokenwithapi_key,time_stampandcodein a JSON body. - Read the bearer token from the response and send it as
Authorization: Bearer YOUR_TOKENon every later request.
The token is valid for 10 hours. It is scoped to your organisation, not to an individual user, so one token serves all of your customers.
⚠️ Warning: getToken is rate limited to 5 requests per minute, and today that limit is one bucket shared across the platform. Cache the token and refresh it shortly before it expires. Never fetch a token on each customer request.
Examples
Replace the placeholders with your own staging credentials. Keep the secret on your server.
curl
API_KEY="YOUR_API_KEY"
SECRET_KEY="YOUR_SECRET_KEY"
TS=$(date -u +"%Y-%m-%d %H:%M:%S")
CODE=$(printf '%s%s' "$API_KEY" "$TS" | openssl dgst -sha256 -hmac "$SECRET_KEY" -hex | sed 's/^.* //')
curl -X POST https://staging-api.spendstream.io/v2/getToken \
-H 'Content-Type: application/json' \
-H 'User-Agent: YourApp/1.0' \
-d "{\"api_key\":\"$API_KEY\",\"time_stamp\":\"$TS\",\"code\":\"$CODE\"}"
JavaScript
import crypto from 'crypto';
const BASE = 'https://staging-api.spendstream.io/v2';
const timeStamp = new Date().toISOString().slice(0, 19).replace('T', ' ');
const code = crypto
.createHmac('sha256', process.env.SPENDSTREAM_SECRET)
.update(process.env.SPENDSTREAM_API_KEY + timeStamp)
.digest('hex');
const res = await fetch(`${BASE}/getToken`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'User-Agent': 'YourApp/1.0',
},
body: JSON.stringify({
api_key: process.env.SPENDSTREAM_API_KEY,
time_stamp: timeStamp,
code,
}),
});
const body = await res.json();
const token = body.token;
Python
import hashlib
import hmac
import os
from datetime import datetime, timezone
import requests
BASE = "https://staging-api.spendstream.io/v2"
api_key = os.environ["SPENDSTREAM_API_KEY"]
secret = os.environ["SPENDSTREAM_SECRET"]
time_stamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
code = hmac.new(
secret.encode(), (api_key + time_stamp).encode(), hashlib.sha256
).hexdigest()
res = requests.post(
f"{BASE}/getToken",
json={"api_key": api_key, "time_stamp": time_stamp, "code": code},
headers={"User-Agent": "YourApp/1.0"},
timeout=15,
)
token = res.json()["token"]
Using the token
curl https://staging-api.spendstream.io/v2/getBrands \
-H 'Authorization: Bearer YOUR_BEARER_TOKEN' \
-H 'User-Agent: YourApp/1.0'
Common problems
What you see | Likely cause |
| The signature does not match. Check the order ( |
| More than 5 token requests in a minute. Cache your token. |
| The bearer token is missing, malformed or older than 10 hours. |
| Blocked at the CDN because of the client’s default User-Agent. Set an explicit User-Agent. |
| Your account has an IP allow-list and the request came from an address that is not on it. See IP allow-listing below. |
| The |
IP allow-listing
Spendstream can restrict your account to a list of approved IP addresses. If a list has been set, every API request is checked against it, and a request from any other address is refused with HTTP 403.
getToken returns:
{ "error": "IP address not allowed" }
Every other endpoint returns:
{ "status": false, "message": "Access denied - IP address not allowed" }
A few points to plan for:
- If no list has been set for your account, nothing changes.
- Matching is exact. Add single IPv4 or IPv6 addresses; ranges are not supported.
- Make your calls from your server’s fixed outbound address, and ask Spendstream to add every address you use, including the ones for staging and production.
- Calls from a developer laptop or a cloud function with a changing address will be refused once a list is set.
Keep credentials safe
Never place your API key, secret or token generation code in browser or mobile code. Generate tokens on your server only, and store the secret in a secrets manager or environment variable.
Related pages
- Environments
- API quickstart
- Go-live checklist
- white-label single sign-on guide (covers the separate per-customer SSO token)
On this page
- Authentication guide