Skip to content

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:

FieldDescription
NameDescriptive name for the integration
DescriptionPurpose of the service account
ScopesPermissions granted to this account
OrganizationOrganization 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:

  1. Navigate to the service account in the admin panel
  2. Click Rotate Credentials
  3. Confirm the rotation
  4. Save the new credentials
  5. Update your application configuration
  6. 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:

  1. Navigate to the service account in the admin panel
  2. Click Deactivate
  3. 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:

  1. Navigate to the service account in the admin panel
  2. Click Delete
  3. 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

ComponentSeparatorDescriptionExample
Service:The API serviceengagehq, datacore, identity
Resource.The resource typecontent, products, circulars
ActionThe operationview, create, update, delete, manage, * (all)

Common Scopes

ScopeDescription
engagehq:*Full EngageHQ access
engagehq:content.viewView CMS content items
engagehq:content.createCreate new content items
engagehq:circulars.viewView weekly circulars
engagehq:offers.viewView promotional offers
datacore:*Full DataCore access
datacore:products.viewView products
datacore:categories.viewView category hierarchy
kitchenclick:*Full KitchenClick ecommerce access
kitchenclick:menus.readCheck item availability
kitchenclick:orders.calculateCalculate order totals
kitchenclick:orders.createCreate guest orders
kitchenclick:payments.readCheck payment status
kitchenclick:payments.createCreate payment requests
kitchenclick:kiosks.bootstrapInitialize kiosks
kitchenclick:kiosks.heartbeatSend 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/credentials

4. 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
DateChange
2026-03-14Accuracy fixes and added missing content.
2026-02-27Documentation corrections.
2026-01-15Initial publication.

ShopHero CommerceCore Platform