Integration
This guide describes the end-to-end workflow for taking a profile that a user designs in the <nu-evolution-editor> and integrating it with your own application and the nuEvolution backend (the Exchange API).
There are two moving parts:
- The editor (this library) runs in the browser. It is where the end user designs a profile. The library hands your application a profile ID.
- The Exchange API runs on nuEvolution's servers. Using the profile ID, your backend can read a profile's details, update its basic properties, delete it, and turn one or more profiles into an order.
Everything below hangs off the profile ID returned by the library.
Call the Exchange API from your backend
The Exchange API is authenticated with a secret header token (nuit-exchange-token). Treat it like any server-side secret - make these requests from your backend, never directly from the browser, so the token is not exposed to end users.
The flow at a glance
The sequence below shows the conversation between everyone involved. Note the boundary: the editor runs in the browser, while the Exchange API calls are made from your backend, so the secret token never reaches the browser.
- Open the editor - the user designs a profile in
<nu-evolution-editor>. - Capture the ID - your page calls
saveProfile()(or listens for thenuit::profile-savedevent) and receives a profile ID from the library. - Persist the ID - store that ID in your backend, linked to the user/cart/session it belongs to.
- Read details - your backend fetches the profile's properties through the
GETroute (everything except geometry). - Update - change basic properties (name, remark, …) through the
PUTroute. The profile geometry is not edited through the API; it is changed by reopening the profile in the editor and saving again (see Update the geometry). - Delete - remove a profile through the
DELETEroute. - Order - once you have one or more saved profiles, submit them as an order through the
POSTroute.
Authentication & environments
All Exchange API requests are authenticated with an API-key header:
| Header | Value |
|---|---|
nuit-exchange-token | Your secret Exchange API token. |
Choose the base URL that matches the environment the editor is pointed at via its env attribute:
Editor env | Base URL |
|---|---|
prod (default) | https://api.nu-it.at/exchangeapi |
staging | https://stg-api.nu-it.at/exchangeapi |
dev | https://dev-api.nu-it.at/exchangeapi |
The endpoint paths below are relative to the chosen base URL.
1. Open the editor and capture the profile ID
Embed the editor and let the user design a profile, then obtain the profile ID. There are two ways to receive it - both return the same ProfileData object:
import type { NuEvolutionEditor } from '@nuitdev/evo-embedded'
const editor = document.querySelector<NuEvolutionEditor>('nu-evolution-editor')!
const { profileId, externalId } = await editor.saveProfile()
// → send profileId (and externalId) to your backendimport { Capability } from '@nuitdev/evo-embedded'
editor.capabilities = [Capability.SAVE_PROFILE] // adds a save button to the toolbar
editor.addEventListener('nuit::profile-saved', (event) => {
const { profileId, externalId } = event.detail
// → send profileId (and externalId) to your backend
})saveProfile() resolves to a ProfileData object:
| Field | Type | Description |
|---|---|---|
profileId | string | The nuEvolution profile ID. Always present. |
externalId | string | null | Your own external ID for this profile, if one was assigned; otherwise null. |
See Working with profiles for the full save/upsert semantics.
2. Persist the ID in your backend
Store the returned ID against whatever entity owns it in your system (a cart line, a saved configuration, an order draft, …). This stored ID is the key you pass to every Exchange API call.
Which ID to send - and the external flag
The profile routes (GET / PUT / DELETE) take the ID as a path parameter, plus an optional external query parameter that tells the API how to interpret that ID. It defaults to false:
| The ID you stored | Path {id} | external |
|---|---|---|
profileData.profileId (nuEvolution ID) | that value | false (or omit it) |
profileData.externalId (your own ID) | that value | true |
TIP
Because external defaults to false, you only need to send it when you stored your own external ID (then pass external=true). The examples below use the nuEvolution profileId, so they omit it.
3. Read profile details - GET
Fetch a profile's properties. The embed variant always omits the geometry field.
GET /exchangeapi/production/embed/profiles/{id}Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | The profile ID. |
external | query | boolean | No (default false) | Set true when id is your own external ID. |
curl "https://api.nu-it.at/exchangeapi/production/embed/profiles/12345" \
-H "nuit-exchange-token: $NUIT_EXCHANGE_TOKEN"Responses
| Status | Meaning |
|---|---|
200 | The profile, as a Profile object. |
404 | No profile with that ID exists. |
The Profile object
This is the shape returned by GET and the shape you send back on PUT.
| Field | Type | Description |
|---|---|---|
id | integer | nuEvolution profile ID. |
externalId | string | null | Your external profile ID. |
externalData | object | Free-form JSON reserved for the external system. |
name | string | Profile name. |
remark | string | Profile remark. |
materialId | integer | nuEvolution material ID associated with the profile. |
material | object | Material object. |
length | number | Profile length [mm]. |
quantity | integer | Profile quantity. Only populated when the profile is embedded in an order/offer. |
blank | number | Profile blank - sum of all segment lengths [mm]. |
tiltingsCount | integer | Number of tiltings. |
hemsCount | integer | Number of hems. |
m2 | number | Profile surface area [m²]. |
weight | number | null | Profile weight = blank × length × material.weight [kg]. |
bendingLength | number | Bending length [mm]. |
conicalBase | integer | Conical base flag/value. |
unit | string | Unit used for length values (e.g. "mm"). |
image | string | Profile preview image URL. |
punches | object[] | Punch definitions. Contact your nuIT representative for details. |
customData | object | Free-form JSON reserved for customer-specific data. |
specials | object[] | Profile specials. Contact your nuIT representative for details. |
positions | object[] | Length × quantity variations of the profile (see below). |
updatedAt | integer (int64) | Last update timestamp (unix seconds). |
updatedBy | integer | nuEvolution user ID of the last editor. |
positions[] - profile position fields
Each entry in positions[] is a length × quantity variation with its own metadata and pricing:
| Field | Type | Description |
|---|---|---|
id | integer | Profile position ID. |
externalId | string | External profile position ID. |
quantity | integer | Position quantity. |
length | number | Position length [mm]. |
weight | number | null | Position weight [kg]. |
weightOverwritten | number | null | Overridden weight value, if the caller overrode it. |
m2 | number | Position surface area [m²]. |
remark | string | Position remark. |
discount | number | Position discount [%]. |
price | number | Total price for this position = priceForOne × quantity. |
priceForOne | number | Price for one piece of this position. |
pricePerUnit | number | Price per unit of length (typically per meter). |
costPrice | object | Free-form cost-price breakdown. |
warnings | object[] | Validation/processing warnings attached to the position. |
customData | object | Free-form customer-specific data. |
externalData | object | Free-form JSON reserved for the external system. |
overrideValues | object | Per-field overrides applied to this position. |
useOriginalPrice | boolean | When true, the original price is used instead of recomputed. |
originalPrice | (number/object) | Original price before any overrides. |
4. Update basic properties - PUT
Update a profile's descriptive properties (such as name and remark).
PUT /exchangeapi/production/embed/profiles/{id}Parameters - identical to GET: id (path, required) and external (query, optional, defaults to false).
Request body - a partial Profile object (fields above). The body is JSON.
Required vs. optional fields
There are no required fields - send only the properties you want to change. The recommended pattern is to GET the profile first, modify the fields you need, then PUT the result back.
- Commonly updated:
name,remark, and your own identifiers/metadata (externalId,externalData,customData). - Computed: fields such as
blank,m2,weight,tiltingsCount,hemsCount,bendingLength,positions,image,updatedAtandupdatedByare calculated/maintained by nuEvolution; they are returned for display and are recalculated server-side.
curl -X PUT "https://api.nu-it.at/exchangeapi/production/embed/profiles/12345" \
-H "nuit-exchange-token: $NUIT_EXCHANGE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Window sill - left",
"remark": "Customer approved"
}'Responses
| Status | Meaning |
|---|---|
200 | Updated profile, returned as a Profile (no geometry). |
404 | No profile with that ID exists. |
5. Update the geometry - via the editor
The profile geometry is never updated through the API. To change a profile's geometry, take it back through the library:
- Load the existing profile into the editor by setting its
profile-id(setid-type="external"if you stored your own external ID). - Let the user edit the geometry.
- Call
saveProfile()again. Because aprofile-idis set, the save is an upsert that updates the same profile - its ID does not change.
import { EditorIdType } from './EditorIdType'
editor.profileId = '12345'
editor.idType = EditorIdType.DEFAULT // or 'EditorIdType.EXTERNAL'
// … user edits the geometry …
await editor.saveProfile()See Working with profiles → Saving a profile for the upsert details.
6. Delete a profile - DELETE
Remove a profile by ID.
DELETE /exchangeapi/production/embed/profiles/{id}Parameters - identical to GET: id (path, required) and external (query, optional, defaults to false).
curl -X DELETE "https://api.nu-it.at/exchangeapi/production/embed/profiles/12345" \
-H "nuit-exchange-token: $NUIT_EXCHANGE_TOKEN"Responses
| Status | Meaning |
|---|---|
204 | Profile deleted (no body). |
404 | No profile with that ID exists. |
7. Create an order - POST
Once you have one or more saved profiles, submit them as an order. This endpoint accepts a batch payload - a flat list of profile references with quantity and length.
POST /exchangeapi/shop/embed/ordersRequest body - a BatchOrderCreate object. The body itself is required.
| Field | Type | Required | Description |
|---|---|---|---|
batches | object | Yes | Container for the order's line items (see below). |
externalId | string | Optional | Your external order ID (e.g. the ID from your ERP/shop). |
externalData | object | Optional | Free-form JSON reserved for the external system. |
details | object | Optional | Cart-level details (project name, shipping type, addresses, …). Out of scope for this guide. |
batches holds two arrays - profiles[] and products[]. Provide your profile references in batches.profiles[].
batches.profiles[] - profile reference
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | One of id / externalId | nuEvolution profile ID. |
externalId | string | One of id / externalId | Your external profile ID. |
quantity | integer | Optional | Quantity to order. Defaults to 1 |
length | number | Optional | Profile length in mm. If not set, the length set in the embedded editor is used. |
Mapping the library ID into a batch
profileData.profileId is the nuEvolution ID returned as a string. To use it as the numeric batches.profiles[].id, convert it (e.g. Number(profileId)), or reference the profile by externalId instead.
curl -X POST "https://api.nu-it.at/exchangeapi/shop/embed/orders" \
-H "nuit-exchange-token: $NUIT_EXCHANGE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"externalId": "ORDER-2026-0001",
"batches": {
"profiles": [
{ "id": 12345, "quantity": 2, "length": 1500 },
{ "id": 12346, "quantity": 1, "length": 980 }
]
}
}'Responses
| Status | Meaning |
|---|---|
200 | Order created, returned as an Order object. Each profile in profiles[] has its geometry omitted. |
The response Order object contains the created order (id, number, status, the resolved profiles[], pricing under sales, and so on). Its full shape - together with the details, products, and address structures omitted above - is beyond the scope of this guide; reach out to your nuIT representative if you need those fields.