Created by Tom Zarr with key contributions from Sandra Golden and Jordane Bachelet
This material is supplemental to the B2B Commerce Partner Learning Camp Administrator and Developer curricula. Please consult the respective curriculum and its courses for obtaining an environment so you can set up, deploy and manage a Salesforce B2B Commerce standalone environment.
This postman collection contains API endpoints from various Salesforce Commerce domains, but the emphasis is on completing B2B Commerce checkouts and performing operational tasks related to that end through the Connect API and other flavors of API available on the Salesforce platform.
Unlike many other Postman collections, this one is meant to be user friendly and have meaningful error messages when something is not set up correctly or there are issues in the request chains.
- This collection is provided as-is. It's not officially supported by Salesforce or covered by SLAs.
- API documentation is not provided with the collection. Please refer to the official documentation.
- The documentation for the majority of the endpoints in this collection can be found in the B2B and D2C Commerce Resources of the Connect REST API Developer Guide.
This collection is intended for a B2B 'standalone' setup. That isn't to say you can't use it with an org containing other products, just that B2B is the targeted commerce product.
- I've tried to stay 'close to the metal' by using the Postman Scripting API directly. There are a few cases where this just isn't possible or realistic because some responses don't adhere to a strict JSON or HTTP structure, such as error codes reported in an HTML body, but those should be the uncommon exception, definitely not the rule.
- I wanted oAuth 2.0 to be easy so I could move things around like Lego blocks. This is the best I could come up with given the limitations of the tool: Have a dummy request where you set it once in that folder and then everything following it just uses the Bearer Token. It works and "better" is the enemy of "good enough."
- The request chains are long; This is by design. This is ultimately a teaching tool. When it comes to working with APIs I find more detail, especially about what needs to happen between them, quite helpful. The intent is to cut out the process of interrogating interfaces and faffing about before you can effectively use them.
- Collection variables are calculated and presented before each request. Please use this to your advantage.
- Tests are applied following each response. If something isn't right, I'd rather it fail fast.
This collection provides the following Use Case operations (some are a work in progress or being debugged for continuity)
- Happy Path (Buyer Login)
- Happy Path (Guest) - WIP
- Cancel Checkout (Buyer Login) - WIP
- Deployment - Payment - LWR & CCA
- Deployment - Register External Services for Aura
- Deployment - Register External Services for LWR
- Pricing (Guest)
- Get Inventory Availability (Buyer Login)
- Get Inventory Availability (oAuth 2.0)
- Search - Perform Reindex
Legos are a good metaphor for building long request chains out of the swappable requests. Maybe stringing beads or connecting train cars may have been better, but it's too late now. Code definitions for all Pre-request and Post-response scripts can be seen in the "LegoBin" folder. The "UseCases" folder, linked to from this README file under Use Cases, contains HTML files explaining the "Legos" used in each use case and login methodology (Buyer Login, oAuth 2.0, Guest).
Because we're using APIs you'll need to set up a Connected App in your org since REST APIs such as the Connect API, Query API and others, plus SOAP may be in play. You can follow the steps in the Salesforce Commerce Postman Collection Guide for Solution Implementing Partners to set up the Connected App in your org and configure the Postman Variables.
Authentication is generally handled with two main flavors which you can read about under Partner Readiness Approach to Salesforce Commerce Postman Collections in the guide (Options 1 and 2).
Logging in as an Administrator or Buyer Account aka "Option 1: Postman oAuth 2.0 Token and Flow Wizard"
This is handled inline. Just supply the environment with the needed variables like these and the collection and scripting should take care of the rest for you:
Name | Description |
---|---|
orgLoginUrl |
Either https://login.salesforce.com (production / trial) or https://test.salesforce.com (sandbox) |
orgHost |
Protocol and host portion of the Salesforce org's URL Example: https://yourusername-august.lightning.force.com |
orgAdminUsername |
The System Administrator username for the Salesforce org |
orgAdminPassword |
The System Administrator password for the Salesforce org |
orgAdminSecurityToken |
The security token for the Salesforce Org System Administrator User |
If you need to move this type of Administrator or Buyer authentication scheme around, just copy the request and paste it into another folder or location in the current folder. A major goal of this collection was to make these "Lego Blocks" fungible in Postman. As long as you have a request these before making other calls, you should generally be fine:
- Log in as System Administrator (SOAP)
- Log in as Buyer (SOAP)
I've tried to make this easy to establish and reusable. You can read more about the approach here.
It's my intent to trap reasonably predictable errors and save anyone using this collection valuable time. I welcome your feedback on that front. That said, I can't cover every single org configuration or set of data and this is where you come in as a partner. Below are some of the common cases I've tried to account for so the request chains can inform you when something's off base or at least provide hints to help troubleshoot what you're seeing and remedy it.
It's recommended you stick to the pattern of having this as the first step in your folder. It does a few things to ensure your request chain data is kept consistent and clean:
- The Pre-request tab makes sure that your environment is selected and stops the chain if not - dead programs tell no lies!
// Check for environment selection
if(pm.environment.name === undefined)
{
const msg = 'No Postman environment selected or set.';
pm.expect.fail(msg);
}
- The Pre-request tab makes sure that it clears out the collection variables:
// Clean up the variables from the collection set throughout the various calls
pm.collectionVariables.clear();
- The Test tab ensures the collection is indeed empty:
pm.test('Make sure collection variables are clean', () =>
{
pm.expect(pm.collectionVariables.values.map((v) => v.key + ': ' + v.value)).to.be.an('array').empty;
});
Whatever the request is named in the Postman user interface is reflected dynamically by these code snippets:
console.log(
${pm.info.requestName} Pre-request Script...);
console.log(
${pm.info.requestName} Tests...);
If you call your request "Foo Bar 42" you will see Foo Bar 42 Pre-request Script...
or Foo Bar 42 Tests...
in the console accordingly. You can drill into your request and response bodies as needed knowing what was passed to the endpoint.
If environment variables are expected for a request they are tested on the Pre-request script tab according to what's in the variable expectedStringsInEnvironmentVariables
. If not found, the test run should go to a 'hard fail' state. Just look for the error (red text) in the Console.
// This script expects you to have these ENVIRONMENT variables configured
const expectedStringsInEnvironmentVariables = ['orgLoginUrl','apiVersion', 'webStoreName'];
// Check expected strings in environment variables
for(const esiev of expectedStringsInEnvironmentVariables)
{
if(!pm.environment.has(esiev))
{
const msg = `Expected Postman environment variable not found: '${esiev} in environment: '${pm.environment.name}'`;
pm.expect.fail(msg);
}
pm.expect(pm.environment.get(esiev)).to.exist;
pm.expect(pm.environment.get(esiev)).to.be.an('string');
}
If collection variables are expected they are tested on the Pre-request script tab. Like the environment variables, the test run should go to a hard fail state and you should find a meaningful error in the Console.
// This script expects you to have these COLLECTION variables configured
const expectedStringsInCollectionVariables = ['_instanceUrl'];
// Check expected strings in collection variables
for(const esicv of expectedStringsInCollectionVariables)
{
if(pm.collectionVariables.get(esicv) === undefined)
{
const msg = 'Expected Postman collection variable not found: ' + esicv;
pm.expect.fail(msg);
}
pm.expect(pm.collectionVariables.get(esicv)).to.exist;
pm.expect(pm.collectionVariables.get(esicv)).to.be.an('string');
}
This code snippet allows you to see things before each request is made in the Pre-Request Script tab:
console.log('Collection variables before:\r\n'.concat(pm.collectionVariables.values.map((v) => v.key + ': ' + v.value).sort().join('\r\n')));
Example of collection variables being printed to the console in a Pre-request script:
Collection variables before:↵
_instanceUrl: https://toms-org.my.salesforce.com↵
_locationGroupIdentifiers: ["LocationGroup01"]↵
_orgId: 00DHn0000YYYYYYYYY↵
_productStockKeepingUnits: ["PROSE","B-C-COFMAC-001","ESP-IOT-1","ID-PEM","PS-EL","PS-INF","TR-COFMAC-001"]↵
_token: 0xdeadbeef!0x8badfood!0xfeedfacecafebeefx.01123581321345589144233377610↵
_userId: 005HnXXXXXXXXXXXXX
Use output like the above to diagnose or debug your API calls.
⚠️ Note: You must set up your environment variables correctly for all of this to work. Collection variables are typically calculated and assigned between requests (in the Test tab script) and used in subsequent requests. The naming convention used in the collection is to prefix collection variable keys with an underscore like_tomsVariableKey
while an environment variable should not contain an underscore. Example:tomsVariableKey
. I would never recommend writing to environment variables at runtime. This is a slippery slope that can avalanche quickly. Instead, keep the environment variables consistent across the collection and all folders within it.
These are some bad examples. You shouldn't see calls like these in the collection and it's strongly recommended that you do not create them this way to avoid needless debugging:
pm.collectionVariables.set('myVariable', 'My new value'); // Should be an underscore-prefixed variable
pm.collectionVariables.get('myVariable'); // Should be an underscore-prefixed variable
pm.environment.set('_myVariable', 'My new value'); // Should not be an underscore-prefixed variable
pm.environment.get('_myVariable'); // Should not be an underscore-prefixed variable
These are good examples as they adhere to the established naming convention and it's clear which dictionary we're using when the name is seen in the Console:
pm.collectionVariables.set('_myVariable', 'My new value');
pm.collectionVariables.get('_myVariable');
pm.environment.set('myVariable', 'My new value');
pm.environment.get('myVariable');
Every coder has their preferences and practices. I don't like mixing my dictionaries for retrieving a value by key. I believe strongly that a few coding principles such as singular definition and not coding by coincidence - even with tests, and especially with tests can save much time. If those terms aren't familiar I'd like to recommend a book called "The Pragmatic Programmer."
These are some examples:
- webstoreName (resolves to a WebStore Id)
- buyerAccountName (resolves to an Account Id)
- productNamesCommaDelimited (resolves to a list of Product2 Ids)
- b2bWebStoreExpectedChildCategoryNamesCommaDelimited (used in Product Category calls)
- productStockKeepingUnitsCommaDelimited (used in OCI Postman collection)
- locationGroupIdentifiersCommaDelimited (used in OCI Postman collection)
- locationIdentifiersCommaDelimited (used in OCI Postman collection)
- productSearchTerm
This Postman collection relies on the following variables:
Name | Description | Location |
---|---|---|
apiVersion |
The Salesforce API version (e.g. 61.0). | User supplied. Most recent value recommended. |
orgLoginUrl |
Either https://login.salesforce.com (production/trial) or https://test.salesforce.com (sandbox) |
User supplied |
orgHost |
Protocol and host portion of the Salesforce org's URL | User supplied. Example: https://yourusername-august.lightning.force.com |
orgAdminUsername |
The System Administrator username for the Salesforce org | User supplied |
orgAdminPassword |
The System Administrator password for the Salesforce org | User supplied |
orgAdminSecurityToken |
The security token for the Salesforce Org System Administrator User | Autogenerated |
orgHostMySalesforceFormat |
The protocol and host portion of the Salesforce org's URL in 'my.salesforce.com' format. Useful for avoiding redirection problems and 'Invalid Session Id' errors post authentication | User supplied. Example: https://yourusername-august.my.salesforce.com |
connectedAppConsumerKey |
The Consumer Secret value for the Connected App in the Salesforce org. | Setup > App Manager > Connected App Record > View > Manage Consumer Details |
connectedAppConsumerSecret |
The Consumer Secret value in the Connected App. | Setup > App Manager > Connected App Record > View > Manage Consumer Details |
webstoreName |
Name of the webstore used to look up a corresponding Id | The value specified when the store / site was created such as 'B2B LWR Enhanced Store from TSO.' Can be found in the Commerce App under 'Stores.' |
buyerUsername |
Registered B2B Buyer User's username. | User supplied. |
buyerPassword |
Registered B2B Buyer User's password. | User supplied. |
buyerAccountName |
Name of the Account used to look up the Account Id which is tied to the Buyer User. | User supplied. Example: United Coffee Bean Corp |
productNamesCommaDelimited |
Comma-delimited list of product names which are resolved to Ids. | User supplied: Example Testa Rossa Coffee Machine (Sample),Capricorn I Group Espresso Machine (Sample) |
productSearchTerm |
The search term to use for a Happy Path | User supplied: Example Coffee |
b2bWebStoreParentCategoryName |
A category with child categories underneath it. If using the uploaded Capricorn Sample product CSV, "Machines" should work. | User supplied. Example: Machines |
b2bWebStoreExpectedChildCategoryNamesCommaDelimited |
The expected child categories underneath the b2bWebStoreParentCategoryName variable. If using the Capricorn sample products imported via CSV, "Coffee Machines,Espresso Machines" should work. | User supplied. Example: Coffee Machines,Espresso Machines |
currencyIsoCode |
The currency code for the cart. | User supplied: Example USD for United States Dollar |
Please consult the Partner Learning Camp B2B Commerce curriculum and course documentation for additional details.
Enjoy the collection! Tom Zarr - October, 2024