Appearance
Service Accounts
Service accounts are non-interactive credentials used for server-to-server authentication. They're ideal for backend applications that need to access ShopHero APIs without user interaction.
What is a Service Account?
A service account represents your application or integration in the ShopHero platform. Unlike user accounts, service accounts:
- Don't have passwords or interactive login
- Use OAuth 2.0 client credentials flow
- Have programmatic access only
- Are scoped to specific permissions
- Can be created and managed by organization admins
Creating a Service Account
Service accounts are created through the CommerceCore admin interface by users with the appropriate permissions.
Required Information
When creating a service account, you'll specify:
| Field | Description |
|---|---|
| Name | Descriptive name for the integration |
| Description | Purpose of the service account |
| Scopes | Permissions granted to this account |
| Organization | Organization context for the account |
Credentials Response
Upon creation, you'll receive credentials once:
json
{
"data": {
"service_account_id": "usr_00000x1Y2z3A4b5",
"name": "Website Content Integration",
"email": "api_integration-1705324800-abcd1234@internal.shophero.internal",
"internal_type": "api_integration",
"internal_description": "Fetches content for the public website",
"internal_scopes": ["engagehq:content.view", "engagehq:circulars.view"],
"is_active": true,
"is_internal_account": true,
"created_at": "2024-01-15T10:30:00Z",
"tenants": [
{
"organization_id": "org_00000k1L2m3N4o5"
}
]
},
"credentials": {
"client_id": "9a1b2c3d-4e5f-6789-abcd-ef0123456789",
"client_secret": "Wk3mPqR7vX9bN2cF5hJ8tL0wA4sD6gY1uI3oE",
"grant_type": "client_credentials",
"scopes": ["engagehq:content.view", "engagehq:circulars.view"],
"service_account_id": "usr_00000x1Y2z3A4b5"
},
"message": "Service user created successfully"
}Save Your Credentials
The client_secret is displayed only once. Copy and store it immediately in a secure location. If you lose it, you'll need to rotate your credentials.
Credential Format
Client ID
The client ID identifies your service account's OAuth client:
- Format: UUID
- Example:
9a1b2c3d-4e5f-6789-abcd-ef0123456789 - Can be shared publicly (it's not a secret)
Client Secret
The client secret authenticates your service account:
- Format: 40-character random alphanumeric string
- Example:
Wk3mPqR7vX9bN2cF5hJ8tL0wA4sD6gY1uI3oE - Must be kept secret - never expose in client-side code
Managing Service Accounts
Viewing Service Accounts
Organization admins can view all service accounts in the CommerceCore admin panel under Identity > Service Accounts.
Credential Rotation
If your credentials are compromised or as part of regular security hygiene, rotate your credentials:
- Navigate to the service account in the admin panel
- Click Rotate Credentials
- Confirm the rotation
- Save the new credentials
- Update your application configuration
- The old credentials become invalid immediately
Rotation Best Practice
Rotate service account credentials every 90 days as a security best practice.
Deactivating a Service Account
To revoke access:
- Navigate to the service account in the admin panel
- Click Deactivate
- Confirm the deactivation
Deactivated accounts:
- Can no longer obtain new tokens
- Existing tokens remain valid until expiry
- Can be reactivated by an admin
Deleting a Service Account
Permanent deletion:
- Navigate to the service account in the admin panel
- Click Delete
- Confirm the deletion
Deletion is Permanent
Deleted service accounts cannot be recovered. All associated tokens are immediately invalidated.
Scopes
Scopes define what resources a service account can access. Follow the principle of least privilege—only request the scopes your integration actually needs.
Scope Format
Scopes follow the pattern: service:resource.action
| Component | Separator | Description | Example |
|---|---|---|---|
| Service | : | The API service | engagehq, datacore, identity |
| Resource | . | The resource type | content, products, circulars |
| Action | The operation | view, create, update, delete, manage, * (all) |
Common Scopes
| Scope | Description |
|---|---|
engagehq:* | Full EngageHQ access |
engagehq:content.view | View CMS content items |
engagehq:content.create | Create new content items |
engagehq:circulars.view | View weekly circulars |
engagehq:offers.view | View promotional offers |
datacore:* | Full DataCore access |
datacore:products.view | View products |
datacore:categories.view | View category hierarchy |
kitchenclick:* | Full KitchenClick ecommerce access |
kitchenclick:menus.read | Check item availability |
kitchenclick:orders.calculate | Calculate order totals |
kitchenclick:orders.create | Create guest orders |
kitchenclick:payments.read | Check payment status |
kitchenclick:payments.create | Create payment requests |
kitchenclick:kiosks.bootstrap | Initialize kiosks |
kitchenclick:kiosks.heartbeat | Send kiosk heartbeats |
Requesting Scopes
When requesting a token, specify the scopes you need:
bash
curl -X POST https://identity.retailsuccessplatform.com/oauth/token \
-d "grant_type=client_credentials" \
-d "client_id=${CLIENT_ID}" \
-d "client_secret=${CLIENT_SECRET}" \
-d "scope=engagehq:content.view engagehq:circulars.view"Note: You can only request scopes that were granted when the service account was created. Requesting additional scopes will result in an error.
Best Practices
1. Use Separate Service Accounts
Create separate service accounts for:
- Different applications/integrations
- Development vs. production environments
- Different permission levels
2. Apply Least Privilege
Only request the minimum scopes necessary:
bash
# Good - specific scopes
scope=engagehq:content.view engagehq:circulars.view
# Avoid - overly broad
scope=engagehq:*3. Secure Credential Storage
Store credentials securely:
bash
# Environment variables (recommended)
export SHOPHERO_CLIENT_ID="9a1b2c3d-4e5f-6789-abcd-ef0123456789"
export SHOPHERO_CLIENT_SECRET="Wk3mPqR7vX9bN2cF5hJ8tL0wA4sD6gY1uI3oE"
# Or use a secrets manager
aws secretsmanager get-secret-value --secret-id shophero/credentials4. Implement Token Caching
Don't request a new token for every API call:
javascript
// Cache token with expiry tracking
const tokenCache = {
token: null,
expiresAt: 0,
async getToken() {
if (this.token && Date.now() < this.expiresAt - 300000) {
return this.token;
}
// ... request new token
}
};5. Handle Errors Gracefully
javascript
async function makeApiCall() {
try {
const token = await tokenService.getToken();
const response = await fetch(apiUrl, {
headers: { Authorization: `Bearer ${token}` }
});
if (response.status === 401) {
// Token may have been revoked, clear cache and retry
tokenService.clearCache();
return makeApiCall();
}
return response.json();
} catch (error) {
console.error('API call failed:', error);
throw error;
}
}Troubleshooting
Invalid Client Credentials
json
{
"error": "invalid_client",
"error_description": "Client authentication failed"
}Causes:
- Incorrect client ID or secret
- Service account has been deactivated or deleted
- Credentials have been rotated
Solution: Verify your credentials and check the service account status in the admin panel.
Invalid Scope
json
{
"error": "invalid_scope",
"error_description": "The requested scope is invalid or not authorized"
}Causes:
- Requesting a scope not granted to the service account
- Typo in scope name
Solution: Check the scopes assigned to your service account and ensure you're requesting only those scopes.
Rate Limited
json
{
"error": "rate_limit_exceeded",
"error_description": "Too many requests"
}Causes:
- Too many token requests in a short period
Solution: Implement token caching to reduce requests. The /oauth/token endpoint allows 60 requests per minute.
Changelog
| Date | Change |
|---|---|
| 2026-03-14 | Accuracy fixes and added missing content. |
| 2026-02-27 | Documentation corrections. |
| 2026-01-15 | Initial publication. |