Set up API keys, test the connection and learn how to handle errors and request limits.
https://alterproduct.com/public-api/v1
Create API credentials in the e-commerce settings panel. The Access Token is shown once, so store it immediately in your backend secret storage.
Keep the Access Key and Access Token on your server. Authenticated endpoints reject browser-origin calls that include Origin or Referer headers.
Credentials can be scoped. Use GET /auth/check to verify the active storefront, plan capabilities and scopes returned for the credential.
x-alter-access-key: YOUR_API_KEY
x-alter-access-token: YOUR_API_TOKEN
| Parameter | Required | Details |
|---|
x-alter-access-key | yes | Public credential identifier. |
x-alter-access-token | yes | Secret token paired with the access key. |
x-alter-client-fingerprint | no | Optional stable fingerprint for embed session rate limiting. |
Authorization | runtime only | Bearer token returned by POST /embed/session, used by /runtime/bootstrap. |
Use the auth check endpoint before enabling synchronization or embed features in a live integration.
GET https://alterproduct.com/public-api/v1/auth/check
Example request (fetch)
const response = await fetch('https://alterproduct.com/public-api/v1/auth/check', {
method: 'GET',
headers: {
'x-alter-access-key': process.env.ALTER_ACCESS_KEY,
'x-alter-access-token': process.env.ALTER_ACCESS_TOKEN
}
});
const payload = await response.json();
if (!response.ok) {
throw new Error(payload?.code || payload?.error || `Alter API ${response.status}`);
}
console.log(payload);
Example response
{
"ok": true,
"message": "success",
"storefrontId": 12,
"userOwnerId": 34,
"credentialId": 56,
"scopes": ["orders:read", "orders:write", "products:read"],
"plan": {
"requiredPlan": "Business",
"currentPlanName": "Business",
"eligible": true,
"runtimeFlags": {
"viewer": true,
"configurator": true,
"customizer": true
},
"limits": {
"activeRuntimeBindingsLimit": 100,
"monthlyReassignmentLimit": 1000,
"monthlyEmbedTokenLimit": 50000
}
}
}
The helper below is used by the remaining examples. It is plain fetch and can run in Node.js 18+ or any server runtime that provides fetch.
const ALTER_API_BASE = 'https://alterproduct.com/public-api/v1';
const authHeaders = {
'x-alter-access-key': process.env.ALTER_ACCESS_KEY,
'x-alter-access-token': process.env.ALTER_ACCESS_TOKEN
};
async function alterFetch(path, options = {}) {
const response = await fetch(`${ALTER_API_BASE}${path}`, {
...options,
headers: {
...authHeaders,
...(options.body ? { 'Content-Type': 'application/json' } : {}),
...options.headers
}
});
const payload = await response.json().catch(() => null);
if (!response.ok) {
throw new Error(payload?.code || payload?.error || `Alter API ${response.status}`);
}
return payload;
}
Most controller errors are normalized to a code response. Authentication middleware and rate limiters can return an error response instead.
// Controller error
{
"code": "assetCatalog.invalidType"
}
// Auth middleware or rate limit
{
"error": "Unauthorized"
}
{
"error": "Too Many Requests"
}
| Type | Limit | Window |
|---|
Global | 600 requests | 60 seconds |
GET /auth/check | 60 requests | 60 seconds |
Orders read/products read | 300 requests | 60 seconds |
Orders write/embed sessions/runtime bindings | 120 requests | 60 seconds |
Assets/design imports read | 180 requests | 60 seconds |
Fonts | 300 requests | 60 seconds |
WP connect exchange | 30 requests | 60 seconds |
GET /model-generator/* | 600 requests | 60 seconds |