Decoloop CPQ Embedded Guide

Note: If your integration needs to route through api.decoloop.com for multiple CPQ applications, suppliers, or instances, see the Proxy-Based Embedded CPQ Guide.

Introduction

Decoloop CPQ can be embedded in a third-party website or application using an iframe. This allows users to configure CPQ products without leaving the host application, while the host application can retrieve the saved project and optionally send it to manufacturing through the Decoloop CPQ Gateway API.

This guide describes the recommended integration flow, iframe parameters, browser event handling, authentication, and the Embedded Gateway API endpoints.

Integration Flow

A typical embedded integration works as follows:

  1. Authenticate: The third-party application requests a bearer token from the Decoloop CPQ Gateway using its API key and credentials.
  2. Embed CPQ: The host application opens Decoloop CPQ in an iframe using the bearer token and isEmbedded=true.
  3. Configure project: The user configures one or more products in the embedded CPQ experience.
  4. Receive iframe event: When the user saves or closes a project, Decoloop CPQ sends a browser message event to the parent window. The event payload contains the project ID.
  5. Load project data: The host application calls POST /api/Gateway/Embedded/LoadProject with the project ID to retrieve the saved project.
  6. Send to manufacturing: If the user confirms the order, the host application calls POST /api/Gateway/Embedded/SendProject.

Prerequisites

To connect to a Decoloop CPQ instance, third-party applications need an API key provided by Decoloop first. Please contact us through phone or email to obtain this key.

The API key is specific to the third-party application and can be reused across multiple CPQ instances when configured by Decoloop.

You also need:

  • The base URL of the target Decoloop CPQ instance, for example https://sandbox.decoloop.com.
  • A valid domainName, username, and password.
  • Permission to use the Embedded Gateway API.

Step 1: Create a Token

Create a token using the Decoloop CPQ Gateway.

Endpoint: POST /token

Request

POST https://sandbox.decoloop.com/token
Content-Type: application/json

{
  "domainName": "test",
  "username": "test",
  "password": "test",
  "apiKey": "test-123-test"
}

Response

{
  "access_token": "aaabbbccc",
  "token_type": "bearer",
  ".issued": "8-10-2018 15:39:41",
  ".expires": "2018-10-22T15:39:41.1959628+02:00",
  "refresh_token": "dddeeefff"
}

The access_token is used in two places:

  1. As the token query parameter when opening the embedded iframe.
  2. As the bearer token for Embedded Gateway API calls.

Authentication for Embedded API Requests

All Embedded Gateway API endpoints require the bearer token returned by POST /token.

Send the token in the Authorization header:

Authorization: bearer aaabbbccc

For example:

GET https://sandbox.decoloop.com/api/Gateway/Embedded/GetAllSuppliers
Authorization: bearer aaabbbccc
Accept: application/json

The token determines which CPQ instance, licensee, language, supplier configuration, material catalog, and project data the caller can access. Do not assume that IDs are globally unique across tenants or CPQ instances.

Step 2: Create an Iframe

Create an iframe using the Decoloop CPQ URL and the required query parameters:

  • token: the access_token from Step 1.
  • isEmbedded=true: enables embedded behavior.

Example iframe URL:

https://sandbox.decoloop.com?token=ACCESS_TOKEN&isEmbedded=true

Example HTML:

<iframe
  src="https://sandbox.decoloop.com?token=ACCESS_TOKEN&isEmbedded=true"
  width="100%"
  height="800"
  title="Decoloop CPQ"
></iframe>

Step 3: Listen for Project Events

When a project is saved or closed, Decoloop CPQ sends a message to the parent window. The message contains the saved project ID.

window.addEventListener('message', event => {
  // Always validate the event origin before trusting the payload.
  if (event.origin !== 'https://sandbox.decoloop.com') {
    return;
  }

  const data = event.data;

  if (!data || typeof data !== 'object') {
    return;
  }

  const projectId = data.payload;

  switch (data.type) {
    case 'CLOSE_PROJECT':
      onCloseProject(projectId);
      break;

    case 'SAVE_PROJECT':
      onSaveProject(projectId);
      break;
  }
});

Event Types

Event typeDescription
SAVE_PROJECTThe user saved a project. Use the project ID to load the full project data.
CLOSE_PROJECTThe embedded CPQ experience was closed. The payload may contain the current project ID.

