Appearance
Getting Started
This guide walks you through authenticating with the Identity API and making your first authenticated API call.
Prerequisites
Before you begin, ensure you have:
- A ShopHero service account with client credentials
- Access to a backend server (Node.js, PHP, Python, etc.)
- An understanding of OAuth 2.0 client credentials flow
Step 1: Obtain Credentials
Service account credentials are created by your organization administrator through the CommerceCore admin interface.
When a service account is created, you'll receive:
json
{
"client_id": "9a1b2c3d-4e5f-6789-abcd-ef0123456789",
"client_secret": "Wk3mPqR7vX9bN2cF5hJ8tL0wA4sD6gY1uI3oE",
"grant_type": "client_credentials",
"scopes": ["engagehq:content.view", "engagehq:circulars.view"]
}Store Credentials Securely
The client_secret is only shown once at creation time. Store it immediately in a secure location like:
- Environment variables
- Secret management service (AWS Secrets Manager, HashiCorp Vault)
- Encrypted configuration files
Never commit credentials to source control.
Step 2: Request an Access Token
Exchange your credentials for a JWT access token:
Request
http
POST /oauth/token HTTP/1.1
Host: identity.retailsuccessplatform.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=9a1b2c3d-4e5f-6789-abcd-ef0123456789&client_secret=Wk3mPqR7vX9bN2cF5hJ8tL0wA4sD6gY1uI3oE&scope=engagehq:content.view engagehq:circulars.viewcURL Example
bash
curl -X POST https://identity.retailsuccessplatform.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=${CLIENT_ID}" \
-d "client_secret=${CLIENT_SECRET}" \
-d "scope=engagehq:content.view engagehq:circulars.view"Response
json
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...",
"token_type": "Bearer",
"expires_in": 86400,
"expires_at": 1705411200
}Step 3: Use the Token
Include the access token in the Authorization header of API requests:
bash
curl https://api.engagehq.retailsuccessplatform.com/public/v1/content \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."Code Examples
JavaScript / Node.js
javascript
// token-service.js
class TokenService {
constructor(clientId, clientSecret) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.baseUrl = process.env.IDENTITY_URL || 'https://identity.retailsuccessplatform.com';
this.token = null;
this.tokenExpiry = null;
}
async getToken() {
// Return cached token if still valid (with 5 min buffer)
if (this.token && this.tokenExpiry > Date.now() + 300000) {
return this.token;
}
const response = await fetch(`${this.baseUrl}/oauth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: this.clientId,
client_secret: this.clientSecret,
scope: 'engagehq:content.view engagehq:circulars.view',
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Token request failed: ${error.message || response.statusText}`);
}
const data = await response.json();
this.token = data.access_token;
this.tokenExpiry = Date.now() + (data.expires_in * 1000);
return this.token;
}
}
// Usage
const tokenService = new TokenService(
process.env.SHOPHERO_CLIENT_ID,
process.env.SHOPHERO_CLIENT_SECRET
);
async function fetchContent() {
const token = await tokenService.getToken();
const response = await fetch('https://api.engagehq.retailsuccessplatform.com/public/v1/content', {
headers: {
'Authorization': `Bearer ${token}`,
},
});
return response.json();
}PHP
php
<?php
class TokenService
{
private string $clientId;
private string $clientSecret;
private string $baseUrl;
private ?string $token = null;
private ?int $tokenExpiry = null;
public function __construct(string $clientId, string $clientSecret)
{
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
$this->baseUrl = getenv('IDENTITY_URL') ?: 'https://identity.retailsuccessplatform.com';
}
public function getToken(): string
{
// Return cached token if still valid (with 5 min buffer)
if ($this->token && $this->tokenExpiry > time() + 300) {
return $this->token;
}
$ch = curl_init("{$this->baseUrl}/oauth/token");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
CURLOPT_POSTFIELDS => http_build_query([
'grant_type' => 'client_credentials',
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
'scope' => 'engagehq:content.view engagehq:circulars.view',
]),
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new Exception("Token request failed with status {$httpCode}");
}
$data = json_decode($response, true);
$this->token = $data['access_token'];
$this->tokenExpiry = time() + $data['expires_in'];
return $this->token;
}
}
// Usage
$tokenService = new TokenService(
getenv('SHOPHERO_CLIENT_ID'),
getenv('SHOPHERO_CLIENT_SECRET')
);
$token = $tokenService->getToken();
$content = file_get_contents(
'https://api.engagehq.retailsuccessplatform.com/public/v1/content',
false,
stream_context_create([
'http' => [
'header' => "Authorization: Bearer {$token}",
],
])
);Python
python
import os
import time
import requests
class TokenService:
def __init__(self, client_id: str, client_secret: str):
self.client_id = client_id
self.client_secret = client_secret
self.base_url = os.getenv('IDENTITY_URL', 'https://identity.retailsuccessplatform.com')
self.token = None
self.token_expiry = None
def get_token(self) -> str:
# Return cached token if still valid (with 5 min buffer)
if self.token and self.token_expiry > time.time() + 300:
return self.token
response = requests.post(
f'{self.base_url}/oauth/token',
data={
'grant_type': 'client_credentials',
'client_id': self.client_id,
'client_secret': self.client_secret,
'scope': 'engagehq:content.view engagehq:circulars.view',
},
headers={'Content-Type': 'application/x-www-form-urlencoded'}
)
response.raise_for_status()
data = response.json()
self.token = data['access_token']
self.token_expiry = time.time() + data['expires_in']
return self.token
# Usage
token_service = TokenService(
os.getenv('SHOPHERO_CLIENT_ID'),
os.getenv('SHOPHERO_CLIENT_SECRET')
)
token = token_service.get_token()
response = requests.get(
'https://api.engagehq.retailsuccessplatform.com/public/v1/content',
headers={'Authorization': f'Bearer {token}'}
)
content = response.json()Token Caching Best Practices
- Cache tokens in memory - Don't request a new token for every API call
- Refresh before expiry - Request a new token when the current one has less than 5 minutes remaining
- Handle 401 errors - If you receive a 401 Unauthorized, your token may have expired early; request a new one
- Don't share tokens - Each backend instance should manage its own token cache
Next Steps
- Service Accounts - Learn about service account management
- OAuth Token Reference - Complete endpoint documentation
- EngageHQ API - Start using your token with EngageHQ
Changelog
| Date | Change |
|---|---|
| 2026-02-27 | Documentation corrections. |
| 2026-01-15 | Initial publication. |