Inventory Visibility public APIs
Note
Azure Active Directory is now Microsoft Entra ID. Learn more
This article describes the public APIs that are provided by Inventory Visibility.
The public REST API of the Inventory Visibility Add-in presents several specific endpoints for integration. It supports four main interaction types:
- Posting on-hand inventory changes to the add-in from an external system
- Setting or overriding on-hand inventory quantities in the add-in from an external system
- Posting reservation events to the add-in from an external system
- Querying current on-hand quantities from an external system
The following table lists the APIs that are currently available:
Path | Method | Description |
---|---|---|
/api/environment/{environmentId}/onhand |
Post | Create one on-hand change event |
/api/environment/{environmentId}/onhand/bulk |
Post | Create multiple change events |
/api/environment/{environmentId}/setonhand/{inventorySystem}/bulk |
Post | Set/override on-hand quantities |
/api/environment/{environmentId}/onhand/reserve |
Post | Create one soft reservation event |
/api/environment/{environmentId}/onhand/reserve/bulk |
Post | Create multiple soft reservation events |
/api/environment/{environmentId}/onhand/unreserve |
Post | Reverse one soft reservation event |
/api/environment/{environmentId}/onhand/unreserve/bulk |
Post | Reverse multiple soft reservation events |
/api/environment/{environmentId}/onhand/reserve/resyncjob |
Post | Clean up reservation data |
/api/environment/{environmentId}/getJobProgress |
Get | Get job execution progress |
/api/environment/{environmentId}/onhand/changeschedule |
Post | Create one scheduled on-hand change |
/api/environment/{environmentId}/onhand/changeschedule/bulk |
Post | Create multiple on-hand changes with dates |
/api/environment/{environmentId}/onhand/indexquery |
Post | Query by using the post method (recommended) |
/api/environment/{environmentId}/onhand |
Get | Query by using the get method |
/api/environment/{environmentId}/onhand/exactquery |
Post | Exact query by using the post method |
/api/environment/{environmentId}/allocation/allocate |
Post | Create one allocate event |
/api/environment/{environmentId}/allocation/unallocate |
Post | Create one unallocate event |
/api/environment/{environmentId}/allocation/reallocate |
Post | Create one reallocate event |
/api/environment/{environmentId}/allocation/consume |
Post | Create one consume event |
/api/environment/{environmentId}/allocation/query |
Post | Query allocation result |
/api/environment/{environmentId}/onhand/productsearch/indexquery |
Post | Post index query with product search |
/api/environment/{environmentId}/onhand/productsearch/exactquery |
Post | Post exact query with product search |
/api/environment/{environmentId}/transaction/adjustment/bulk |
Post | Sync external inventory changes through Inventory Visibility |
Note
The {environmentId} part of the path is the environment ID of Microsoft Dynamics 365 Supply Chain Management. This ID is the one stated for Supply Chain Management in Lifecycle Services, not the ID of the Power Platform environment that is linked to the Supply Chain Management environment.
The bulk API can return a maximum of 512 records for each request.
Authentication
The platform security token is used to call the Inventory Visibility public API. Therefore, you must generate a Microsoft Entra token by using your Microsoft Entra application. You must then use the Microsoft Entra token to get the access token from the security service.
To get a security service token, follow these steps.
Sign in to the Azure portal, and use it to find the
clientId
andclientSecret
values for your Dynamics 365 Supply Chain Management app.Fetch a Microsoft Entra token (
aadToken
) by submitting an HTTP request that has the following properties:URL:
https://login.microsoftonline.com/${aadTenantId}/oauth2/v2.0/token
Method:
GET
Body content (form data):
Key Value client_id ${aadAppId} client_secret ${aadAppSecret} grant_type client_credentials scope 0cdb527f-a8d1-4bf8-9436-b352c68682b2/.default
You should receive a Microsoft Entra token (
aadToken
) in response. It should resemble the following example.{ "token_type": "Bearer", "expires_in": "3599", "ext_expires_in": "3599", "access_token": "eyJ0eX...8WQ" }
Formulate a JavaScript Object Notation (JSON) request that resembles the following example.
{ "grant_type": "client_credentials", "client_assertion_type": "aad_app", "client_assertion": "${Your_Microsoft_EntraToken}", "scope": "https://inventoryservice.operations365.dynamics.com/.default", "context": "${fno_environment_id}", "context_type": "finops-env" }
Note the following points:
- The
client_assertion
value must be the Microsoft Entra token (aadToken
) that you received in the previous step. - The
context
value must be the Supply Chain Management environment ID where you want to deploy the add-in. - Set all the other values as shown in the example.
- The
Fetch an access token (
access_token
) by submitting an HTTP request that has the following properties:URL:
https://securityservice.operations365.dynamics.com/token
Method:
POST
HTTP header:
Key Value Api-Version 1.0 Content-Type application/json Body content: Include the JSON request that you created in the previous step.
You should receive an access token (
access_token
) in response. You must use this token as a bearer token to call the Inventory Visibility API. Here's an example.{ "access_token": "${Returned_Token}", "token_type": "bearer", "expires_in": 3600 }
Note
If you receive a response with status code 307, use the value of the
Location
header to resend the token request to the new URL. Most HTTP libraries handle redirects automatically.
Create on-hand change events
There are two APIs for creating on-hand change events:
- Create one record:
/api/environment/{environmentId}/onhand
- Create multiple records:
/api/environment/{environmentId}/onhand/bulk
The following table summarizes the meaning of each field in the JSON body.
Field ID | Description |
---|---|
id |
A unique ID for the specific change event. If a resubmission occurs due to a service failure, this ID is used to ensure the same event won't be counted twice in the system. |
organizationId |
The identifier of the organization that's linked to the event. This value is mapped to an organization or data area ID in Supply Chain Management. |
productId |
The identifier of the product. |
quantities |
The quantity that the on-hand quantity must be changed by. For example, if 10 new books are added to a shelf, this value will be quantities:{ shelf:{ received: 10 }} . If three books are removed from the shelf or sold, this value will be quantities:{ shelf:{ sold: 3 }} . |
dimensionDataSource |
The data source of the dimensions that are used in the posting change event and query. If you specify the data source, you can use the custom dimensions from the specified data source. Inventory Visibility can use the dimension configuration to map the custom dimensions to the general default dimensions. If no dimensionDataSource value is specified, you can use only the general base dimensions in your queries. |
dimensions |
A dynamic key-value pair. The values are mapped to some of the dimensions in Supply Chain Management. However, you can also add custom dimensions (for example, Source) to indicate whether the event is coming from Supply Chain Management or an external system. |
Note
If your data partition rule is set to By product ID, siteId
and locationId
are optional dimensions. Otherwise, they're required dimensions. This rule also applies to the allocation, soft reserve, and change schedule APIs.
The following subsections provide examples that show how to use these APIs.
Create one on-hand change event
This API creates a single on-hand change event.
Path:
/api/environment/{environmentId}/onhand
Method:
Post
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
{
id: string,
organizationId: string,
productId: string,
dimensionDataSource: string, # Optional
dimensions: {
[key:string]: string,
},
quantities: {
[dataSourceName:string]: {
[key:string]: number,
},
},
}
The following example shows sample body content. In this example, the company has a point-of-sale (POS) system that processes in-store transactions and therefore inventory changes. The customer has returned a red T-shirt to your store. To reflect the change, you post a single change event for the T-shirt product. This event will increase the quantity of the T-shirt product by 1.
{
"id": "Test201",
"organizationId": "usmf",
"productId": "T-shirt",
"dimensionDataSource": "pos",
"dimensions": {
"siteId": "1",
"locationId": "11",
"posMachineId": "0001",
"colorId": "red"
},
"quantities": {
"pos": {
"inbound": 1
}
}
}
The following example shows sample body content without dimensionDataSource
. In this case, dimensions
will be the base dimensions. If dimensionDataSource
is set, dimensions
can be either the data source dimensions or the base dimensions.
{
"id": "Test202",
"organizationId": "usmf",
"productId": "T-shirt",
"dimensions": {
"siteId": "1",
"locationId": "11",
"colorId": "red"
},
"quantities": {
"pos": {
"inbound": 1
}
}
}
Create multiple change events
This API can create change events, just as the single-event API can. The only difference is that this API can create multiple records at the same time. Therefore, the Path
and Body
values differ. For this API, Body
provides an array of records. The maximum number of records is 512. Therefore, the on-hand change bulk API can support up to 512 change events at a time.
For example, a retail store POS machine processed the following two transactions:
- One return order of one red T-shirt
- One sales transaction of three black T-shirts
In this case, you can include both inventory updates in one API call.
Path:
/api/environment/{environmentId}/onhand/bulk
Method:
Post
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
[
{
id: string,
organizationId: string,
productId: string,
dimensionDataSource: string, # Optional
dimensions: {
[key:string]: string,
},
quantities: {
[dataSourceName:string]: {
[key:string]: number,
},
},
},
...
]
The following example shows sample body content.
[
{
"id": "Test203",
"organizationId": "usmf",
"productId": "T-shirt",
"dimensionDataSource": "pos",
"dimensions": {
"SiteId": "Site1",
"LocationId": "11",
"posMachineId": "0001"
"colorId": "red"
},
"quantities": {
"pos": { "inbound": 1 }
}
},
{
"id": "Test204",
"organizationId": "usmf",
"productId": "T-shirt",
"dimensions": {
"siteId": "1",
"locationId": "11",
"colorId": "black"
},
"quantities": {
"pos": { "outbound": 3 }
}
}
]
Set/override on-hand quantities
The Set on-hand API overrides the current data for the specified product. This functionality is typically used to do inventory counting updates. For example, during its daily inventory counting, a store might find that the actual on-hand inventory for a red T-shirt is 100. Therefore, the POS inbound quantity must be updated to 100, regardless of what the previous quantity was. You can use this API to override the existing value.
Path:
/api/environment/{environmentId}/setonhand/{inventorySystem}/bulk
Method:
Post
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
[
{
id: string,
organizationId: string,
productId: string,
dimensionDataSource: string, # Optional
dimensions: {
[key:string]: string,
},
quantities: {
[dataSourceName:string]: {
[key:string]: number,
},
},
modifiedDateTimeUTC: datetime,
},
...
]
The following example shows sample body content. The behavior of this API differs from the behavior of the APIs that are described in the Create on-hand change events section earlier in this article. In this sample, the quantity of the T-shirt product will be set to 1.
[
{
"id": "Test204",
"organizationId": "usmf",
"productId": "T-shirt",
"dimensionDataSource": "pos",
"dimensions": {
"SiteId": "1",
"LocationId": "11",
"posMachineId": "0001"
"colorId": "red"
},
"quantities": {
"pos": {
"inbound": 100
}
}
}
]
Create reservation events
To use the Reserve API, you must turn on the reservation feature and complete the reservation configuration. For more information (including a dataflow and sample scenario), see Inventory Visibility reservations.
Create one reservation event
A reservation can be made against different data source settings. To configure this type of reservation, first specify the data source in the dimensionDataSource
parameter. Then, in the dimensions
parameter, specify dimensions according to the dimension settings in the target data source.
When you call the reservation API, you can control the reservation validation by specifying the Boolean ifCheckAvailForReserv
parameter in the request body. A value of True
means that the validation is required, whereas a value of False
means that the validation isn't required. The default value is True
.
If you want to reverse a reservation or unreserve specified inventory quantities, set the quantity to a negative value, and set the ifCheckAvailForReserv
parameter to False
to skip the validation. There's also a dedicated unreserve API to do the same. The difference is only in the way the two APIs are called. It's easier to reverse a specific reservation event by using reservationId
with the unreserve API. Learn more in Unreserve one reservation event section.
Path:
/api/environment/{environmentId}/onhand/reserve
Method:
Post
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
{
id: string,
organizationId: string,
productId: string,
dimensionDataSource: string,
dimensions: {
[key:string]: string,
},
quantityDataSource: string, # optional
quantities: {
[dataSourceName:string]: {
[key:string]: number,
},
},
modifier: string,
quantity: number,
ifCheckAvailForReserv: boolean,
}
The following example shows sample body content.
{
"id": "reserve-0",
"organizationId": "SCM_IV",
"productId": "iv_contoso_product",
"quantity": 1,
"quantityDataSource": "iv",
"modifier": "softReservOrdered",
"ifCheckAvailForReserv": true,
"dimensions": {
"siteId": "iv_contoso_site",
"locationId": "iv_contoso_location",
"colorId": "red",
"sizeId": "small"
}
}
The following example shows a successful response.
{
"reservationId": "RESERVATION_ID",
"id": "ohre~id-822-232959-524",
"processingStatus": "success",
"message": "",
"statusCode": 200
}
Create multiple reservation events
This API is a bulk version of the single-event API.
Path:
/api/environment/{environmentId}/onhand/reserve/bulk
Method:
Post
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
[
{
id: string,
organizationId: string,
productId: string,
dimensionDataSource: string,
dimensions: {
[key:string]: string,
},
quantityDataSource: string, # optional
quantities: {
[dataSourceName:string]: {
[key:string]: number,
},
},
modifier: string,
quantity: number,
ifCheckAvailForReserv: boolean,
},
...
]
Reverse reservation events
The Unreserve API serves as the reverse operation for Reservation events. It provides a way to reverse a reservation event specified by reservationId
or to decrease the reservation quantity.
Reverse one reservation event
When a reservation is created, a reservationId
will be included in the response body. You must provide the same reservationId
to cancel the reservation, and include the same organizationId
, productId
, and dimensions
used for the reservation API call. Finally, specify an OffsetQty
value that represents the number of items to be freed from the previous reservation. A reservation can either be fully or partially reversed depending on the specified OffsetQty
. For example, if 100 units of items were reserved, you can specify OffsetQty: 10
to unreserve 10 of the initial reserved amount.
Path:
/api/environment/{environmentId}/onhand/unreserve
Method:
Post
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
{
id: string,
organizationId: string,
productId: string,
reservationId: string,
dimensions: {
[key:string]: string,
},
OffsetQty: number
}
The following code shows an example of body content.
{
"id": "unreserve-0",
"organizationId": "SCM_IV",
"productId": "iv_contoso_product",
"reservationId": "RESERVATION_ID",
"dimensions": {
"siteid":"iv_contoso_site",
"locationid":"iv_contoso_location",
"ColorId": "red",
"SizeId": "small"
},
"OffsetQty": 1
}
The following code shows an example of a successful response body.
{
"reservationId": "RESERVATION_ID",
"totalInvalidOffsetQtyByReservId": 0,
"id": "ohoe~id-823-11744-883",
"processingStatus": "success",
"message": "",
"statusCode": 200
}
Note
In the response body, when OffsetQty
is less than or equal to the reservation quantity, processingStatus
will be "success" and totalInvalidOffsetQtyByReservId
will be 0.
If OffsetQty
is greater than the reserved amount, processingStatus
will be "partialSuccess" and totalInvalidOffsetQtyByReservId
will be the difference between OffsetQty
and the reserved amount.
For example, if the reservation has a quantity of 10, and OffsetQty
has a value of 12, totalInvalidOffsetQtyByReservId
would be 2.
Reverse multiple reservation events
This API is a bulk version of the single-event API.
Path:
/api/environment/{environmentId}/onhand/unreserve/bulk
Method:
Post
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
[
{
id: string,
organizationId: string,
productId: string,
reservationId: string,
dimensions: {
[key:string]: string,
},
OffsetQty: number
}
...
]
Clean up reservation data
The clean up reservation data API is used to clean up historical reservation data. The body should be a list of data sources. If the list is empty, all data sources will be cleaned up.
Path:
/api/environment/{environmentId}/onhand/reserve/resyncjob
Method:
Post
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
[
"iv",
"pos"
]
If the cleanup job is successfully created, a job ID will be returned in the response, which can be used to get job execution progress.
Get job execution progress
Use the get job execution progress API to obtain the execution progress of a job. A job ID is required to identify the job.
Path:
/api/environment/{environmentId}/getJobProgress
Method:
Get
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Query(Url Parameters):
jobId
Here's a sample get URL.
/api/environment/{environmentId}/getJobProgress?jobId=SomeJob:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Query on-hand
Use the Query on-hand API to fetch current on-hand inventory data for your products. You can use this API whenever you must know the stock, such as when you want to review product stock levels on your e-commerce website, or when you want to check product availability across regions or in nearby stores and warehouses. The API currently supports querying up to 5,000 individual items by productID
value. Multiple siteID
and locationID
values can also be specified in each query. When your data partition rule is set to By location, the maximum limit is defined by the following equation:
NumOf(SiteID) × NumOf(LocationID) <= 10,000.
Query by using the post method
The query by post API is available in two versions. The following table outlines the differences.
API version 1.0 | API version 2.0 |
---|---|
Can only query one organization ID. | Can query multiple organization IDs. |
Can query up to 10,000 combinations of sites and warehouses. | Can query more than 10,000 combinations of organization IDs, sites, and warehouses. Can return results in multiple pages. |
The following subsections show how to use each API version.
Query by post API version 1.0
Path:
/api/environment/{environmentId}/onhand/indexquery
Method:
Post
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
{
dimensionDataSource: string, # Optional
filters: {
organizationId: string[],
productId: string[],
siteId: string[],
locationId: string[],
[dimensionKey:string]: string[],
},
groupByValues: string[],
returnNegative: boolean,
}
In the body part of this request, dimensionDataSource
is an optional parameter. If it isn't set, filters
will be treated as base dimensions.
The returnNegative
parameter controls whether the results contain negative entries.
Query data stored by location
This section applies when your data partition rule is set to By location.
organizationId
should be an array containing exactly one value.productId
can contain one or more values. If it's an empty array, the system will return all products for the specified sites and locations. In this case,siteId
andlocationId
shouldn't be empty.siteId
andlocationId
are used for partitioning. You can specify more than onesiteId
andlocationId
value in a Query on-hand request. If both arrays are empty, the system will return all sites and locations for the specified products. In this case,productId
shouldn't be empty.
We recommend to use the groupByValues
parameter in a way that's consistent with your index configuration. Learn more in On-hand index configuration.
Query data stored by product ID
This section applies when your data partition rule is set to By product ID. In this case, two filters
fields are required: organizationId
, productId
.
organizationId
should be an array containing exactly one value.productId
should be an array with at least one value.
Unlike when storing data by location, if you don't specify values for siteId
and locationId
, inventory information for each product ID will be aggregated across all sites and/or locations.
Note
If you've enabled the on-hand change schedule and available-to-promise (ATP) features, your query can also include the QueryATP
Boolean parameter, which controls whether the query results include ATP information. For more information and examples, see Inventory Visibility on-hand change schedules and available to promise.
The following example shows sample body content. It shows that you can query the on-hand inventory from multiple locations (warehouses).
{
"dimensionDataSource": "pos",
"filters": {
"organizationId": ["usmf"],
"productId": ["T-shirt"],
"siteId": ["1"],
"locationId": ["11","12","13"],
"colorId": ["red"]
},
"groupByValues": ["colorId", "sizeId"],
"returnNegative": true
}
The following example shows how to query all products in a specific site and location.
{
"filters": {
"organizationId": ["usmf"],
"productId": [],
"siteId": ["1"],
"locationId": ["11"],
},
"groupByValues": ["colorId", "sizeId"],
"returnNegative": true
}
Query by post API version 2.0
Path:
/api/environment/{environmentId}/onhand/indexquery?pageNumber={pageNumber}&pageSize={pageSize}
Method:
Post
Headers:
Api-Version="2.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
# Same as version 1.0
The request format for API version 2.0 is similar to that of version 1.0, but also supports two optional parameters: pageNumber
and pageSize
, which allow the system to split a single large result into several smaller documents. The results are sorted by warehouse (locationId
), and the parameters are used as follows to split results into pages:
pageSize
establishes the number of warehouses (locationId
values) that are returned in each page.pageNumber
establishes the page number that's returned.
A request of this format returns on-hand inventory data starting from warehouse number ({pageNumber} − 1) × {pageSize} and includes data for the next {pageSize} warehouses.
API version 2.0 responds with a document that uses the following structure:
{
Value: { # Response same as Api-Version=1.0 }
nextLink: onhand/indexquery?pageNumber={pageNumber+1}&pageSize={pageSize}
}
When the request reaches the last warehouse (locationId
), the nextLink
value is an empty string.
API version 2.0 also lets you specify more than one organization ID in your request. To do so, include a comma-separated list of organization IDs in the organizationId
filter of your request document. For example, "organizationId": ["org1", "org2", "org3"]
.
Query by using the get method
Path:
/api/environment/{environmentId}/onhand
Method:
Get
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Query(Url Parameters):
groupBy
returnNegative
[Filters]
Here's a sample get URL. This get request is exactly the same as the post sample that was provided earlier.
/api/environment/{environmentId}/onhand?organizationId=SCM_IV&productId=iv_contoso_product&siteId=iv_contoso_site&locationId=iv_contoso_location&colorId=red&groupBy=colorId,sizeId&returnNegative=true
The system doesn't support querying inventory over multiple organization IDs with the GET method.
On-hand exact query
On-hand exact queries resemble regular on-hand queries, but they let you specify a mapping hierarchy between a site and a location. For example, you have the following two sites:
- Site 1, which is mapped to location A
- Site 2, which is mapped to location B
For a regular on-hand query, if you specify "siteId": ["1","2"]
and "locationId": ["A","B"]
, Inventory Visibility will automatically query the result for the following sites and locations:
- Site 1, location A
- Site 1, location B
- Site 2, location A
- Site 2, location B
As you see, the regular on-hand query doesn't recognize that location A exists only in site 1, and location B exists only in site 2. Therefore, it makes redundant queries. To accommodate this hierarchical mapping, you can use an on-hand exact query and specify the location mappings in the query body. In this case, you'll query and receive results for only site 1, location A and site 2, location B.
On-hand exact query query using the post method
The on-hand exact query by post API is available in two versions. The following table outlines the differences.
API version 1.0 | API version 2.0 |
---|---|
Can only query one organization ID. | Can query multiple organization IDs. |
On-hand exact query by post API version 1.0
Path:
/api/environment/{environmentId}/onhand/exactquery
Method:
Post
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
{
dimensionDataSource: string, # Optional
filters: {
organizationId: string[],
productId: string[],
dimensions: string[],
values: string[][],
},
groupByValues: string[],
returnNegative: boolean,
}
In the body part of this request, dimensionDataSource
is an optional parameter. If it isn't set, dimensions
in filters
will be treated as base dimensions. There are four required fields for filters
: organizationId
, productId
, dimensions
, and values
.
organizationId
should contain only one value, but it's still an array.productId
could contain one or more values. If it's an empty array, all products will be returned.- In the
dimensions
array,siteId
andlocationId
are required if and only if your data partition rule is set to By location. In this case, they could appear with other elements in any order. values
could contain one or more distinct tuples of values corresponding todimensions
.
dimensions
in filters
will be automatically added to groupByValues
.
The returnNegative
parameter controls whether the results contain negative entries.
The following example shows sample body content.
{
"dimensionDataSource": "pos",
"filters": {
"organizationId": ["SCM_IV"],
"productId": ["iv_contoso_product"],
"dimensions": ["siteId", "locationId", "colorId"],
"values" : [
["iv_contoso_site", "iv_contoso_location", "red"],
["iv_contoso_site", "iv_contoso_location", "blue"],
]
},
"groupByValues": ["colorId", "sizeId"],
"returnNegative": true
}
The following example shows how to query all products in multiple sites and locations.
{
"filters": {
"organizationId": ["SCM_IV"],
"productId": [],
"dimensions": ["siteId", "locationId"],
"values" : [
["iv_contoso_site_1", "iv_contoso_location_1"],
["iv_contoso_site_2", "iv_contoso_location_2"],
]
},
"groupByValues": ["colorId", "sizeId"],
"returnNegative": true
}
On-hand exact query by post API version 2.0
Path:
/api/environment/{environmentId}/onhand/exactquery
Method:
Post
Headers:
Api-Version="2.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
{
dimensionDataSource: string, # Optional
filters: {
productId: string[],
keys: string[],
values: string[][],
},
groupByValues: string[],
returnNegative: boolean,
}
API version 2.0 differs from version 1.0 in the following ways:
- The
filters
section now has akeys
field instead of adimensions
field. Thekeys
field works like thedimensions
field in version 1.0, but can now also includeorganizationId
. You can specify the keys in any order. - The
filters
section no longer supports theorganizationId
field. Instead, you can includeorganizationId
among the dimensions in thekeys
field (for example,keys: ["organizationId", "siteId", "locationId"]
) and define organization ID values at the matching position in thevalues
field (for example,values: ["SCM_IV", "iv_contoso_site_1", "iv_contoso_location_1"]
).
Other fields are identical to API version 1.0.
Query with product search
The following on-hand query APIs are enhanced to support product search:
Note
When you post an Inventory Visibility query that uses product search, use the productSearch
request parameter (with a ProductAttributeQuery
object inside) to find or filter by product ID. The newer APIs no longer support the older productid
request parameter in the request body.
Prerequisites
Before you can start to use the product search APIs, your system must meet the following requirements:
- You must be running Dynamics 365 Supply Chain Management 10.0.36 or later.
- Inventory Visibility version 1.2.2.54 or later must be installed and set up as described in Install and set up Inventory Visibility.
- The Inventory Visibility search service must be installed and set up as described in Set up product search for Inventory Visibility.
Product search contract
The product search contract defines the rules for communicating with the product search APIs. It provides a standardized way to describe the capabilities and behavior of the product search capabilities. Therefore, users can more easily understand, interact with, and build applications that consume the Inventory Visibility APIs.
The following example shows a sample contract.
{
"productFilter": {
"logicalOperator": "And",
"conditions": [
{
"conditionOperator": "Contains",
"productName": [
"Deluxe"
],
},
],
"subFilters": [
{
"conditions": [
{
"conditionOperator": "IsExactly",
"productType": [
"Item"
]
}
]
}
]
},
"attributeFilter": {
"logicalOperator": "Or",
"conditions": [
{
"attributeName": "Weight Limit",
"attributeTypeName":"PoundDomain",
"attributeArea": " ProductAttribute",
"attributeValues": [
"370"
],
"conditionOperator": "GreaterEqual"
}
],
"subFilters": [
{
"conditions": [
{
"attributeName": "Weight Limit",
"attributeTypeName":"PoundDomain",
"attributeArea": " ProductAttribute",
"attributeValues": [
"330"
],
"conditionOperator": "LessEqual"
}
]
}
]
},
}
The following table describes the fields that are used in the contract.
Field ID | Description |
---|---|
logicalOperator |
The possible values are And and Or . Use this field to connect multiple conditions or conditions and sub-filters. Note that subFilters is actually a productFilter or attributeFilter object. Therefore, you can have subFilters inside subFilters . |
conditionOperator |
The possible values are IsExactly , IsNot , Contains , DoesNotContain , BeginsWith , IsOneOf , GreaterEqual , LessEqual , and Between . |
ProductFilter |
Use this field to filter products by product-related information. For example, you can change productName in the contract to Company , itemNumber , productSearchName , productType , productName , productDescription , inventoryUnitSymbol , salesUnitSymbol , or purchaseUnitSymbol to fit your business needs. |
AttributeFilter |
Use this field to filter products by attribute-related information. |
attributeArea |
The possible values are ProductAttribute , DimensionAttribute , and BatchAttribute . |
Query with product search
Path:
/api/environment/{environmentId}/onhand/productsearch/indexquery
Method:
Post
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
{
productSearch: {ProductAttributeQuery contract object inherited from Product Search}
dimensionDataSource: string, # Optional
filters: {
organizationId: string[],
siteId: string[],
locationId: string[],
[dimensionKey:string]: string[],
},
groupByValues: string[],
returnNegative: boolean,
}
The following example shows sample body content.
{
"productSearch": {
"productFilter": {
"conditions": [
{
"conditionOperator": "contains",
"productName": [
"speaker cable"
],
},
],
},
},
"returnNegative": true,
"filters":
{
"organizationId": ["usmf"],
"siteId": ["1"],
"locationId": ["13"],
},
"groupByValues": ["colorid"],
}
The following example shows a successful response.
[
{
"productId": "M0030",
"dimensions": {
"ColorId": "White",
"siteid": "1",
"locationid": "13"
},
"quantities": {
"fno": {
"arrived": 0,
"availordered": 20,
"onorder": 5,
"ordered": 20,
"physicalinvent": 0,
"reservordered": 0,
"reservphysical": 0,
"orderedsum": 20,
"softreserved": 0
},
"iv": {
"ordered": 0,
"softreserved": 0,
"softreservphysical": 0,
"softreservordered": 0,
"total ordered": 20,
"total on order": 5,
"availabletoreserve": 20,
"totalavailable": 20,
"totalordered": 20,
"totalonorder": 5
},
"pos": {
"inbound": 0,
"outbound": 0
},
"@iv": {
"@allocated": 0
}
}
},
{
"productId": "M0030",
"dimensions": {
"ColorId": "Black",
"siteid": "1",
"locationid": "13"
},
"quantities": {
"fno": {
"arrived": 0,
"availordered": 3,
"ordered": 3,
"physicalinvent": 0,
"reservordered": 0,
"reservphysical": 0,
"orderedsum": 3,
"softreserved": 0
},
"iv": {
"ordered": 0,
"softreserved": 0,
"softreservphysical": 0,
"softreservordered": 0,
"total ordered": 3,
"availabletoreserve": 3,
"totalavailable": 3,
"totalordered": 3
},
"pos": {
"inbound": 0,
"outbound": 0
},
"@iv": {
"@allocated": 0
}
}
}
]
Exact query with product search
Path:
/api/environment/{environmentId}/onhand/productsearch/exactquery
Method:
Post
Headers:
Api-Version="1.0"
Authorization="Bearer $access_token"
ContentType:
application/json
Body:
{
productSearch: {ProductAttributeQuery contract object inherited from Product Search}
dimensionDataSource: string, # Optional
filters: {
organizationId: string[],
dimensions: string[],
values: string[][],
},
groupByValues: string[],
returnNegative: boolean,
}
The following example shows sample body content.
{
"productSearch": {
"productFilter": {
"conditions": [
{
"conditionOperator": "contains",
"productName": [
"speaker cable"
],
},
],
},
},
"filters": {
"organizationId": ["usmf"],
"dimensions": ["siteId", "locationId", "colorid"],
"values" : [
["1", "13", "Black"],
]
},
"groupByValues": [],
"returnNegative": true
}
The following example shows a successful response.
[
{
"productId": "M0030",
"dimensions": {
"ColorId": "Black",
"siteid": "1",
"locationid": "13"
},
"quantities": {
"fno": {
"arrived": 0,
"availordered": 3,
"ordered": 3,
"physicalinvent": 0,
"reservordered": 0,
"reservphysical": 0,
"orderedsum": 3,
"softreserved": 0
},
"iv": {
"ordered": 0,
"softreserved": 0,
"softreservphysical": 0,
"softreservordered": 0,
"total ordered": 3,
"availabletoreserve": 3,
"totalavailable": 3,
"totalordered": 3
},
"pos": {
"inbound": 0,
"outbound": 0
},
"@iv": {
"@allocated": 0
}
}
}
]
Available to promise
You can set up Inventory Visibility to let you schedule future on-hand changes and calculate ATP quantities. ATP is the quantity of an item that's available and can be promised to a customer in the next period. Use of the ATP calculation can greatly increase your order fulfillment capability. For information about how to enable this feature, and how to interact with Inventory Visibility through its API after the feature is enabled, see Inventory Visibility on-hand change schedules and available to promise.
Allocation
Allocation related APIs are located in Inventory Visibility allocation.