Skip to Content
Technical Articles
Author's profile photo Yashwanth Kumar Koratikere

Spartacus B2B Punchout Level1 Implementation

In this blog, we will learn how you can integrate Spartacus – a composable storefront with SAP Commerce to achieve Level 1 B2B Punchout Functionality.

What’s the need – Latest Spartacus 5.2 version does not provide any OOTB feature/library to integrate B2B Level 1 or Level 2 Punchout to SAP Commerce.

Before diving into the implementation part from Spartacus’s end, let’s understand the B2B Punchout feature in SAP Commerce.

SAP Commerce 2211 B2B Punchout

Punchout in SAP commerce allows buyers to shop for different suppliers’ online catalogs and save the items selected for purchase as a requisition in the buyer’s procurement system.  Here for this blog consider the buyer’s procurement system as SAP Ariba.

B2B Punchout is not a new feature in SAP Commerce, this was present as an addon in the previous version which can be installed on the accelerator storefront.

As we know that accelerator storefront is based on the JSP storefront and which is becoming obsolete now and the SAP commerce implementations are moving towards headless architecture.

In the latest release of SAP Commerce 2211, to support the headless architecture. The Punchout functionality in Commerce is now offered through the new Punchout module and has been enhanced in the following ways:

  1. New extensions are introduced to make the overall functionality efficient and stable.
  2. A new OCC API for Punchout is introduced to expose the functionalities of setting up a session, creating a profile, and getting order information.
  3. The password requirements for Shared Secret and its storage have been strengthened.
  4. The cXML files are handled by the latest DTD structure.
  5. A cronjob to clean up the expired PunchOut sessions can now be scheduled from the backoffice administration cockpit.

If you need to understand more about the B2B Pucnhout functionality, I would strongly recommend you to go through the below link

NOTE: In this blog, I will limit my explanation on how you can configure or make necessary changes to your SPARTACUS store to achieve the Level 1  Punchout functionality.


Setting Up SAP Commerce and Requisition System Credentials

  • SAP Commerce 2211 is installed and it’s up and running with the below extensions added to local.extension file


    <extension name='b2bpunchout' />
    <extension name='b2bpunchoutbackoffice' />
    <extension name='b2bpunchoutocc' />
  • Below impex is imported in the SAP Commerce to set the Punchout credentials


# ---------------------------------------------------------------------------
# Copyright (c) 2022 SAP SE or an SAP affiliate company. All rights reserved.
# ---------------------------------------------------------------------------

INSERT_UPDATE PunchOutCredential ; code[unique = true] ; domain[unique = true] ; identity[unique = true] ; sharedsecret   
                                 ; NetworkId1          ; NetworkID             ; AN01000002779-T         ; VerySecret1234$
                                 ; AribaSupplier       ; NetworkId             ; AN01000865920-T         ; VerySecret1234$
                                 ; DUNS1               ; DUNS                  ; 123456789               ; VerySecret1234$
                                 ; AribaNetworkUserId1 ; AribaNetworkUserId    ;      ; VerySecret1234$
                                 ; DUNS2               ; DUNS                  ; 123                     ; VerySecret1234$

INSERT_UPDATE B2BCustomerPunchOutCredentialMapping ; B2BCustomer(uid)[unique = true]    ; credentials(code)                
                                                   ;  ; NetworkId1,DUNS1                 
                                                   ; ; AribaNetworkUserId1,AribaSupplier

INSERT_UPDATE OAuthClientDetails ; clientId[unique=true] ; resourceIds ; scope ; authorizedGrantTypes        ; authorities ; clientSecret ; registeredRedirectUri
                                 ; punchout_client       ; hybris      ; basic ; password,client_credentials ; ROLE_CLIENT ;              ;                      

