NOVAGATESNOVAGATES
NovaTechNovaCom
NovaTechNovaCom
AR Tools
AI Tools
Services
Technologies
Solutions
Packages
Blog
LoginDemo store
NOVATECH
Demo store
Blog
Language
For Developers

Build Faster. Integrate Smarter. Scale Seamlessly.

Whether you're launching a feature-rich e-commerce site, building a virtual try-on experience, or powering a scalable AI engine, our developer-first architecture makes it easy to implement, customize, and deploy powerful AR and AI tools into your digital stack.

What We Offer

Developer-Friendly by Design

We offer flexible, modular solutions that can plug directly into your infrastructure, no heavy lifting required.

RESTful APIs & Webhooks

Pre-built SDKs for web & mobile

Clean, well-documented codebase

Full tech support & integration guides

Seamless Integration with Any Tech Stack

Our platform is built to fit yours. Novagates works across all major environments, frameworks, and CMS platforms, from Shopify and Magento to custom-built systems.

Frontend agnostic

Headless architecture ready

Easy plugin options for CMS & storefronts

1

4

Authenticating to the REST APIs

Your backend signs a client_assertion with its ES256 private key and POSTs it to /api/token, receiving a short-lived (5 min) access_token in return. You hand that to your frontend, which appends it to the SDK <script> tag as ?sessionToken=…. The SDK reads it off its own src and attaches it as Authorization: Bearer on every Novagates call.

Keep server-side only

  • API key (Client ID)
  • ES256 private key (private JWK)
  • Signing the client_assertion
  • POSTing /api/token

Safe to ship to the browser

  • Short-lived access_token (≤ 5 min) passed as ?sessionToken=…
  • The SDK <script> tag with sessionToken + module

Refresh by re-fetching from your backend before the 5-minute expiry. Never send the private key or client_assertion to the browser.

Install

# Requires bash, curl, jq.
# Pre-sign client_assertion with one of the language tabs below.

Implementation

CLIENT_ASSERTION="$(node ./scripts/sign-client-assertion.js)"
curl -sS -X POST https://novagates.com/api/token \
-H 'Content-Type: application/json' \
-d "{
\"client_assertion\": \"${CLIENT_ASSERTION}\",
\"client_assertion_type\": \"urn:ietf:params:oauth:client-assertion-type:jwt-bearer\"
}" | jq -r .access_token

POST /api/token — Request & response schema

The only endpoint your backend calls directly. Everything else is invoked by the SDK on your behalf using the sessionToken you embed on its <script> tag.

Request

POST · application/json or application/x-www-form-urlencoded

  • client_assertion (required) — ES256-signed JWT. Header carries the public jwk (kty/crv/x/y). Payload: iss=sub=[API_KEY], aud=https://novagates.com/api/token (exact match), unique jti.
  • client_assertion_type (required) — must be exactly: urn:ietf:params:oauth:client-assertion-type:jwt-bearer
  • dpop_jkt (optional) — base64url thumbprint (42–44 chars) of an ephemeral browser key to bind the token to.

Response

200 OK · application/json

  • access_token — HS256-signed JWT. Claims: sub=[API_KEY], cnf.jkt=bound thumbprint, iss=novagates, unique jti.
  • token_type — "Bearer"
  • expires_in — 300 (5 minutes)

Errors: 400 for invalid input, 401 when the header jkt doesn't match the stored [API_KEY] jkt, when aud is missing or isn't exactly the /api/token URL, or when the jti has been replayed.

SDK Integration — Web & Mobile

Initialize the SDK by embedding a sessionToken on its <script> tag. Your frontend fetches the token from your backend (which calls /api/token), injects the SDK script tag with ?sessionToken=… and ?module=…, and the SDK reads it off its own src and attaches it as Bearer on every Novagates call.

