Get started
The OneEntry Platform SDK is a JavaScript client for the OneEntry Platform API.
Quick start
Installation
npm install oneentry
Initialize the SDK
import { defineOneEntry } from 'oneentry';
const api = defineOneEntry('https://your-project.oneentry.cloud', {
token: 'your-app-token'
});
Make your first calls
// Fetch products — filters first, the query object third
const products = await api.Products.getProducts([], 'en_US', { limit: 10 });
// Sign in first: getUser returns the signed-in user's profile.
// Use the field markers from your project's auth form.
await api.AuthProvider.auth('email', {
authData: [
{ marker: 'email', value: 'john@example.com' },
{ marker: 'password', value: 'your-password' },
],
});
const user = await api.Users.getUser();
// Submit a form — one body object, fields carry a marker and a type
const formData = await api.FormData.postFormsData({
formIdentifier: 'contact-form',
formModuleConfigId: 1,
moduleEntityIdentifier: 'contact-us',
replayTo: null,
status: 'sent',
formData: [
{ marker: 'your_name', type: 'string', value: 'John Smith' },
{ marker: 'your_email', type: 'string', value: 'john@example.com' },
],
});
TypeScript: every public type is exported from the package root and from
oneentry/types, e.g.import type { IProductsEntity } from 'oneentry'. See Importing types.
Features
Built-in token management and OAuth support
Localized content: set a default langCode once or pass one per call
Full type definitions, importable from the package root
Tree-shakeable ESM build — about 11 kB gzip in a typical setup
29 modules, one per API area
Custom error handlers and shell mode
Resources
Learn more about OneEntry Platform
Sign Up (opens in a new tab)Create your free account
npm (opens in a new tab)Install the package
JS SDK Sandbox (opens in a new tab)Try SDK methods live in your browser — no setup required
Usage
Modules
Destructure the modules you need from defineOneEntry:
import { defineOneEntry } from 'oneentry'
const config = { token: 'your-app-token',}const { , , , , , , , , , , , , , , , , , , , , , , , , , , , , } = defineOneEntry('https://your-project.oneentry.cloud', config);
Or keep the whole API object:
const config = {
token: 'your-app-token',
};
const api = defineOneEntry('https://your-project.oneentry.cloud', config);
Config
The second argument of defineOneEntry is the config object:
token: your project's Security API Token.defineOneEntrythrows if it is missing or empty. See the project security instructions.langCode: the default language. Set it once and you don't have to passlangCodeto every method. Default:"en_US".traficLimit(spelled with one f): some methods send follow-up requests so the result is complete, such as full pages behind quick search results or products of page blocks. Set it totrueto skip them and save traffic. Some results then change shape; for example,searchPagereturns short{ id, title }cards. Default:false.rawData: whenfalse(the default), the SDK turns theadditionalFieldsarray into an object keyed bymarker. Set it totrueto getadditionalFieldsas the original array from the API.guestId: an optional guest identifier, sent as thex-guest-idheader on unauthenticated requests. It enables the guest cart, wishlist and activity flows. In the browser, if you omit it, the SDK generates a stable per-device id and keeps it inlocalStorage. On the server you must pass a per-visitorguestId. See Guest mode. Default:undefined.deviceMetadata: an optional string sent as thex-device-metadataheader (on POST requests and token refresh) instead of the fingerprint the SDK computes from the current environment. The API binds refresh tokens to this header, so a server that issues tokens on behalf of a browser must pass the browser's fingerprint here. See Device metadata. Default:undefined.auth: authorization settings. By default the SDK stores and refreshes tokens in memory, so the user has to sign in again after a reload or restart. If that suits you, don't passauth.
auth accepts:
refreshToken: the user's refresh token. Pass it from your storage to restore the user's session on initialization.saveFunction: called with the new refresh token whenever it is updated. To keep the token between sessions (e.g. in local storage), pass a function that stores it. The function receives the token string as its argument.customAuth: set totrueto handle authorization and tokens yourself. To use the SDK's built-in handling, set it tofalseor omit it.providerMarker: the auth provider marker. Default:'email'.
A configuration with token protection that restores the user's session from localStorage:
const tokenFunction = (token) => {
localStorage.setItem('refreshToken', token);
};
const api = defineOneEntry('https://your-project.oneentry.cloud', {
token: 'your-app-token',
langCode: 'en_US',
auth: {
refreshToken: localStorage.getItem('refreshToken') ?? undefined,
saveFunction: tokenFunction,
providerMarker: 'email'
},
});
A configuration that handles authorization itself and saves traffic:
const api = defineOneEntry('https://your-project.oneentry.cloud', {
token: 'your-app-token',
langCode: 'en_US',
traficLimit: true,
auth: {
customAuth: true,
refreshToken: localStorage.getItem('refreshToken') ?? undefined,
providerMarker: 'email'
},
});
If you manage tokens yourself, pass the access token with setAccessToken and then call the method you need. Don't call setAccessToken before methods that don't require user authorization.
const user = await api.Users.setAccessToken('my.access.token').getUser();
Getting a token
- Sign in to your personal account.
- Open the Projects tab and select a project.
- Open the Access tab.
- Switch it to Security API Token.
- Sign in to the project, go to the settings section and open the token tab.
- Copy your project's token.
You can also protect your project with a TLS certificate (mTLS); requests then go through a proxy in your project that adds the certificate. Learn more about mTLS certificates
With mTLS enabled, the API doesn't check the app token. Pass your project URL as usual. SDK 1.0.175 still requires a non-empty token, so pass any placeholder string:
const { Pages } = defineOneEntry('https://your-project.oneentry.cloud', {
token: 'mtls', // not checked when mTLS is enabled
});
Guest mode
The SDK can act on behalf of an unauthenticated guest. When no access token is set, it sends an x-guest-id header, so guest-aware endpoints work without a logged-in user: the cart, wishlist and user activity flows, as well as the personalization blocks (recently viewed, personal recommendations, and others).
The guest id is resolved in this order:
- An explicitly configured
guestId(fromconfig.guestIdorsetGuestId) always wins. - In the browser, if none is provided, the SDK generates a stable id (with Web Crypto when available) and stores it in
localStorageunderoneentry_guest_id, the same way it handles device metadata. The id stays the same across sessions and tabs. - Otherwise the id is
undefinedand thex-guest-idheader is omitted.
Server-side: the SDK never generates a guest id on the server. Otherwise a single shared
defineOneEntryinstance would expose one guest cart and wishlist to every anonymous visitor. On the server, pass a per-visitorguestIdyourself (viaconfig.guestIdorsetGuestId).
Authenticated requests (with an access token set) never carry the header, so a logged-in user always works with their own data.
Set the guest id at initialization
const api = defineOneEntry('https://your-project.oneentry.cloud', {
token: 'your-app-token',
guestId: 'visitor-123', // per-visitor id, required on the server
});
Set or clear the guest id at runtime
setGuestId works like setAccessToken: it returns the module instance, so you can chain it. Pass an empty string to clear the id. The SDK then falls back to the localStorage id in the browser, or to no guest id on the server.
// Set the guest id, then call a guest-aware method
const cart = await api.Users.setGuestId('visitor-123').getCart();
// Clear the guest id
api.Users.setGuestId('');
Device metadata
The SDK sends an x-device-metadata header on POST requests and on token refresh. By default it is a fingerprint of the current environment (platform, user agent, language, screen, timezone and a persistent instance id). The API uses it for analytics and fraud prevention.
The API binds refresh tokens to this header: a refresh token can only be refreshed with the same fingerprint it was issued with. That breaks when the token is issued on the server on behalf of a browser, for example in an OAuth code exchange that keeps the client secret on the server. The token gets bound to the server's fingerprint, and the browser can never refresh it.
deviceMetadata fixes this. The server sends the browser's fingerprint, and the refresh token it gets stays refreshable from that browser.
Read the value in the browser
getDeviceMetadata() is available on every module. It returns the exact string the SDK sends: the override if one is set, otherwise the computed fingerprint.
// Browser: obtain the fingerprint and forward it to your backend
const deviceMetadata = api.Users.getDeviceMetadata();
await fetch('/api/oauth/exchange', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code, deviceMetadata }),
});
Set the override
Pass it at initialization:
const api = defineOneEntry('https://your-project.oneentry.cloud', {
token: 'your-app-token',
deviceMetadata, // the string forwarded from the browser
});
Or set it at runtime with setDeviceMetadata(deviceMetadata). Like setAccessToken, it is available on every module and chainable. An empty string clears the override, and the SDK goes back to the computed fingerprint.
// Server: issue tokens bound to the browser's fingerprint
const auth = await api.AuthProvider
.setDeviceMetadata(deviceMetadata)
.auth('email', { authData });
// Clear the override
api.AuthProvider.setDeviceMetadata('');
| Method | Returns | Description |
|---|---|---|
getDeviceMetadata() | string | The x-device-metadata string this instance sends (override, or computed fingerprint) |
setDeviceMetadata(value) | module instance | Sets the override; an empty string clears it |
API response validation
The SDK can validate API responses with Zod schemas that match its TypeScript interfaces.
- Validation is off by default; you turn it on in the config.
- There are two modes: soft mode logs errors, strict mode returns them.
- Zod and the response schemas are loaded on demand, the first time a response has to be validated. With validation off they never reach your bundle (see Bundle size and module formats).
Configuration
Add validation to the config:
import { defineOneEntry } from 'oneentry'
const api = defineOneEntry('https://your-project.oneentry.cloud', {
token: 'your-app-token',
validation: {
enabled: true, // Enable validation (default: false)
strictMode: false, // Strict mode (default: false)
logErrors: true, // Log validation errors (default: true)
}
})
Options
| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable/disable response validation |
strictMode | boolean | false | When true, returns IError on validation failure. When false, logs errors and returns original data |
logErrors | boolean | true | Log validation errors to console (useful for debugging) |
Modes
Soft mode (default)
With strictMode: false, validation errors are logged to the console and the original API response is returned unchanged. Use it during development to spot data inconsistencies without breaking the app.
const api = defineOneEntry('https://your-project.oneentry.cloud', {
token: 'your-app-token',
validation: {
enabled: true,
strictMode: false, // Soft mode
logErrors: true,
}
})
// Even if validation fails, you'll get the API response
const user = await api.Users.getUser()
// Console will show validation errors if any
Strict mode
With strictMode: true, a validation failure returns an IError object instead of the data, so your app only processes validated data. The error has statusCode: 422, message: 'Response validation failed' and the Zod issues in validationErrors. It is returned even when isShell is false.
const api = defineOneEntry('https://your-project.oneentry.cloud', {
token: 'your-app-token',
validation: {
enabled: true,
strictMode: true, // Strict mode
logErrors: true,
}
})
const user = await api.Users.getUser()
// Check if response is an error
if ('statusCode' in user) {
console.error('Validation failed:', user.message)
} else {
// Type-safe: user is IUserEntity
console.log('User:', user.identifier)
}
Additional fields format
By default, the SDK turns additionalFields from the array the API returns into an object keyed by marker, so you can read a field without knowing its index.
Default behavior (rawData: false)
const api = defineOneEntry('https://your-project.oneentry.cloud', {
token: 'your-app-token',
// rawData is false by default — no need to pass it explicitly
})
// additionalFields is an object keyed by marker:
const field = attribute.additionalFields['my_field']
console.log(field.value) // direct access, no array search needed
Raw mode (rawData: true)
To get the original API format (e.g. for backward compatibility), set rawData: true:
const api = defineOneEntry('https://your-project.oneentry.cloud', {
token: 'your-app-token',
rawData: true,
})
// additionalFields is the original array from the API:
const field = attribute.additionalFields.find(f => f.marker === 'my_field')
console.log(field.value)
Option
| Option | Type | Default | Description |
|---|---|---|---|
rawData | boolean | false | When false, additionalFields is transformed to an object keyed by marker. When true, the original array from the API is returned |
The rest of the normalization the SDK applies to attribute values (single-file unwrapping, numeric casting,
nullfor unset values, sorting byposition) is described in Attribute values.
Errors
With the default errors settings, the SDK doesn't throw: every method returns either the entity data or an error object. Check which one you got, for example with 'statusCode' in result.
To use try/catch instead, set isShell to false.
You can also pass custom handlers for specific status codes. The SDK calls them with the error object as the argument.
const api = defineOneEntry('https://your-project.oneentry.cloud', {
token: 'your-app-token',
langCode: 'en_US',
errors: {
isShell: false,
customErrors: {
400: (error) => console.error('Bad Request:', error.message),
401: (error) => console.error('Unauthorized:', error.message),
403: (error) => console.error('Forbidden:', error.message),
404: (error) => console.error('Not Found:', error.message),
429: (error) => console.error('Rate Limit Exceeded:', error.message),
500: (error) => console.error('Server Error:', error.message),
502: (error) => console.error('Bad Gateway:', error.message),
503: (error) => console.error('Service Unavailable:', error.message),
504: (error) => console.error('Gateway Timeout:', error.message),
},
},
})
isShell: false
When a request fails (an HTTP error such as 400, 401, 404 or 500, or a network error), the SDK throws instead of returning the error object, so you handle errors with try/catch:
try {
const result = await api.someMethod();
// Handling a successful result
} catch (error) {
// Error handling
}
isShell: true (default)
Errors are returned as values, so check the result type explicitly:
const result = await api.someMethod();
if ('statusCode' in result) { // Assumes the presence of a statusCode property on the error object
// Error handling
} else {
// Handling a successful result
}
In short, isShell: false gives you the familiar try/catch model, while isShell: true returns errors and results as values of the same type.
You can also write a type guard with the IError type:
import type { IError } from 'oneentry';
function isErrorResult(result: unknown): result is IError {
return (
!!result &&
typeof result === 'object' &&
('statusCode' in result || 'message' in result)
);
}
// Then use it like this:
const result = await api.someMethod();
if (isErrorResult(result)) {
// Error handling
console.error('Error:', result);
} else {
// Handling a successful result
console.log('Success:', result);
}
statusCode: 0: no usable response
Two cases return statusCode: 0, a value no HTTP response can have: a request that never reached the platform (since 1.0.168) and a response that isn't JSON (since 1.0.169):
// The request never reached the platform: a dropped connection, a timeout, DNS (v1.0.168).
const networkError = { statusCode: 0, message: 'TypeError: fetch failed', pageData: null, timestamp: '…' };
// An answer arrived, but it was not JSON (v1.0.169). The platform can answer
// 200 OK with content-type: text/html and its own admin page in the body.
const notJson = { statusCode: 0, message: 'Expected JSON from the platform, received text/html (HTTP 200): <!DOCTYPE html>…', pageData: null, timestamp: '…' };
Treat it as "there was no response", not "there is no record". Don't cache it, don't treat it as an empty result, and let a static build fail rather than bake a 404 into a page whose data still exists. When a non-JSON body comes with an error status, the SDK keeps the status the server actually sent, and the message names the content-type that arrived instead of JSON.
Earlier versions: before 1.0.168, the first case was a thrown TypeError that serialized to {}, with no statusCode and no message, so "no connection" looked the same as "no data". The second case surfaced as the SDK's own parser error (SyntaxError: Unexpected token '<'), and on the error branch as an empty object that didn't look like an error at all.
Next steps
- Products: build a product catalog with filtering and search.
- Users: sign users in and manage their profiles.
- Orders: create orders and take payments.
- Pages: fetch pages with their attributes, blocks and templates.
- Forms: read form definitions.
- Form data: submit and read form submissions.
- Importing types: import every SDK type from
oneentryoroneentry/types. - Bundle size: ESM build, tree-shaking, and Zod and socket.io loaded on demand.
- Attribute values: the normalized shape every attribute arrives in.
- Time intervals: expand schedules into concrete booking slots.