INSERT_UPDATE B2BCustomer ; description                      ; customerID                                ; uid[unique = true]                        ; originalUid                               ; email                                     ; name                      ; title(code) ; groups(uid)                             ; loginDisabled ; password ; permissionGroups(uid) ; sessionCurrency(isocode)[default = 'USD'] ;  
                          ; PunchOut Session Sample Customer ; ; ; ; ; PunchOut Customer Session ; mr          ; PunchOut Organization, b2bcustomergroup ; false         ; pwd4all  ;                       ;                                           ;  

INSERT_UPDATE PunchOutCredential ; code[unique = true] ; domain[unique = true] ; identity[unique = true] ; sharedsecret   
                                 ; DUNSSession         ; DUNSSession           ; 888888                  ; VerySecret1234$

INSERT_UPDATE B2BCustomerPunchOutCredentialMapping ; B2BCustomer(uid)[unique = true]           ; credentials(code)
                                                   ; ; DUNSSession      
  •   Add the Below properties in of SAP Commerce. This helps in mapping the Spartacus landing page URL with the “initiate a Punchout Session” API.

Customer B2B Punchout Journey

1. The customer logs into the Ariba supplier site

2. Customers select any one of the available suppliers

3. Clicks on the punchout Icon.

4. Customer Lands on Spartacus Homepage as Punhout Logged In user.

5. Browse the supplier catalog and add the product to the cart.

6. Return back to with the Product added to the cart as a purchase requisition in the buyer’s procurement system


Technical User Flow 

Step 1 to Step 3  remains the same as the customer journey

4. Procurement system internally invokes SAP Commerce Backend OCC POST API                     ({baseSiteId}/punchout/cxml/setup) to set up the punchout profile

5. SAP Commerce backend now creates a user punchout session and responds with a home page URL which includes a hex code token.

6. OCC response will include, Spartacus home page URL to which the procurement system will redirect the Customer to the landing page.

You will understand these steps more when you start testing the flow.



B2B Punchout Cart Page


Swagger API Details For Punchout in 2211 version OOTB


B2B Punchout OOTB Swagger API


Setting Up Spartacus Storefront 5.2 Version

Now we have just made our SAP Commerce backend ready for B2B Punchout. This was mostly configuration.

Create a new angular app with the name “myStore”. This will be used as a store name in this document. I will not go through the steps to set up a Composable storefront as it is already outlined in many other Blogs. You can also refer to the self-explanatory help link below.

http://Building the Composable Storefront From 5.2 Libraries | SAP Help Portal

NOTE: Make sure to enable the B2B features in the interactive tool while setting up the Spartacus store as we are working on the B2B Punchout.

Once you are done with the storefront setup, make sure you can access the powertools-spa website ( https://localhost:4200/powertools-spa/en/USD )

Let’s now begin with changes to be done on the SPARTACUS end to accommodate the Punchout functionality


STEP 1 : 

The first step is to listen to the URL with the shape ‘punchout/cxml/session?sid=asddfsdf…..’ . This can be achieved by making use of Router configuration in angular.

Open your project in VS code or any other code editor and create a new routing module in your “myStore” app under the location “src/app/ ” with a file name “app-routing.module.ts” and inject this file in “app.module.ts”. Below is the code to be added to the file

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoginRedirectComponent } from './demo/features/login-redirect/login-redirect.component';