Init flow

  1. Your frontend fetches a token from your own /api/sdk-token endpoint.
  2. Your backend signs an ES256 client_assertion, exchanges it at POST /api/token for a 5-minute access_token, and returns it as sessionToken.
  3. The frontend injects the SDK <script> tag with ?sessionToken=<token>&module=<module-name>.
  4. The SDK calls Novagates.init({ rootId, productsSource, immediate: true }), reads sessionToken off its own src, and sends it as Authorization: Bearer on every request.
  5. Refresh by re-fetching before the 5-minute expiry (or just reload the page) to avoid 401s.

Implementation

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Novagates Virtual Try-On</title>
</head>
<body>
<div id="novagates-root"></div>
<script>
(async function bootNovagates() {
// 1. Mint a short-lived sessionToken on YOUR backend.
const res = await fetch("/api/sdk-token", { credentials: "include" });
if (!res.ok) throw new Error("Failed to fetch SDK session token");
const { sessionToken } = await res.json();
// 2. Inject the SDK loader with sessionToken + module on the URL.
const params = new URLSearchParams({
sessionToken: sessionToken,
module: "virtual-try-on",
});
const script = document.createElement("script");
script.src =
"https://cdn.novagates.com/sdk/novagates-sdk.js?" + params.toString();
script.async = true;
script.onload = function () {
// 3. Init once the loader has registered the global.
window.Novagates.init({
rootId: "novagates-root",
productsSource: "/api/products.json",
immediate: true,
});
};
document.body.appendChild(script);
})();
// 4. Listen for product events emitted by the SDK.
window.addEventListener("sdk:addToCart", function (e) {
console.log("[novagates] add to cart", e.detail);
// forward to your cart, analytics, etc.
});
</script>
</body>
</html>

Content Security Policy

The SDK runs inside your page, so it is governed by your site's Content Security Policy, not ours. If you enforce a strict CSP, allow the directives below before you go live - otherwise the SDK fails in ways that are hard to attribute from the outside: a black iframe, or a CompileError thrown from inside a minified bundle.

A srcdoc iframe does not isolate the SDK from your policy

The SDK runs in an about:srcdoc frame, and such a frame has no URL to derive a policy from - it inherits the embedding document's CSP, and its origin. Assuming the iframe isolates the SDK from your policy is the single most common misunderstanding here, and it is wrong.

DirectiveSources to allowWhy
script-src'self' https://cdn.novagates.comThe loader, the module bundles and the ONNX Runtime .mjs are all script src off the CDN.
script-src'wasm-unsafe-eval'MediaPipe, ONNX Runtime and TFLite all call WebAssembly.compile / instantiate, which CSP gates. Without it the SDK loads and then fails from inside with a CompileError - no blocked-resource message, so it is the hardest failure to attribute. 'unsafe-eval' also works but is strictly wider and should not be used.
connect-src'self' blob: https://cdn.novagates.comModel weights (.nova), MediaPipe .task landmarkers, .wasm runtimes, .glb / .hdr scene assets and the category manifests are all fetched. TFLite weights are decoded into a Blob and re-fetched through an object URL, which is why blob: belongs here too.
worker-src'self' blob: https://cdn.novagates.comThe inference worker is bundled inline and instantiated from a blob: URL. Omit this directive and it does NOT fall back to default-src - the chain is child-src, then script-src, then default-src - so it silently inherits whatever script-src allows. The refusal itself does reach the console and the violation report - it is the SDK's fallback to main-thread inference that is silent, so the page keeps working and only gets slower.
media-src'self' blob: data:Uploaded and recorded video plus generated audio play through URL.createObjectURL. The live-camera path uses srcObject, which CSP does not gate - so camera try-on keeps working while upload try-on breaks, which is a nasty way to find out.
style-src'self' 'unsafe-inline'The SDK renders into your page and styles its own UI inline. Absent a style-src it falls back to default-src, so a strict policy renders the try-on surface unstyled rather than blocking it — visibly wrong, with nothing thrown. This is the value our own site serves, in Report-Only, while running the same SDK; if yours is stricter, prove it in Report-Only before promoting. Be clear-eyed that this one is a real relaxation of your policy and the only directive here that is: 'unsafe-inline' on style-src permits any injected CSS on your pages, so it is worth confirming you want it rather than pasting it. A nonce or hash works for styles too if you would rather not, at the cost of coordinating with each SDK release.
font-src'self' data:Icon and UI fonts the SDK inlines as data: URIs. Falls back to default-src when omitted, which drops them to the browser default — again visible, not thrown.
img-src'self' data: blob: https://cdn.novagates.comCanvas captures the SDK produces as data: and blob: URLs, plus the image assets it loads from the origin it is itself served from. Your PRODUCT imagery is not covered here — that comes from whatever origin your catalog points at, so add that origin yourself. This is also the one row not derived from our own middleware policy: that file allows the same origin in img-src for an unrelated reason (our marketing media CDN shares it), so it corroborates this row rather than proving it. If you would rather not grant it, drop it and watch the Report-Only reports.

