Authentication and security
The REST API uses OAuth 2.0 client credentials for authentication. Tokens expire after 30 minutes. If your integration runs unattended (syncing products from an ERP, exporting orders on a schedule), you need to handle token renewal automatically.
This page covers how to manage authentication in production integrations. For a first-time walkthrough of getting a token, see Getting Started → Authenticate.
Token lifecycle
Your integration follows a simple cycle:
- Request an access token using your
client_idandclient_secret - Use that token for API requests (up to 30 minutes)
- Request a new token when the current one expires
There are no refresh tokens. When a token expires, you request a completely new one using the same client credentials. This means your integration always needs access to the credentials, not just a stored token.
Requesting a token
Send a POST request to the token endpoint with your credentials:
POST https://api.helice.cloud/oauth2/token
Content-Type: application/x-www-form-urlencoded
client_id=your_client_id&client_secret=your_client_secret&grant_type=client_credentials
A successful response returns the token and its lifetime:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5...",
"expires_in": 1800,
"refresh_expires_in": 0,
"token_type": "Bearer",
"not-before-policy": 0,
"scope": "profile"
}
| Field | Description |
|---|---|
access_token | The bearer token to use in API requests |
expires_in | Token lifetime in seconds (1800 = 30 minutes) |
token_type | Always Bearer |
scope | Token permissions |
Using the token
Include the token as a Bearer token in the Authorization header of every API request:
GET https://api.helice.cloud/v2/products?page=1&offset=10
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5...
Content-Type: application/json
Token renewal
Build a renewal buffer of about 5 minutes into your integration. Before each API call, check whether the token will expire within 5 minutes. If it will, request a new token before making the call. This prevents tokens from expiring mid-request.
For long-running sync operations that make hundreds of calls, the renewal logic should run transparently between requests without interrupting the sync.
Handling authentication errors
Not all auth errors should be retried. Your integration needs to distinguish between temporary failures and permanent ones.
Expired token (401 invalid_token)
If an API request returns 401 with error code invalid_token, the token has expired. Request a new token and retry the call once. If the retry also fails with 401, the problem is not token expiration.
{
"Error": "Token is expired or invalid",
"ErrorCode": "invalid_token"
}
Invalid credentials (401 invalid_client)
If the token request itself returns 401 with invalid_client, your credentials are wrong. Do not retry in a loop. Log the error, send an alert and stop the sync run. Retrying with the same credentials will never succeed and may trigger rate limiting.
{
"Error": "ClientId is Invalid",
"ErrorCode": "invalid_client"
}
Bad request (400 invalid_request)
If the token request returns 400, the request format is wrong. Verify that Content-Type is set to application/x-www-form-urlencoded and that all three parameters (client_id, client_secret, grant_type) are included in the request body.
{
"Error": "Unsupported grant type",
"ErrorCode": "invalid_request"
}
Insufficient permissions (403 insufficient_scope)
If an API request returns 403, the token does not have permission to access the requested resource. Check the API client permissions in the Backoffice.
Rate limiting (429)
If you receive 429, back off and retry with exponential delays. Start with a 1 second delay and double it on each retry, up to a maximum of 30 seconds. Stop retrying after 5 attempts.
Error reference
| HTTP status | Error code | Cause | Action |
|---|---|---|---|
| 400 | invalid_request | Malformed token request | Check Content-Type header and request body parameters |
| 401 | invalid_client | Wrong credentials | Verify client_id and client_secret in the Backoffice |
| 401 | invalid_token | Token expired | Request a new token and retry once |
| 403 | insufficient_scope | Missing permissions | Check API client permissions in the Backoffice |
| 429 | rate_limit_exceeded | Too many requests | Retry with exponential backoff |
Securing credentials
Keep your client_id and client_secret out of source code:
- Use environment variables or a secrets manager (AWS Secrets Manager, Azure Key Vault, HashiCorp Vault). Never hardcode credentials in your integration code or configuration files that are committed to version control.
- Use separate credentials per environment. Create different API clients in the Backoffice for your test and production environments. This prevents test integrations from accidentally modifying production data.
- Rotate credentials periodically. Create a new API client in the Backoffice, update your integration to use the new credentials, verify it works, then delete the old client.
See also
- Getting Started → Authenticate for a first-time walkthrough
- Get Access Token endpoint for the full endpoint specification