Step 4: Load or Send the Project

After receiving a project ID from the iframe, use the Embedded Gateway API:

ActionEndpoint
Load a saved projectPOST /api/Gateway/Embedded/LoadProject
Send a project to manufacturingPOST /api/Gateway/Embedded/SendProject

Embedded Gateway API

The following endpoints are available for embedded integrations.

All examples assume this base URL:

https://sandbox.decoloop.com

All examples also assume this authorization header:

Authorization: bearer ACCESS_TOKEN

Load a Project

Loads a stored project by project ID.

Endpoint: POST /api/Gateway/Embedded/LoadProject

Use this endpoint after receiving a SAVE_PROJECT or CLOSE_PROJECT event from the iframe.

Request

POST https://sandbox.decoloop.com/api/Gateway/Embedded/LoadProject
Authorization: bearer ACCESS_TOKEN
Content-Type: application/json
Accept: application/json

{\n  \"projectId\": 69623,\n  \"includePurchasePrices\": false\n}

Request Body

FieldTypeRequiredDescription
projectIdintegerYesID of the project to load. This is usually the project ID received from the iframe event payload.
includePurchasePricesboolean or nullNoWhen true, purchase prices are included if the authenticated user has the required embedded rights. Use false unless purchase prices are explicitly needed.

Successful Response

200 OK returns the full project.

{
  "id": 69623,
  "projectNumber": "0001.00482",
  "reference": "Sandbox Customer",
  "created": "2026-06-05T12:17:35.303Z",
  "lastOpened": "2026-06-05T12:17:35.303Z",
  "lastModified": "2026-06-05T12:21:58.31Z",
  "projectStatus": 1,
  "price": {
    "totalPrice": 667.56,
    "totalPriceBeforePromotions": 667.56,
    "priceGroups": [
      {
        "code": "MATERIAL",
        "description": "Material",
        "displayOrder": 998,
        "elements": [
          {
            "code": "1234",
            "quantity": 15.07,
            "description": "Fabric A",
            "unit": "m",
            "unitPriceBeforePromotion": 19.36,
            "unitPrice": 19.36,
            "totalPrice": 291.7552,
            "totalPriceBeforePromotion": 291.7552,
            "sbnid": 2,
            "purchasePriceInfo": {
              "unitPurchasePrice": 0.0,
              "totalPurchasePrice": 0.0
            }
          }
        ]
      },
      {
        "code": "WAGE",
        "description": "Wage",
        "displayOrder": 999,
        "elements": [
          {
            "code": "C1234",
            "quantity": 10.0,
            "description": "NL1211: Weefstof band 8",
            "unit": "bn",
            "unitPriceBeforePromotion": 37.58,
            "unitPrice": 37.58,
            "totalPrice": 375.8,
            "totalPriceBeforePromotion": 375.8,
            "sbnid": 2,
            "purchasePriceInfo": {
              "unitPurchasePrice": 18.79,
              "totalPurchasePrice": 187.9
            }
          }
        ]
      }
    ],
    "promotions": [],
    "discountAmount": 0.0,
    "totalPurchasePrice": 187.9
  },
  "polygons": [
    {
      "id": 95032,
      "productCategoryId": 10001,
      "modelCode": "1100",
      "modelDescription": "Gordijn, Vliesband",
      "width": 200.0,
      "height": 200.0,
      "categoryLinks": [
        {
          "id": 401,
          "description": "Gordijn",
          "childCategoryId": 2001,
          "childCategoryDescription": "Gordijnstoffen",
          "categoryLinkMaterial": {
            "materialCode": "1234",
            "materialId": 55407,
            "materialDescription": "Fabric A",
            "price": {
              "totalPrice": 323.01,
              "totalPriceBeforePromotions": 323.01,
              "priceGroups": [
                {
                  "code": "MATERIAL",
                  "description": "Material",
                  "displayOrder": 998,
                  "elements": [
                    {
                      "code": "1234",
                      "quantity": 8.92,
                      "description": "Fabric A",
                      "unit": "m",
                      "unitPriceBeforePromotion": 19.36,
                      "unitPrice": 19.36,
                      "totalPrice": 172.6912,
                      "totalPriceBeforePromotion": 172.6912,
                      "sbnid": 2,
                      "purchasePriceInfo": {
                        "unitPurchasePrice": 0.0,
                        "totalPurchasePrice": 0.0
                      }
                    }
                  ]
                },
                {
                  "code": "WAGE",
                  "description": "Wage",
                  "displayOrder": 999,
                  "elements": [
                    {
                      "code": "C1234",
                      "quantity": 4.0,
                      "description": "C1234: Confection tape 8",
                      "unit": "bn",
                      "unitPriceBeforePromotion": 37.58,
                      "unitPrice": 37.58,
                      "totalPrice": 150.32,
                      "totalPriceBeforePromotion": 150.32,
                      "sbnid": 2,
                      "purchasePriceInfo": {
                        "unitPurchasePrice": 18.79,
                        "totalPurchasePrice": 75.16
                      }
                    }
                  ]
                }
              ],
              "promotions": [],
              "discountAmount": 0.0,
              "totalPurchasePrice": 75.16
            },
            "properties": [
              {
                "id": 12842,
                "interfaceKey": "Curtain.Fabric.Quantity",
                "propertyId": 28,
                "dataType": 4,
                "description": "Aantal",
                "value": "1",
                "displayLabel": "Aantal",
                "displayOrder": 1,
                "controlType": 1,
                "listValues": null,
                "isVisible": true,
                "exclude": false
              },
              {
                "id": 12839,
                "interfaceKey": "Curtain.Fabric.Distribution",
                "propertyId": 16,
                "dataType": 11,
                "description": "Distribution",
                "value": "S",
                "displayLabel": "Distribution",
                "displayOrder": 2,
                "controlType": 2,
                "listValues": [
                  {
                    "interfaceKey": "Curtain.Fabric.Distribution.Pair",
                    "description": "Stel",
                    "value": "S",
                    "remarks": null,
                    "imageUrl": null
                  },
                  {
                    "interfaceKey": "Curtain.Fabric.Distribution.Left",
                    "description": "Stuk links",
                    "value": "SL",
                    "remarks": null,
                    "imageUrl": null
                  },
                  {
                    "interfaceKey": "Curtain.Fabric.Distribution.Right",
                    "description": "Stuk rechts",
                    "value": "SR",
                    "remarks": null,
                    "imageUrl": null
                  }
                ],
                "isVisible": true,
                "exclude": false
              },
              {
                "id": 12855,
                "interfaceKey": "Curtain.Fabric.Tape",
                "propertyId": 72,
                "dataType": 11,
                "description": "Bandsoort",
                "value": "8",
                "displayLabel": "Band",
                "displayOrder": 3,
                "controlType": 2,
                "listValues": [
                  {
                    "interfaceKey": "Curtain.Fabric.Tape.6",
                    "description": "6 cm",
                    "value": "6",
                    "remarks": null,
                    "imageUrl": null
                  },
                  {
                    "interfaceKey": "Curtain.Fabric.Tape.8",
                    "description": "8 cm",
                    "value": "8",
                    "remarks": null,
                    "imageUrl": null
                  },
                  {
                    "interfaceKey": "Curtain.Fabric.Tape.10",
                    "description": "10 cm",
                    "value": "10",
                    "remarks": null,
                    "imageUrl": null
                  }
                ],
                "isVisible": true,
                "exclude": false
              },
              {
                "id": 12827,
                "interfaceKey": "Curtain.Fabric.Pleat",
                "propertyId": 3,
                "dataType": 11,
                "description": "Plooi",
                "value": "V",
                "displayLabel": "Plooi",
                "displayOrder": 11,
                "controlType": 2,
                "listValues": [
                  {
                    "interfaceKey": "Curtain.Fabric.Pleat.Flat",
                    "description": "Ongeplooid",
                    "value": "G",
                    "remarks": null,
                    "imageUrl": null
                  },
                  {
                    "interfaceKey": "Curtain.Fabric.Pleat.Single",
                    "description": "Enkele plooi",
                    "value": "E",
                    "remarks": null,
                    "imageUrl": null
                  },
                  {
                    "interfaceKey": "Curtain.Fabric.Pleat.Double",
                    "description": "Vlinderplooi",
                    "value": "V",
                    "remarks": null,
                    "imageUrl": null
                  }
                ],
                "isVisible": true,
                "exclude": false
              }
            ],
            "supplier": {
              "id": 47,
              "sbnid": 2,
              "searchName": "SANDBOX",
              "shortName": "SANDBOX",
              "name": "Sandbox Supplier"
            }
          }
        ]
      }
    ]
  }
}

The actual project response can contain more fields depending on the CPQ configuration, selected product model, price setup, language, and permissions.

Empty Response

204 No Content means no project data was returned for the request. Treat this as a “not available" result and do not continue to manufacturing without user review.

Error Response

400 Bad Request returns ProblemDetails.

{
  "type": "https://sandbox.decoloop.com/problems/invalid-request",
  "title": "Invalid request",
  "status": 400,
  "detail": "The projectId field is required.",
  "instance": "/api/Gateway/Embedded/LoadProject"
}

Send a Project to Manufacturing

Sends a configured project to manufacturing.

Endpoint: POST /api/Gateway/Embedded/SendProject

This endpoint should be called only after the user has explicitly confirmed the order. Sending a project changes the project status and makes configured polygons read-only.

Request

POST https://sandbox.decoloop.com/api/Gateway/Embedded/SendProject
Authorization: bearer ACCESS_TOKEN
Content-Type: application/json
Accept: application/json

{
  "projectId": 69623,
  "reference": "Order Ref 12345",
  "setDeliveryAddress": false,
  "customer": {
    "companyName": "Sandbox Corp",
    "lastName": "Doe",
    "website": null,
    "mainAddress": {
      "name": "",
      "street": "Main Street",
      "streetNumber": "123",
      "zip": "1234 AB",
      "city": "Amsterdam",
      "countryCode": "NL"
    }
  }
}

Request Body

FieldTypeRequiredDescription
projectIdintegerYesID of the project to send to manufacturing.
customerobject or nullNoCustomer data to attach to the project. If customer.id is 0, a new customer may be created. If an existing ID is supplied, the customer may be updated.
referencestring or nullNoProject reference. When empty, the customer name may be used automatically.
setDeliveryAddressbooleanYesWhen true, the customer address is used as the delivery address. If customer.deliveryAddress is filled, that address is used.

Customer Object

Common customer fields include:

FieldTypeDescription
idintegerExisting customer ID, or 0 for a new customer.
codestring or nullDebtor code. Usually treated as read-only.
deliveryCodestring or nullDelivery code. Usually treated as read-only.
companyNamestring or nullCompany name, if applicable.
firstNamestring or nullCustomer first name.
middleNamestring or nullCustomer middle name.
lastNamestring or nullCustomer last name.
displayNamestring or nullDisplay-friendly customer name.
phonestring or nullPhone number.
mobilestring or nullMobile number.
eMailstring or nullEmail address.
mainAddressobject or nullMain customer address.
deliveryAddressobject or nullDelivery address.
invoiceAddressobject or nullInvoice address.

Address Object

Common address fields include:

FieldTypeDescription
namestring or nullName associated with the address.
streetstring or nullStreet name.
streetNumberstring or nullStreet number.
zipstring or nullPostal code.
citystring or nullCity.
countryCodestring or nullISO-style country code, for example NL or BE.
phoneNumberstring or nullPhone number for the address.
emailAddressstring or nullEmail address for the address.
contactNamestring or nullContact person.

Successful Response

200 OK returns a boolean.

true

A response of true means the project was successfully sent to manufacturing.

A response of false means the project was not sent. The host application should keep the project in a pending state and show an actionable message to the user or support team.

Error Response

{
  "type": "https://sandbox.decoloop.com/problems/project-send-failed",
  "title": "Project could not be sent",
  "status": 400,
  "detail": "The project is incomplete and cannot be sent to manufacturing.",
  "instance": "/api/Gateway/Embedded/SendProject"
}

Browse Materials

Browses and filters materials available to the authenticated user/licensee.

Endpoint: POST /api/Gateway/Embedded/BrowseMaterials

The result is paginated and can be filtered by:

  • Category
  • Supplier
  • Free-text search term

Request

POST https://sandbox.decoloop.com/api/Gateway/Embedded/BrowseMaterials
Authorization: bearer ACCESS_TOKEN
Content-Type: application/json
Accept: application/json

{
  "categoryId": 2001,
  "supplierId": 47,
  "searchTerm": "blackout",
  "pageNumber": 1,
  "pageSize": 25
}

Request Body

FieldTypeRequiredDescription
categoryIdinteger or nullNoFilters materials by category. Omit or use null to include all categories.
supplierIdinteger or nullNoFilters materials by supplier. Omit or use null to include all suppliers.
searchTermstring or nullNoCase-insensitive free-text search against material name or description.
pageNumberintegerYes1-based page number. Use 1 for the first page.
pageSizeintegerYesNumber of materials to return per page. Use a reasonable page size, for example 25 or 50.

Successful Response

{
  "items": [
    {
      "id": 292515,
      "code": "5971",
      "categoryId": 2001,
      "eanCode": null,
      "supplierCode": null,
      "description": "Standard Blackout White",
      "remarks": null,
      "promotionPrice": null,
      "salePrice": 24.95,
      "purchasePrice": null,
      "saleQuantity": 1,
      "saleUnit": "m",
      "leadTime": 10,
      "imageUrl": null,
      "supplierId": 47,
      "isWage": false,
      "color": "#FFFFFF",
      "categoryDescription": "Gordijnstoffen",
      "extraFieldValues": [],
      "promotions": [],
      "materialOptionValues": [],
      "displayProperties": [
        {
          "description": "Color",
          "value": "White",
          "valueKind": 0
        }
      ],
      "attachments": [],
      "materialGroups": []
    },
    {
      "id": 292516,
      "code": "5972",
      "categoryId": 2001,
      "eanCode": null,
      "supplierCode": null,
      "description": "Premium Blackout Grey",
      "remarks": null,
      "promotionPrice": null,
      "salePrice": 29.95,
      "purchasePrice": null,
      "saleQuantity": 1,
      "saleUnit": "m",
      "leadTime": 10,
      "imageUrl": null,
      "supplierId": 47,
      "isWage": false,
      "color": "#888888",
      "categoryDescription": "Gordijnstoffen",
      "extraFieldValues": [],
      "promotions": [],
      "materialOptionValues": [],
      "displayProperties": [
        {
          "description": "Color",
          "value": "Grey",
          "valueKind": 0
        }
      ],
      "attachments": [],
      "materialGroups": []
    }
  ],
  "totalItemCount": 2
}

Response Fields

FieldTypeDescription
itemsarrayMaterials for the requested page.
totalItemCountintegerTotal number of materials matching the filters before paging.

Important material fields:

FieldDescription
idMaterial ID to use with iframe materialId. IDs are scoped to the authenticated CPQ context.
codeMaterial code used by the backend configuration. This can be an EAN code or supplier code.
eanCodeMaterial EAN code, when available.
supplierCodeSupplier-specific material code, when available.
descriptionLocalized material description.
salePriceSale price, when available for the authenticated user.
purchasePricePurchase price, when available and permitted. Do not expose this to end users unless intended.
imageUrlRelative or absolute image URL, depending on CPQ configuration.
supplierIdSupplier ID.
categoryIdMaterial category ID.
categoryDescriptionLocalized category description.

Material data is requestor-dependent. The same material ID or code can have different descriptions, prices, colors, or availability in another CPQ instance, licensee, supplier configuration, or language.

Get All Suppliers

Returns all suppliers available to the current licensee.

Endpoint: GET /api/Gateway/Embedded/GetAllSuppliers

Use this endpoint to build a supplier filter for material browsing.

Request

GET https://sandbox.decoloop.com/api/Gateway/Embedded/GetAllSuppliers
Authorization: bearer ACCESS_TOKEN
Accept: application/json

Successful Response

[
  {
    "id": 1,
    "sbnid": 100001,
    "searchName": "supplier a",
    "shortName": "Supplier A",
    "name": "Supplier A"
  },
  {
    "id": 2,
    "sbnid": 100002,
    "searchName": "supplier b",
    "shortName": "Supplier B",
    "name": "Supplier B"
  },
  {
    "id": 3,
    "sbnid": 100003,
    "searchName": "supplier c",
    "shortName": "Supplier C",
    "name": "Supplier C"
  },
  {
    "id": 4,
    "sbnid": 100004,
    "searchName": "supplier d",
    "shortName": "Supplier D",
    "name": "Supplier D"
  }
]

Supplier Fields

FieldTypeDescription
idintegerSupplier ID. Use this as supplierId in BrowseMaterials.
sbnidinteger or nullGlobally unique SBN ID, when available.
searchNamestring or nullSearch-friendly supplier name.
shortNamestring or nullShort supplier name.
namestring or nullFull supplier company name.

Get Material Categories

Returns selectable material categories for the current licensee and language.

Endpoint: GET /api/Gateway/Embedded/GetMaterialCategories

Use this endpoint to build a category filter for material browsing.

Request

GET https://sandbox.decoloop.com/api/Gateway/Embedded/GetMaterialCategories
Authorization: bearer ACCESS_TOKEN
Accept: application/json

Successful Response

[
  {
    "id": 2001,
    "description": "Curtain fabrics",
    "interfaceKey": "Curtain.Fabric"
  }
]

Category Fields

FieldTypeDescription
idintegerCategory ID. Use this as categoryId in BrowseMaterials.
descriptionstring or nullLocalized category description.
interfaceKeystring or nullIntegration key configured for the category.

Optional Iframe URL Parameters

The iframe URL can be customized with optional parameters to control the initial state of Decoloop CPQ.

All iframe URLs should include:

token=ACCESS_TOKEN&isEmbedded=true

Loading an Existing Project

To open an existing project in the iframe, pass the project ID:

https://sandbox.decoloop.com?token=ACCESS_TOKEN&isEmbedded=true&projectId=69623

This loads the saved project into Decoloop CPQ.

To retrieve the same project through the API, use:

POST /api/Gateway/Embedded/LoadProject

Start With a Material

To start a new project with a preselected material, use either materialId or materialCode.

When Decoloop CPQ starts with a material, it selects the first product from the menu for the first polygon.

Use POST /api/Gateway/Embedded/BrowseMaterials to find available materials for the authenticated user.

Material ID

https://sandbox.decoloop.com?token=ACCESS_TOKEN&isEmbedded=true&materialId=292515

Material Code

https://sandbox.decoloop.com?token=ACCESS_TOKEN&isEmbedded=true&materialCode=5971

If an invalid material ID or material code is passed, Decoloop CPQ shows an error message.

Copy Project

To copy an existing project, use the copy parameter together with projectId:

https://sandbox.decoloop.com?token=ACCESS_TOKEN&isEmbedded=true&copy=true&projectId=69623

Copy Polygon

To copy a specific polygon from a project, use copyPolygonId together with projectId:

https://sandbox.decoloop.com?token=ACCESS_TOKEN&isEmbedded=true&projectId=69623&copyPolygonId=501

Error Handling

Embedded API endpoints can return ProblemDetails for invalid requests.

Example:

{
  "type": "https://sandbox.decoloop.com/problems/invalid-request",
  "title": "Invalid request",
  "status": 400,
  "detail": "The pageSize field must be greater than zero.",
  "instance": "/api/Gateway/Embedded/BrowseMaterials"
}

Recommended handling:

StatusMeaningRecommended action
200Request succeeded.Process the response.
204No content, possible for LoadProject.Treat as no project returned. Ask the user to retry or contact support.
400Invalid request or business validation failure.Show a clear validation message and log the ProblemDetails.detail.
401Missing or expired token.Request a new token and retry once.
403Authenticated but not allowed.Do not retry automatically. Contact Decoloop or check permissions.
5xxServer error.Show a generic error and retry later. Log correlation details if available.

Security Recommendations

  • Do not expose API credentials or API keys in browser code.
  • Store tokens securely and avoid logging them.
  • Always validate event.origin before trusting messages from the iframe.
  • Treat project IDs, material IDs, supplier IDs, and category IDs as scoped to the authenticated CPQ context.
  • Do not cache material or supplier data globally across tenants, licensees, languages, or CPQ instances.
  • Avoid exposing purchase prices to end users unless the integration explicitly requires it and the user is authorized.
  • Require explicit user confirmation before calling SendProject.

Next Steps

  • Use the full API reference for detailed schema information.
  • Contact Decoloop if you need access to additional embedded permissions, purchase price visibility, or custom customer/address fields.

On this page