The bootstrap above is an inline script — give it a nonce

The Vanilla JS example in the integration section above puts its boot function in an inline script tag on your page. Under a strict script-src that tag is blocked and the SDK never loads at all — this is the first thing anyone hits who copies both the snippet and the policy. Emit a per-request nonce on the tag and in the header: add a nonce attribute to the opening script tag of the Vanilla JS example above, with the same value you substitute for the nonce placeholder in the snippets below. Or move the function into a file that 'self' already covers, which needs no nonce at all. The example is left without a nonce attribute on purpose, because the value has to be generated per request and a copied placeholder would be worse than none. Do not reach for 'unsafe-inline': it re-enables every inline script on your site, which is a far higher price than this needs. AND MIND WHAT THE NONCE DOES TO A POLICY YOU ALREADY HAVE — under CSP Level 3, a script-src containing a nonce or hash makes 'unsafe-inline' in that same directive IGNORED. If you serve script-src 'self' 'unsafe-inline' today and simply append this nonce, every other inline script on your storefront (tag manager, analytics, chat widget) stops running, site-wide, with nothing on this page to warn you. Nonce them all in the same change, or externalise this one function instead.

# THESE ARE THE SDK'S DIRECTIVES, NOT A COMPLETE POLICY. Merge each source
# expression into the directive you already serve - pasting this block as your
# whole CSP replaces yours and breaks the rest of your site.
#
# NOTE on the nonce: a script-src that contains a nonce makes 'unsafe-inline'
# in that same directive IGNORED (CSP Level 3). If you serve 'unsafe-inline'
# today, nonce your other inline scripts in the same change or they stop
# running.
#
# Roll it out FIRST in Report-Only, with a collector at /csp-report, and read
# the reports before you promote. Shown wrapped for readability - send it as
# ONE header line; HTTP header folding is obsolete and proxies will not
# reassemble it.
add_header Content-Security-Policy-Report-Only "
script-src 'self' 'wasm-unsafe-eval' https://cdn.novagates.com 'nonce-<PER-REQUEST>';
connect-src 'self' blob: https://cdn.novagates.com;
worker-src 'self' blob: https://cdn.novagates.com;
style-src 'self' 'unsafe-inline';
font-src 'self' data:;
media-src 'self' blob: data:;
img-src 'self' data: blob: https://cdn.novagates.com;
report-uri /csp-report;
report-to csp-endpoint
" always;
# report-to needs this companion header to bind the group name to a URL.
add_header Reporting-Endpoints 'csp-endpoint="https://your-site.example/csp-report"' always;

Check connect-src if your integration calls the REST API from the browser. The values above cover what the SDK fetches from the CDN and from your own origin; the token exchange at novagates.com runs on your backend, where CSP does not apply. If you add a browser-side call to that API yourself, allow its origin in connect-src too.

Start Report-Only, then promote

Ship the policy on Content-Security-Policy-Report-Only with a reporting endpoint first, and leave it there for a full traffic cycle before promoting it to enforcing. That is the same ordering we hold ourselves to on this site.