const routes: Routes = [
    path: 'punchout/cxml/session',
    component: LoginRedirectComponent,

  declarations: [],
  imports: [RouterModule.forRoot(routes)],
export class DemoRoutingModule {}


You will see errors in your Visual Studio Code for this class as you have not yet created “LoginRedirectComponent”


STEP 2: 

The next step is to create a new angular component – LoginRedirectComponent. Create this new component under ‘src/app/demo/features/login-redirect’. (You need to create this folder structure as this will not exist).

Component holds the main functionality to extract the SID token from the URL, send the SID token to SAP Commerce OCC API “’punchout/sessions/${sid}’ and get the user-related details. Once you have created a LoginRedirectComponent. It looks like the below is an empty class.


import { Component, OnInit } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

  selector: 'app-login-redirect',
  templateUrl: './login-redirect.component.html',
  styleUrls: ['./login-redirect.component.scss'],
export class LoginRedirectComponent implements OnInit {

protected busy$ = new BehaviorSubject(true);
  constructor() {}

  ngOnInit(): void {}



Below is the code for LoginRedirectModule and HTML code snippet

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { SpinnerModule } from '@spartacus/storefront';
import { LoginRedirectComponent } from './login-redirect.component';

  declarations: [LoginRedirectComponent],
  imports: [CommonModule, SpinnerModule],
  exports: [LoginRedirectComponent],
export class LoginRedirectModule {}
<cx-spinner class="overlay" *ngIf="busy$ | async"></cx-spinner>


STEP 3: 

Now we will create a service to call SAP Commerce OCC API to fetch the user session info from the “SID” token. We will read the sid value from the previous step and pass it in the below GET request as shown below.


   Request :  {baseSiteId}/punchout/sessions/{sid}

HTTP Method: GET



      cartId: '00002159', 
      token: {
        accessToken: 'adss2332ew324324ewr3432432de',
        tokenType: 'bearer',
      userId: ''

Observe the response, it consists of cartId for the user and an access token. We will use this to set the “active cart ID” and “access token” in Spartacus. So that user will be automatically logged In.

Create a new Service class “PunchoutService” in Spartacus to fetch the above details from SAP Commerce. Below is a sample code, which is created under the file structure “src/app/demo/services”

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { OccEndpointsService } from '@spartacus/core';
import { Observable } from 'rxjs';

export interface PunchOutSession {
  customerId: string;
  cartId: string;
  punchOutLevel: string;
  punchOutOperation: string;
  selectedItem: string;
  token: PunchOutToken;

export interface PunchOutToken {
  accessToken: String;
  tokenType: String;

  providedIn: 'root',
export class PunchOutService {
    protected http: HttpClient,
    protected occEndpoints: OccEndpointsService
  ) {}

  getPunchOutSessionData(sid: string): Observable<PunchOutSession> {
    localStorage.setItem('punchout-sid-key', sid);
    const url = this.occEndpoints.buildUrl('getPunchOutAccessToken', {
      urlParams: { sid: sid },
    return this.http.get<PunchOutSession>(url, httpOptions);

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json',


Step 4:

URL “getPunchOutAccessToken” can be configured as new constant file and must be referred to in the provider’s section of the Spartacus-configuration.module.ts file as below

A new constant file to hold all the URLs should be created and imported accordingly in the Spartacus-configuration.module.ts file

Below is a sample constant file

export const DemoOccEndPoints = {
  getPunchOutAccessToken: 'punchout/sessions/${sid}'


Below is a code snippet where you need to inject the DemoOccEndPoints constant file in your application.




Step 5:  Set Active Cart ID and Access Token in the Spartacus Session. To achieve this let us re-write the “LoginRedirectComponent” to achieve this functionality.


import { ActivatedRoute } from '@angular/router';
import { Store } from '@ngrx/store';
import { CartActions } from '@spartacus/cart/base/core';
import {
} from '@spartacus/core';
import { BehaviorSubject, of, Subscription } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';
import { PunchOutService } from '../../services/punchout-service';

  selector: 'app-login-redirect',
  templateUrl: './login-redirect.component.html',
  styleUrls: ['./login-redirect.component.scss'],
export class LoginRedirectComponent implements OnInit {
  protected busy$ = new BehaviorSubject(true);

  protected subscription = new Subscription();

    private activateRoute: ActivatedRoute,
    private userIdService: UserIdService,
    private store: Store,
    private punchoutService: PunchOutService,
    private authStorageService: AuthStorageService,
    private routing: RoutingService,
    private statePersistenceService: StatePersistenceService,
    protected siteContextParamsService: SiteContextParamsService
  ) {}

  ngOnInit(): void {
        switchMap((params) => {
          return this.punchoutService
              tap((data) => {
                if (data.token.accessToken) {
                    key: 'cart',
                    state$: of({
                      active: data.cartId,
                    context$: this.siteContextParamsService.getValues([
                    storageType: StorageSyncType.LOCAL_STORAGE,
                    onRead: (state) => this.onRead(state),

                    access_token: data.token.accessToken,
                    token_type: data.token.tokenType,
                  } as AuthToken);


  protected onRead(state: { active: string } | undefined) { CartActions.ClearCartState());
    if (state) { CartActions.SetActiveCartId(;
    } else { CartActions.SetActiveCartId(''));


STEP 6: 

Start the server to check if there are any errors and resolve them accordingly. Mostly you could have missed an import or had an incorrect entry. Make sure to correct as per your application specific. Also, make sure you have injected LoginRedirectComponent and DemoRoutingModule in the app.module.ts file else it will not consider this file when the angular app is bootstrapped.


STEP 7: 

If Step 6 is successful, then it’s time for testing. Here for testing purposes, I will use POSTMAN to send Request to SAP Commerce Backend OCC API to set up a login session instead of directly configuring it in the S4 Ariba system.


POST Request For Setup API:  This API will be invoked from S4 to set up user sessions in SAP Commerce.

Request URL: https://localhost:9002/occ/v2/powertools-spa/punchout/cxml/setup

Request Body:

<?xml version="1.0" encoding="UTF-8"?>
<cXML payloadID="1391193486192-325467636084519232@" timestamp="2013-12-19T09:07:19-08:00" xml:lang="en-US">
            <Credential domain="NetworkId">
            <Credential domain="NetworkID">
            <Credential domain="AribaNetworkUserId">
            <UserAgent>Buyer 14s2</UserAgent>
        <PunchOutSetupRequest operation="create">
            <Extrinsic name="CostCenter">670</Extrinsic>
            <Extrinsic name="UniqueName">catalog_tester</Extrinsic>
            <Extrinsic name="UserEmail"></Extrinsic>
                <Address addressID="26">
                    <Name xml:lang="en-US">Catalog Tester</Name>
                    <PostalAddress name="_5uicbb">
                        <DeliverTo>Catalog Tester</DeliverTo>
                        <Street>1234 Catalog Tester Way</Street>
                        <Country isoCountryCode="US">United States</Country>
                    <SupplierPartAuxiliaryID />


Response:  Observe the <URL> tag in the below response. It has a landing page URL for Spartacus with a SID request parameter.The SID parameter will hold the information of the commerce user.

<?xml version="1.0" encoding="UTF-8"?>
<cXML payloadID="d868d40c-7bc3-4e3e-96fa-668cc6715ec8" timestamp="2023-04-14T06:29:20Z" xml:lang="en-US">
        <Status code="200" text="success"/>


Copy the URL from the Response and paste it into Browser and click enter.

https://localhost:4200/ punchout/cxml/session?sid=MdXK777UoiHOrFnYjimf89Lardkp3tQ7pInKP67DIjs



B2B Punchout User Landing Page




If you can see the screen related to power tools-spa as logged Punchout User. Congratulations, you have successfully punched out from the procurement system to Spartacus Storefront.

In the next Blog, I will try to cover how you can send the cart details back to the procurement system once the customer adds the product to the cart. Till then Happy Coding!!

Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Jitendra Singh
      Jitendra Singh

      Thanks and very nicely explained. Steps are so clear and explained.

      Author's profile photo Yashwanth Kumar Koratikere
      Yashwanth Kumar Koratikere
      Blog Post Author

      Thanks Jiten

      Author's profile photo Priti Mittal
      Priti Mittal

      nice Article !

      Author's profile photo Yashwanth Kumar Koratikere
      Yashwanth Kumar Koratikere
      Blog Post Author

      Thanks Priti Mittal

      Author's profile photo Padmaja Maddula
      Padmaja Maddula

      This is very insightful!! Thank you!

      when is the next one coming? Curious to see how the cart details can be sent back to procurement system.

      Author's profile photo abdur rahaman
      abdur rahaman

      This is very helpful. I am trying to implement but getting CORS error when spartacus storefront trying to access OCC punchout session API.