Pricefx Interceptor API
    Preparing search index...

    Pricefx Interceptor API

    Interceptors Developer Guid

    TEST to run the build

    TEST to run the build

    An interceptor is a record in Advanced Configuration options in the Pricefx application and it contains a JavaScript code. The record name has to start with a prefix pfxInterceptor_ and then it has to continue with the actual interceptor name. A correct name is, for example, pfxInterceptor_myFirstExperiment.

    The record cannot be empty; if it is, Pricefx will show an error: “The interceptor with name pfxInterceptor_myFirstExperiment was not found”.

    It has to contain at least one exported Javascript constant with a function such as this:

    export const quotesDetailOpen = async () => {
    // Code which will be triggered when a user opens an existing quote
    }

    If you need to add custom behavior at more places, just export more constants:

    export const quotesDetailNew = async () => {
    // This will trigger at a new quote
    }

    export const quotesDetailOpen = async () => {
    // This will trigger at an existing one
    }

    export const quotesDetailSubmit = async () => {
    // This will trigger when a user presses the Submit button at a quote detail
    }

    A list of all possible constant names which can be exported from the interceptor code is here.

    To make the interceptor active you have to set it at Administration > Configuration > Interceptors. This page also contains all possible constant names mentioned above.

    It is visible only if you have the user role Develop Interceptors.

    For more details see Pricefx Knowledge Base.

    See also other sources: reference and configuration.

    Pre & Post Methods

    Each named constant can exist in two variants, one is for the PRE action with a suffix Pre and the second one for the POST action where the suffix is omitted.

    export const quotesDetailSubmitPre = () => {
    console.log('This will be triggered before quotesDetailSubmit');
    };

    export const quotesDetailSubmit = () => {
    console.log('Test 1');
    };

    You do not need to implement both variants. In some cases only the PRE action makes sense, for others it is only the POST action.

    When a user triggers an action, for example quote submit, Pricefx checks if the PRE action exists (quotesDetailSubmitPre in our submit example).

    If this method exists, then is processed and the return value is used to decide if to continue or not. For false, the action is canceled. Other non-false values are passed to Pricefx action.

    After Pricefx action we check if the POST action exists (quotesDetailSubmit) and if does, then it is processed. Some POST actions will obtain data from Pricefx action.

      graph TD
        A["trigger an ACTION (e.g. Submit)"] --> B["PRE method exists?"]
        B:::condition --> |no| F
        B --> |yes| C["PRE method executed"]
        C --> CC["PRE method return value is not false?"]
        CC:::condition --> |false| D["ACTION canceled"]
        CC --> |true| E["return value is passed to ACTION"]
        E --> F["ACTION executed"]
        F --> |value from action|G["POST method exists?"]
        G:::condition --> |yes| H[POST method executed]
        H --> K
        G --> |no| K["ACTION completed"]
      classDef condition fill:#fff2cc,stroke:#ffd700,color:#000000
    

    For Quotes, Contracts, Rebate Agreements and Compensation Plans, creating a new object follows a specific multi-step flow with two interceptor methods wired into different stages. The order matters when you want to push values into the new object — the wrong stage can mean your values are ignored, or applied too late to affect header logic.

    graph TD
      A["User presses New {Quote/Contract/...} on the list page"] --> B["*DetailNewCheck interceptor"]
      B:::condition --> |returns false| Z["Creation cancelled, user stays on list"]
      B --> |non-false| C["Visual Mapping applies (CRM values → object payload)"]
      C --> D["Backend clicmanager.create endpoint"]
      D --> E["Header logic runs (driven by the object type)"]
      E --> F["Object returned to frontend"]
      F --> G["*DetailNew interceptor"]
      G --> H["User lands on detail page"]
      classDef condition fill:#fff2cc,stroke:#ffd700,color:#000000
    

    The same pattern applies to all four CLIC object types:

    List action Before create After create
    New Quote quotesDetailNewCheck quotesDetailNew
    New Contract contractsDetailNewCheck contractsDetailNew
    New Rebate Agreement rebateAgreementsDetailNewCheck rebateAgreementsDetailNew
    New Compensation Plan compensationsDetailNewCheck compensationsDetailNew
    • *DetailNewCheck runs before the object exists. quoteAPI (or contractAPI / rebateAgreementAPI / compensationPlanAPI) is not available. You can still call other APIs — typically CRM-related — to decide whether to allow creation. Return false to cancel; any other value (including no return) lets creation proceed.
    • *DetailNew runs after header logic. Values you set here will not trigger header logic automatically, because it has already executed. If your values should influence the header, you have two options:
      1. Push them via Visual Mapping (preferred when the value can be derived from the CRM payload) — the mapping is applied between *DetailNewCheck and the backend clicmanager.create call, so values are in place when header logic runs.
      2. Set them in *DetailNew and call recalculate() explicitly, e.g. await quoteAPI.recalculate();.

    This API is available in each intercepted method and here is how to access it:

    export const quotesDetailSubmit = async ({ api }) => {
    // code
    }

    For Quotes, Contracts, Rebate Agreements and Compensation Plans you can use ClicInterceptorAPI to manipulate CLIC objects. Name of this API will vary based on the module where you are using. For Quotes it will be:

    export const quotesDetailAccountAssign = ({ quoteAPI }) => {
    // code
    }
    • Compensation Plans: compensationPlanAPI
    • Contracts: contractAPI
    • Rebate Agreements: rebateAgreementAPI
    • Quotes: quoteAPI

    Intercepted method for creating a new Contract.

    export const contractsDetailNew = async ({
    contractAPI,
    api: { crmManager, configuration },
    }) => {
    const payload = await crmManager.getPayload();
    const appEnv = await configuration.retrieveConfig("applicationEnvironment");
    const isOpportunity = await crmManager.isOpportunityPage();
    const isAccount = await crmManager.isAccountPage();

    if (isOpportunity) {
    const opportunityId = await crmManager.getOpportunityAssociatedValue();
    await contractAPI.setHeaderValue("externalRef", opportunityId);
    }

    if (isAccount) {
    if (appEnv === "salesforce") {
    const customerIdSF = await crmManager.getAccountAssociatedValue();
    const customerLabel = `${customerIdSF} (CustomerID)`;

    if (customerIdSF) {
    await contractAPI.setHeaderInputValue("CustomerGroup", {
    customerFieldName: "customerId",
    customerFieldValue: customerIdSF,
    label: customerLabel,
    });
    } else {
    await contractAPI.setHeaderInputValue("CustomerGroup", {
    customerFieldName: "customerId",
    customerFieldValue: payload.Account_Num__c,
    label: `${payload.Account_Num__c} (CustomerID)`,
    });
    }
    }
    }
    };