Declare both report-uri and report-to

report-uri is deprecated in the spec but is the only one Firefox and Safari implement, while Chrome and Edge ignore it entirely whenever report-to is present. Declaring only one collects nothing from a whole browser family - which looks identical to having no violations.

No frame-src entry is needed for the SDK: an about:srcdoc frame is not gated by that directive because it inherits instead. That changes only if a future release moves the SDK to a real cross-origin URL.

Drop-in Plugins

For WordPress / WooCommerce, Magento, Shopify, and OpenCart we ship the full plugin. It handles client_assertion signing, /api/token exchange, sessionToken rotation, and catalog sync for you — no signing keys to manage. Download links and installation instructions live inside your dashboard.

WordPressWooCommerceMagentoShopifyOpenCart

Products Endpoint & Schema

The SDK consumes a JSON catalog conforming to the schema below. The `technologies` field decides which try-on / analysis / 3D pipeline activates per product; `product_types` and `category` drive the UX.

simple

Single SKU, one set of attributes

configurable

Parent SKU exposes variants (shades, sizes)

variable

Variants with independent pricing

// GET /api/products → Product[]
//
// Three product shapes, distinguished by `type_id`:
// "simple" — single SKU, single set of attributes
// "configurable" — parent SKU exposes child variants (size/shade swatches)
// "variable" — parent SKU with priced variants (e.g. fragrance volumes)
//
// Every product family below extends this base. Required vs null fields
// depend on the family — see the next tabs.
interface Product {
/* identity */
id: number;
uid: string;
sku: string; // unique merchant SKU
type_id: "simple" | "configurable" | "variable";
name: string;
brand: string | null;
manufacturer: string | null;
country_of_manufacture: string | null;
made_in: string | null;
/* taxonomy */
category: string; // e.g. "Women > Makeup > Face > Foundation"
product_types: string; // see family tabs
product_type_id: string; // your CMS taxonomy id
/* commerce */
url_key: string;
url_path: string;
price: { regularPrice: { amount: { currency: string; value: number } } };
/* media */
image: { url: string };
swatch_image: { url: string };
thumbnail: { url: string };
small_image?: { url: string };
/* try-on / 3D pipeline switch */
is_product_try_on: 0 | 1;
is_product_skin_improvement: 0 | 1;
asset_url: string | null; // PNG texture, .glb, or null per family
technologies: string; // pipe-separated; activates SDK modules
/* configurable / variable parents */
variants?: Array<{ product: Product }>;
}

Join the Dev Community

Novagates isn’t just a platform, it’s a partner.

We support developers every step of the way, with expert onboarding, shared codebases, and a growing developer community.

Start Growing Your Business

We deliver cutting-edge solutions that are secure, scalable, and customer-focused.

Gates

  • VTO Tech
  • AI Tech
  • Nova AI Assistant
  • AR, VR Novaverse
  • Visualization Tech

Hubs

  • Makeup
  • Accessories
  • Lenses
  • Nails
  • Hair
  • Mix'nMatch
  • Skin
  • Face
  • Luxe Look
  • Smart Mirror Glam

Suites

  • Lips
  • Eyes
  • Face
  • Head Accessories
  • Face Accessories
  • Neck Accessories
  • Hand Accessories
  • Makeup Mix'nMatch
  • Accessories Mix'nMatch
  • Makeup & Accessories Mix'nMatch
  • Skin Insights
  • Face Analyzer
  • Personality Finder
  • Style Scanner Tech
  • Look Book
  • AR Interior
  • Space Visualization
  • Product Visualization

Company

  • About us
  • Founders
  • Contact Us
  • Careers
  • Blog

Resources

  • Contact Us
  • Terms and Conditions
  • Privacy Policy
  • Cookies
NOVATECH
Novagates. All rights reserved © 2026
LinkedInFacebookInstagramThreadsSnapchatXYouTubeTikTok